1
2 ///////////////////////////////////////////////////////////
3 // //
4 // SAGA //
5 // //
6 // System for Automated Geoscientific Analyses //
7 // //
8 // Module Library: //
9 // image_tools //
10 // //
11 //-------------------------------------------------------//
12 // //
13 // sentinel_2_scene_import.cpp //
14 // //
15 // Olaf Conrad (C) 2019 //
16 // //
17 //-------------------------------------------------------//
18 // //
19 // This file is part of 'SAGA - System for Automated //
20 // Geoscientific Analyses'. SAGA is free software; you //
21 // can redistribute it and/or modify it under the terms //
22 // of the GNU General Public License as published by the //
23 // Free Software Foundation, either version 2 of the //
24 // License, or (at your option) any later version. //
25 // //
26 // SAGA is distributed in the hope that it will be //
27 // useful, but WITHOUT ANY WARRANTY; without even the //
28 // implied warranty of MERCHANTABILITY or FITNESS FOR A //
29 // PARTICULAR PURPOSE. See the GNU General Public //
30 // License for more details. //
31 // //
32 // You should have received a copy of the GNU General //
33 // Public License along with this program; if not, see //
34 // <http://www.gnu.org/licenses/>. //
35 // //
36 //-------------------------------------------------------//
37 // //
38 // e-mail: oconrad@saga-gis.org //
39 // //
40 // contact: Olaf Conrad //
41 // Institute of Geography //
42 // University of Hamburg //
43 // Germany //
44 // //
45 ///////////////////////////////////////////////////////////
46
47 //---------------------------------------------------------
48 #include "sentinel_2_scene_import.h"
49
50
51 ///////////////////////////////////////////////////////////
52 // //
53 // //
54 // //
55 ///////////////////////////////////////////////////////////
56
57 //---------------------------------------------------------
58 enum EBand_Head
59 {
60 INFO_FIELD_ID = 0,
61 INFO_FIELD_BAND,
62 INFO_FIELD_NAME,
63 INFO_FIELD_RES,
64 INFO_FIELD_WAVE_MIN,
65 INFO_FIELD_WAVE,
66 INFO_FIELD_WAVE_MAX,
67 INFO_FIELD_COUNT
68 };
69
70 //---------------------------------------------------------
Get_Info_Bands(void)71 CSG_Table CSentinel_2_Scene_Import::Get_Info_Bands(void)
72 {
73 CSG_Table Info_Bands;
74
75 Info_Bands.Add_Field("ID" , SG_DATATYPE_Int );
76 Info_Bands.Add_Field("BAND" , SG_DATATYPE_String);
77 Info_Bands.Add_Field("NAME" , SG_DATATYPE_String);
78 Info_Bands.Add_Field("RESOLUTION", SG_DATATYPE_Int );
79 Info_Bands.Add_Field("WAVE_MIN" , SG_DATATYPE_Double);
80 Info_Bands.Add_Field("WAVE" , SG_DATATYPE_Double);
81 Info_Bands.Add_Field("WAVE_MAX" , SG_DATATYPE_Double);
82
83 #define ADD_INFO_BAND(band, name, res, wmin, wave, wmax) { CSG_Table_Record &Info = *Info_Bands.Add_Record();\
84 Info.Set_Value(INFO_FIELD_ID , 1 + Info.Get_Index());\
85 Info.Set_Value(INFO_FIELD_BAND, band);\
86 Info.Set_Value(INFO_FIELD_NAME, CSG_String::Format("[%s] %s", SG_T(band), name));\
87 Info.Set_Value(INFO_FIELD_RES , res);\
88 Info.Set_Value(INFO_FIELD_WAVE_MIN, wave);\
89 Info.Set_Value(INFO_FIELD_WAVE , wave);\
90 Info.Set_Value(INFO_FIELD_WAVE_MAX, wave);\
91 }
92
93 ADD_INFO_BAND("B01", _TL("Aerosols" ), 60, 412, 442.7, 456); // 1, 60m
94 ADD_INFO_BAND("B02", _TL("Blue" ), 10, 456, 492.7, 533); // 2, 10m
95 ADD_INFO_BAND("B03", _TL("Green" ), 10, 538, 559.8, 583); // 3, 10m
96 ADD_INFO_BAND("B04", _TL("Red" ), 10, 646, 664.6, 684); // 4, 10m
97 ADD_INFO_BAND("B05", _TL("Red Edge" ), 20, 695, 704.1, 714); // 5, 20m
98 ADD_INFO_BAND("B06", _TL("Red Edge" ), 20, 731, 740.5, 749); // 6, 20m
99 ADD_INFO_BAND("B07", _TL("Red Edge" ), 20, 769, 782.8, 797); // 7, 20m
100 ADD_INFO_BAND("B08", _TL("NIR" ), 10, 760, 832.8, 907); // 8, 10m
101 ADD_INFO_BAND("B8A", _TL("NIR" ), 20, 837, 864.7, 881); // 9, 20m
102 ADD_INFO_BAND("B09", _TL("Water Vapour" ), 60, 932, 945.1, 958); // 10, 60m
103 ADD_INFO_BAND("B10", _TL("Cirrus" ), 60, 1337, 1373.5, 1412); // 11, 60m
104 ADD_INFO_BAND("B11", _TL("SWIR" ), 20, 1539, 1613.7, 1682); // 12, 20m
105 ADD_INFO_BAND("B12", _TL("SWIR" ), 20, 2078, 2202.4, 2320); // 13, 20m
106 ADD_INFO_BAND("TCI", _TL("True Color Image" ), 10, 0, 0.0, 0); // 14, 10m
107 ADD_INFO_BAND("AOT", _TL("Aerosol Optical Thickness"), 10, 0, 0.0, 0); // 15, 10m
108 ADD_INFO_BAND("WVP", _TL("Water Vapour" ), 10, 0, 0.0, 0); // 16, 10m
109 ADD_INFO_BAND("SCL", _TL("Scene Classification" ), 20, 0, 0.0, 0); // 17, 20m
110
111 return( Info_Bands );
112 }
113
114 //---------------------------------------------------------
115 #define BAND_IS_10m(b) (b+1 == 2 || b+1 == 3 || b+1 == 4 || b+1 == 8)
116 #define BAND_IS_20m(b) (b+1 == 5 || b+1 == 6 || b+1 == 7 || b+1 == 9 || b+1 == 12 || b+1 == 13)
117 #define BAND_IS_60m(b) (b+1 == 1 || b+1 == 10 || b+1 == 11)
118 #define BAND_IS_TCI(b) (b+1 == 14)
119 #define BAND_IS_AOT(b) (b+1 == 15)
120 #define BAND_IS_WVP(b) (b+1 == 16)
121 #define BAND_IS_SCL(b) (b+1 == 17)
122
123
124 ///////////////////////////////////////////////////////////
125 // //
126 // //
127 // //
128 ///////////////////////////////////////////////////////////
129
130 //---------------------------------------------------------
CSentinel_2_Scene_Import(void)131 CSentinel_2_Scene_Import::CSentinel_2_Scene_Import(void)
132 {
133 Set_Name (_TL("Import Sentinel-2 Scene"));
134
135 Set_Author ("O.Conrad (c) 2019");
136
137 Set_Description (_TW(
138 "Import Sentinel-2 scenes from a folder structure as provided "
139 "by the original ESA download. "
140 ));
141
142 Add_Reference("https://sentinel.esa.int/web/sentinel/missions/sentinel-2",
143 SG_T("Sentinel-2 at ESA's Sentinel Online")
144 );
145
146 Add_Reference("https://sentinel.esa.int/web/sentinel/document-library/content/-/article/sentinel-2-user-handbook",
147 SG_T("Sentinel-2 User Handbook")
148 );
149
150 //-----------------------------------------------------
151 Parameters.Add_FilePath("",
152 "METAFILE" , _TL("Metadata File"),
153 _TL(""),
154 CSG_String::Format("%s|MTD*.xml|%s|*.*",
155 _TL("Sentinel-2 Metadata Files"),
156 _TL("All Files")
157 )
158 );
159
160 Parameters.Add_Grid_List("",
161 "BANDS" , _TL("Bands"),
162 _TL(""),
163 PARAMETER_OUTPUT
164 );
165
166 Parameters.Add_Bool("",
167 "MULTI2GRIDS" , _TL("Multispectral Bands as Grid Collection"),
168 _TL(""),
169 true
170 );
171
172 Parameters.Add_Bool("", "LOAD_60M", _TL("Aerosol, Vapour, Cirrus" ), _TL(""), false);
173 // Parameters.Add_Bool("", "LOAD_TCI", _TL("True Color Image" ), _TL(""), false);
174 // Parameters.Add_Bool("", "LOAD_AOT", _TL("Aerosol Optical Thickness"), _TL(""), false);
175 // Parameters.Add_Bool("", "LOAD_WVP", _TL("Water Vapour" ), _TL(""), false);
176 Parameters.Add_Bool("", "LOAD_SCL", _TL("Scene Classification" ), _TL(""), true);
177
178 Parameters.Add_Choice("",
179 "REFLECTANCE" , _TL("Reflectance Values"),
180 _TL(""),
181 CSG_String::Format("%s|%s",
182 _TL("original"),
183 _TL("fraction")
184 ), 1
185 );
186
187 Parameters.Add_Choice("",
188 "PROJECTION" , _TL("Coordinate System"),
189 _TL(""),
190 CSG_String::Format("%s|%s|%s",
191 _TL("UTM North"),
192 _TL("UTM South"),
193 _TL("Geographic Coordinates")
194 ), 0
195 );
196
197 Parameters.Add_Choice("PROJECTION",
198 "RESAMPLING" , _TL("Resampling"),
199 _TL(""),
200 CSG_String::Format("%s|%s|%s|%s",
201 _TL("Nearest Neighbour"),
202 _TL("Bilinear Interpolation"),
203 _TL("Bicubic Spline Interpolation"),
204 _TL("B-Spline Interpolation")
205 ), 3
206 );
207
208 //-----------------------------------------------------
209 Parameters.Add_Choice("",
210 "EXTENT" , _TL("Extent"),
211 _TL(""),
212 CSG_String::Format("%s|%s|%s|%s",
213 _TL("original"),
214 _TL("user defined"),
215 _TL("grid system"),
216 _TL("shapes extent")
217 ), 0
218 );
219
220 Parameters.Add_Double("EXTENT", "EXTENT_XMIN", _TL("Left" ), _TL(""));
221 Parameters.Add_Double("EXTENT", "EXTENT_XMAX", _TL("Right" ), _TL(""));
222 Parameters.Add_Double("EXTENT", "EXTENT_YMIN", _TL("Bottom"), _TL(""));
223 Parameters.Add_Double("EXTENT", "EXTENT_YMAX", _TL("Top" ), _TL(""));
224
225 Parameters.Add_Grid_System("EXTENT",
226 "EXTENT_GRID" , _TL("Grid System"),
227 _TL("")
228 );
229
230 Parameters.Add_Shapes("EXTENT",
231 "EXTENT_SHAPES" , _TL("Shapes Extent"),
232 _TL(""),
233 PARAMETER_INPUT
234 );
235
236 Parameters.Add_Double("EXTENT",
237 "EXTENT_BUFFER" , _TL("Buffer"),
238 _TL(""),
239 0., 0., true
240 );
241 }
242
243
244 ///////////////////////////////////////////////////////////
245 // //
246 ///////////////////////////////////////////////////////////
247
248 //---------------------------------------------------------
On_Parameters_Enable(CSG_Parameters * pParameters,CSG_Parameter * pParameter)249 int CSentinel_2_Scene_Import::On_Parameters_Enable(CSG_Parameters *pParameters, CSG_Parameter *pParameter)
250 {
251 if( pParameter->Cmp_Identifier("METAFILE") )
252 {
253 bool bLevel2 = SG_File_Exists (pParameter->asString())
254 && SG_File_Get_Name(pParameter->asString(), false).Find("MTD_MSIL2") == 0;
255
256 pParameters->Set_Enabled("LOAD_AOT", bLevel2);
257 pParameters->Set_Enabled("LOAD_WVP", bLevel2);
258 pParameters->Set_Enabled("LOAD_SCL", bLevel2);
259 }
260
261 if( pParameter->Cmp_Identifier("PROJECTION") )
262 {
263 pParameters->Set_Enabled("RESAMPLING", pParameter->asInt() == 2);
264 }
265
266 if( pParameter->Cmp_Identifier("EXTENT") )
267 {
268 pParameters->Set_Enabled("EXTENT_XMIN" , pParameter->asInt() == 1);
269 pParameters->Set_Enabled("EXTENT_XMAX" , pParameter->asInt() == 1);
270 pParameters->Set_Enabled("EXTENT_YMIN" , pParameter->asInt() == 1);
271 pParameters->Set_Enabled("EXTENT_YMAX" , pParameter->asInt() == 1);
272 pParameters->Set_Enabled("EXTENT_GRID" , pParameter->asInt() == 2);
273 pParameters->Set_Enabled("EXTENT_SHAPES", pParameter->asInt() == 3);
274 pParameters->Set_Enabled("EXTENT_BUFFER", pParameter->asInt() >= 2);
275 }
276
277 return( CSG_Tool::On_Parameters_Enable(pParameters, pParameter) );
278 }
279
280
281 ///////////////////////////////////////////////////////////
282 // //
283 ///////////////////////////////////////////////////////////
284
285 //---------------------------------------------------------
On_Execute(void)286 bool CSentinel_2_Scene_Import::On_Execute(void)
287 {
288 CSG_MetaData Info_General, Info_Granule;
289
290 if( !Load_Metadata(Parameters("METAFILE")->asString(), Info_General, Info_Granule) )
291 {
292 Error_Fmt("%s [%s]", _TL("failed to load metadata"), Parameters("METAFILE")->asString());
293
294 return( false );
295 }
296
297 CSG_String Date = Info_General["PRODUCT_START_TIME"].Get_Content().BeforeFirst('T');
298
299 //-----------------------------------------------------
300 CSG_String Path = SG_File_Get_Path(Parameters("METAFILE")->asString());
301
302 bool bLoadTCI = Parameters("LOAD_TCI") && Parameters("LOAD_TCI")->asBool();
303 bool bLoadAOT = Parameters("LOAD_AOT") && Parameters("LOAD_AOT")->asBool();
304 bool bLoadWVP = Parameters("LOAD_WVP") && Parameters("LOAD_WVP")->asBool();
305 bool bLoadSCL = Parameters("LOAD_SCL") && Parameters("LOAD_SCL")->asBool();
306 bool bLoad60m = Parameters("LOAD_60M") && Parameters("LOAD_60M")->asBool();
307
308 bool bMultiGrids = Parameters("MULTI2GRIDS")->asBool();
309 double Scaling = Parameters("REFLECTANCE")->asInt () == 0 ? 1. : 1. / 10000.;
310
311 CSG_Table Info_Bands(Get_Info_Bands());
312
313 //-----------------------------------------------------
314 Parameters("BANDS")->asGridList()->Del_Items();
315
316 CSG_Grids *pBands[2]; pBands[0] = pBands[1] = NULL; CSG_Grid *pSCL = NULL;
317
318 for(int Band=0; Band<Info_Bands.Get_Count() && Process_Get_Okay(); Band++)
319 {
320 if( (!bLoadTCI && BAND_IS_TCI(Band))
321 || (!bLoadAOT && BAND_IS_AOT(Band))
322 || (!bLoadWVP && BAND_IS_WVP(Band))
323 || (!bLoadSCL && BAND_IS_SCL(Band))
324 || (!bLoad60m && BAND_IS_60m(Band)) )
325 {
326 continue;
327 }
328
329 CSG_Grid *pBand = Load_Band(Path, Find_Band(Info_Bands[Band], Info_Granule));
330
331 if( !pBand )
332 {
333 continue;
334 }
335
336 pBand->Get_MetaData().Add_Child(Info_General)->Set_Name("SENTINEL-2");
337 pBand->Set_Description(Info_General.asText());
338
339 if( bMultiGrids && (BAND_IS_10m(Band) || BAND_IS_20m(Band)) )
340 {
341 int b = BAND_IS_10m(Band) ? 0 : 1;
342
343 if( pBands[b] == NULL )
344 {
345 if( (pBands[b] = SG_Create_Grids(pBand->Get_System(), Info_Bands)) == NULL )
346 {
347 Error_Set(_TL("memory allocation failed"));
348
349 return( false );
350 }
351
352 Parameters("BANDS")->asGridList()->Add_Item(pBands[b]);
353 }
354
355 pBands[b]->Add_Grid(Info_Bands[Band], pBand, true);
356 }
357 else
358 {
359 pBand->Fmt_Name("S2_%s_%s", Date.c_str(), Info_Bands[Band].asString(INFO_FIELD_BAND));
360
361 if( BAND_IS_10m(Band) || BAND_IS_20m(Band) || BAND_IS_60m(Band) )
362 {
363 pBand->Set_Scaling(Scaling);
364 }
365
366 if( BAND_IS_SCL(Band) )
367 {
368 pSCL = pBand;
369 }
370
371 Parameters("BANDS")->asGridList()->Add_Item(pBand);
372 }
373 }
374
375 //-----------------------------------------------------
376 for(int i=0; i<2; i++)
377 {
378 if( pBands[i] )
379 {
380 pBands[i]->Fmt_Name("S2_%s_%dm", Date.c_str(), i == 0 ? 10 : 20);
381 pBands[i]->Get_MetaData().Add_Child(Info_General)->Set_Name("SENTINEL-2");
382 pBands[i]->Set_Description(Info_General.asText());
383 pBands[i]->Set_Z_Attribute (INFO_FIELD_WAVE);
384 pBands[i]->Set_Z_Name_Field(INFO_FIELD_NAME);
385 pBands[i]->Set_Scaling(Scaling);
386
387 DataObject_Add(pBands[i], true);
388 }
389 }
390
391 if( pSCL )
392 {
393 Load_Classification(pSCL, Parameters("METAFILE")->asString());
394 }
395
396 return( true );
397 }
398
399
400 ///////////////////////////////////////////////////////////
401 // //
402 ///////////////////////////////////////////////////////////
403
404 //---------------------------------------------------------
Load_Metadata(const CSG_String & File,CSG_MetaData & General,CSG_MetaData & Granule)405 bool CSentinel_2_Scene_Import::Load_Metadata(const CSG_String &File, CSG_MetaData &General, CSG_MetaData &Granule)
406 {
407 CSG_MetaData Metadata;
408
409 if( !Metadata.Load(File)
410 || !Metadata("n1:General_Info")
411 || !Metadata["n1:General_Info"]("Product_Info")
412 || !Metadata["n1:General_Info"]["Product_Info"]("Product_Organisation")
413 || !Metadata["n1:General_Info"]["Product_Info"]["Product_Organisation"]("Granule_List")
414 || !Metadata["n1:General_Info"]["Product_Info"]["Product_Organisation"]["Granule_List"]("Granule") )
415 {
416 return( false );
417 }
418
419 Granule = Metadata["n1:General_Info"]["Product_Info"]["Product_Organisation"]["Granule_List"]["Granule"];
420 General = Metadata["n1:General_Info"]["Product_Info"];
421
422 General.Del_Child("Product_Organisation");
423
424 return( true );
425 }
426
427
428 ///////////////////////////////////////////////////////////
429 // //
430 ///////////////////////////////////////////////////////////
431
432 //---------------------------------------------------------
Find_Band(const CSG_Table_Record & Band,const CSG_MetaData & Granule)433 CSG_String CSentinel_2_Scene_Import::Find_Band(const CSG_Table_Record &Band, const CSG_MetaData &Granule)
434 {
435 CSG_String IDold(Band.asString(1)), IDnew(CSG_String::Format("%s_%dm", Band.asString(1), Band.asInt(3)));
436
437 for(int i=0; i<Granule.Get_Children_Count(); i++)
438 {
439 if( Granule[i].Cmp_Name("IMAGE_FILE")
440 && (!Granule[i].Get_Content().Right(IDnew.Length()).Cmp(IDnew)
441 || !Granule[i].Get_Content().Right(IDold.Length()).Cmp(IDold)) )
442 {
443 return( Granule[i].Get_Content() );
444 }
445 }
446
447 return( "" );
448 }
449
450 //---------------------------------------------------------
Load_Band(const CSG_String & Path,const CSG_String & File)451 CSG_Grid * CSentinel_2_Scene_Import::Load_Band(const CSG_String &Path, const CSG_String &File)
452 {
453 Process_Set_Text("%s: %s", _TL("loading"), File.AfterLast('/').c_str());
454
455 //-----------------------------------------------------
456 CSG_String _File(Path + "/" + File + ".jp2");
457
458 #ifdef _SAGA_MSW
459 _File.Replace("/", "\\");
460 #endif
461
462 CSG_Grid *pBand = Load_Grid(_File);
463
464 if( !pBand )
465 {
466 return( NULL );
467 }
468
469 pBand->Set_NoData_Value(0); // landsat 8 pretends to use a value of 65535 (2^16 - 1)
470
471 if( !pBand->Get_Projection().is_Okay() )
472 {
473 // undefined coordinate system, nothing to do be further done...
474 }
475
476 //-----------------------------------------------------
477 else if( Parameters("PROJECTION")->asInt() != 2 ) // UTM
478 {
479 CSG_Grid *pTmp = pBand;
480
481 CSG_String Projection = pTmp->Get_Projection().Get_Proj4();
482
483 if( Projection.Find("+proj=utm") >= 0
484 && ( (Projection.Find("+south") >= 0 && Parameters("PROJECTION")->asInt() == 0)
485 || (Projection.Find("+south") < 0 && Parameters("PROJECTION")->asInt() == 1))
486 && (pBand = SG_Create_Grid(pTmp->Get_Type(), pTmp->Get_NX(), pTmp->Get_NY(), pTmp->Get_Cellsize(),
487 pTmp->Get_XMin(), pTmp->Get_YMin() + (Parameters("PROJECTION")->asInt() == 1 ? 10000000 : -10000000)
488 )) != NULL )
489 {
490 if( Parameters("PROJECTION")->asInt() == 1 )
491 Projection.Append (" +south");
492 else
493 Projection.Replace(" +south", "");
494
495 pBand->Get_Projection().Create(Projection, SG_PROJ_FMT_Proj4);
496
497 pBand->Set_Name (pTmp->Get_Name());
498 pBand->Set_Description (pTmp->Get_Description());
499 pBand->Set_NoData_Value_Range(pTmp->Get_NoData_Value(), pTmp->Get_NoData_Value(true));
500 pBand->Set_Scaling (pTmp->Get_Scaling(), pTmp->Get_Offset());
501
502 #pragma omp parallel for
503 for(int y=0; y<pBand->Get_NY(); y++)
504 {
505 for(int x=0; x<pBand->Get_NX(); x++)
506 {
507 pBand->Set_Value(x, y, pTmp->asDouble(x, y));
508 }
509 }
510
511 delete(pTmp);
512 }
513 }
514
515 //-----------------------------------------------------
516 else if( Parameters("PROJECTION")->asInt() == 2 ) // Geographic Coordinates
517 {
518 CSG_Tool *pTool = SG_Get_Tool_Library_Manager().Create_Tool("pj_proj4", 4); // Coordinate Transformation (Grid)
519
520 if( pTool )
521 {
522 Message_Fmt("\n%s (%s: %s)\n", _TL("re-projection to geographic coordinates"), _TL("original"), pBand->Get_Projection().Get_Name().c_str());
523
524 pTool->Set_Manager(NULL);
525
526 if( pTool->Set_Parameter("CRS_PROJ4" , SG_T("+proj=longlat +ellps=WGS84 +datum=WGS84"))
527 && pTool->Set_Parameter("SOURCE" , pBand)
528 && pTool->Set_Parameter("RESAMPLING", Parameters("RESAMPLING"))
529 && pTool->Set_Parameter("KEEP_TYPE" , true)
530 && pTool->Execute() )
531 {
532 delete(pBand);
533
534 pBand = pTool->Get_Parameters()->Get_Parameter("GRID")->asGrid();
535 }
536
537 SG_Get_Tool_Library_Manager().Delete_Tool(pTool);
538 }
539 }
540
541 //-----------------------------------------------------
542 return( pBand );
543 }
544
545 //---------------------------------------------------------
Load_Grid(const CSG_String & File)546 CSG_Grid * CSentinel_2_Scene_Import::Load_Grid(const CSG_String &File)
547 {
548 CSG_Rect Extent;
549
550 switch( Parameters("EXTENT")->asInt() )
551 {
552 default: // original
553 return( SG_Create_Grid(File) );
554
555 case 1: // user defined
556 Extent.Assign(
557 Parameters("EXTENT_XMIN")->asDouble(),
558 Parameters("EXTENT_YMIN")->asDouble(),
559 Parameters("EXTENT_XMAX")->asDouble(),
560 Parameters("EXTENT_YMAX")->asDouble()
561 );
562 break;
563
564 case 2: // grid system
565 Extent = Parameters("EXTENT_GRID" )->asGrid_System()->Get_Extent();
566 Extent.Inflate(Parameters("EXTENT_BUFFER")->asDouble(), false);
567 break;
568
569 case 3: // shapes extent
570 Extent = Parameters("EXTENT_SHAPES")->asShapes ()->Get_Extent();
571 Extent.Inflate(Parameters("EXTENT_BUFFER")->asDouble(), false);
572 break;
573 }
574
575 //-----------------------------------------------------
576 CSG_Grid *pGrid = NULL;
577 CSG_Tool *pTool = SG_Get_Tool_Library_Manager().Create_Tool("io_gdal", 0); // Import Raster
578
579 if( pTool && pTool->Set_Manager(NULL)
580 && pTool->Set_Parameter("FILES" , File)
581 && pTool->Set_Parameter("EXTENT" , 1)
582 && pTool->Set_Parameter("EXTENT_XMIN", Extent.Get_XMin())
583 && pTool->Set_Parameter("EXTENT_XMAX", Extent.Get_XMax())
584 && pTool->Set_Parameter("EXTENT_YMIN", Extent.Get_YMin())
585 && pTool->Set_Parameter("EXTENT_YMAX", Extent.Get_YMax())
586 && pTool->Execute() )
587 {
588 pGrid = pTool->Get_Parameter("GRIDS")->asGridList()->Get_Grid(0);
589 }
590
591 SG_Get_Tool_Library_Manager().Delete_Tool(pTool);
592
593 return( pGrid );
594 }
595
596
597 ///////////////////////////////////////////////////////////
598 // //
599 ///////////////////////////////////////////////////////////
600
601 //---------------------------------------------------------
Load_Classification(CSG_Grid * pGrid,const CSG_String & File)602 bool CSentinel_2_Scene_Import::Load_Classification(CSG_Grid *pGrid, const CSG_String &File)
603 {
604 CSG_MetaData Metadata;
605
606 if( !Metadata.Load(File)
607 || !Metadata("n1:General_Info")
608 || !Metadata["n1:General_Info"]("Product_Image_Characteristics")
609 || !Metadata["n1:General_Info"]["Product_Image_Characteristics"]("Scene_Classification_List") )
610 {
611 return( false );
612 }
613
614 CSG_MetaData ClassList = Metadata["n1:General_Info"]["Product_Image_Characteristics"]["Scene_Classification_List"];
615
616 //-----------------------------------------------------
617 CSG_Table LUT;
618
619 LUT.Add_Field("Color" , SG_DATATYPE_Color );
620 LUT.Add_Field("Name" , SG_DATATYPE_String);
621 LUT.Add_Field("Description", SG_DATATYPE_String);
622 LUT.Add_Field("Minimum" , SG_DATATYPE_Double);
623 LUT.Add_Field("Maximum" , SG_DATATYPE_Double);
624
625 for(int i=0, Index; i<ClassList.Get_Children_Count(); i++)
626 {
627 if( ClassList[i].Cmp_Name("Scene_Classification_ID")
628 && ClassList[i]("SCENE_CLASSIFICATION_TEXT" )
629 && ClassList[i]["SCENE_CLASSIFICATION_INDEX"].Get_Content().asInt(Index) )
630 {
631 CSG_String Name(ClassList[i]["SCENE_CLASSIFICATION_TEXT"].Get_Content().AfterFirst('_')); Name.Replace("_", " ");
632
633 CSG_Table_Record &Class = *LUT.Add_Record();
634
635 Class.Set_Value(0, SG_Color_Get_Random());
636 Class.Set_Value(1, Name);
637 Class.Set_Value(3, Index);
638 Class.Set_Value(4, Index);
639 }
640 }
641
642 if( LUT.Get_Count() > 0 )
643 {
644 DataObject_Add(pGrid);
645
646 CSG_Parameter *pLUT = DataObject_Get_Parameter(pGrid, "LUT");
647
648 if( pLUT && pLUT->asTable() && pLUT->asTable()->Assign_Values(&LUT) )
649 {
650 DataObject_Set_Parameter(pGrid, pLUT);
651 DataObject_Set_Parameter(pGrid, "COLORS_TYPE", 1); // Color Classification Type: Lookup Table
652
653 return( true );
654 }
655 }
656
657 return( false );
658 }
659
660
661 ///////////////////////////////////////////////////////////
662 // //
663 // //
664 // //
665 ///////////////////////////////////////////////////////////
666
667 //---------------------------------------------------------
668