1
2 ///////////////////////////////////////////////////////////
3 // //
4 // SAGA //
5 // //
6 // System for Automated Geoscientific Analyses //
7 // //
8 // Tool Library //
9 // grid_analysis //
10 // //
11 //-------------------------------------------------------//
12 // //
13 // coverage_of_categories.cpp //
14 // //
15 // Copyright (C) 2019 by //
16 // Olaf 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.org //
40 // //
41 // contact: Olaf Conrad //
42 // Institute of Geography //
43 // University of Hamburg //
44 // Germany //
45 // //
46 ///////////////////////////////////////////////////////////
47
48 //---------------------------------------------------------
49 #include "coverage_of_categories.h"
50
51
52 ///////////////////////////////////////////////////////////
53 // //
54 // //
55 // //
56 ///////////////////////////////////////////////////////////
57
58 //---------------------------------------------------------
CCoverage_of_Categories(void)59 CCoverage_of_Categories::CCoverage_of_Categories(void)
60 {
61 Set_Name (_TL("Coverage of Categories"));
62
63 Set_Author ("O.Conrad (c) 2019");
64
65 Set_Description (_TW(
66 "The Coverage of Categories tool calculates for each category of "
67 "the categories input grid the percentage it covers in each cell "
68 "of the target grid system. "
69 ));
70
71 //-----------------------------------------------------
72 Parameters.Add_Grid("",
73 "CLASSES" , _TL("Categories"),
74 _TL(""),
75 PARAMETER_INPUT
76 );
77
78 Parameters.Add_Grid_List("",
79 "COVERAGES" , _TL("Coverages"),
80 _TL(""),
81 PARAMETER_OUTPUT
82 );
83
84 Parameters.Add_Table("",
85 "LUT" , _TL("Classification"),
86 _TL(""),
87 PARAMETER_INPUT_OPTIONAL
88 );
89
90 Parameters.Add_Table_Field("LUT",
91 "LUT_VAL" , _TL("Value"),
92 _TL("The class value or - in combination with value 2 - the minimum/maximum value specifying a value range."),
93 false
94 );
95
96 Parameters.Add_Table_Field("LUT",
97 "LUT_MAX" , _TL("Maximum Value"),
98 _TL("Use this option to specify a value range equal or greater than previous value and less than this (maximum) value."),
99 true
100 );
101
102 Parameters.Add_Table_Field("LUT",
103 "LUT_NAME" , _TL("Class name"),
104 _TL("Optional, a class name used for the naming of the target coverage rasters."),
105 true
106 );
107
108 Parameters.Add_Bool("",
109 "NO_DATA" , _TL("Mark No Coverage as No-Data"),
110 _TL(""),
111 true
112 );
113
114 Parameters.Add_Choice("",
115 "DATADEPTH" , _TL("Data Depth"),
116 _TL(""),
117 CSG_String::Format("%s|%s|%s|%s",
118 _TL("1-byte"),
119 _TL("2-byte"),
120 _TL("4-byte"),
121 _TL("8-byte")
122 ), 1
123 );
124
125 //-----------------------------------------------------
126 m_Grid_Target.Create(&Parameters, false, "", "TARGET_");
127 }
128
129
130 ///////////////////////////////////////////////////////////
131 // //
132 ///////////////////////////////////////////////////////////
133
134 //---------------------------------------------------------
On_Parameter_Changed(CSG_Parameters * pParameters,CSG_Parameter * pParameter)135 int CCoverage_of_Categories::On_Parameter_Changed(CSG_Parameters *pParameters, CSG_Parameter *pParameter)
136 {
137 if( pParameter == pParameters->Get_Grid_System_Parameter() && pParameter->asGrid_System() )
138 {
139 m_Grid_Target.Set_User_Defined(pParameters, *pParameter->asGrid_System());
140 }
141
142 m_Grid_Target.On_Parameter_Changed(pParameters, pParameter);
143
144 return( CSG_Tool_Grid::On_Parameter_Changed(pParameters, pParameter) );
145 }
146
147 //---------------------------------------------------------
On_Parameters_Enable(CSG_Parameters * pParameters,CSG_Parameter * pParameter)148 int CCoverage_of_Categories::On_Parameters_Enable(CSG_Parameters *pParameters, CSG_Parameter *pParameter)
149 {
150 if( pParameter->Cmp_Identifier("LUT") )
151 {
152 pParameter->Set_Children_Enabled(pParameter->asTable() != NULL);
153 }
154
155 m_Grid_Target.On_Parameters_Enable(pParameters, pParameter);
156
157 return( CSG_Tool_Grid::On_Parameters_Enable(pParameters, pParameter) );
158 }
159
160
161 ///////////////////////////////////////////////////////////
162 // //
163 ///////////////////////////////////////////////////////////
164
165 //---------------------------------------------------------
On_Execute(void)166 bool CCoverage_of_Categories::On_Execute(void)
167 {
168 m_pClasses = Parameters("CLASSES")->asGrid();
169
170 CSG_Grid_System System = m_Grid_Target.Get_System();
171
172 if( !System.Get_Extent().Intersects(m_pClasses->Get_Extent()) )
173 {
174 Error_Set(_TL("no overlap of grid extents"));
175
176 return( false );
177 }
178
179 //-----------------------------------------------------
180 Process_Set_Text(_TL("initializing"));
181
182 if( !Initialize(System) )
183 {
184 m_Classes.Destroy();
185
186 return( false );
187 }
188
189 //---------------------------------------------------------
190 CSG_Parameter_Grid_List *pCoverages = Parameters("COVERAGES")->asGridList();
191
192 double dSize = 0.5 * System.Get_Cellsize() / Get_Cellsize();
193
194 //-----------------------------------------------------
195 Process_Set_Text(_TL("processing"));
196
197 for(int y=0; y<System.Get_NY() && Set_Progress(y, System.Get_NY()); y++)
198 {
199 double yy = (System.Get_yGrid_to_World(y) - Get_YMin()) / Get_Cellsize();
200
201 #ifndef _DEBUG
202 #pragma omp parallel for
203 #endif
204 for(int x=0; x<System.Get_NX(); x++)
205 {
206 double xx = (System.Get_xGrid_to_World(x) - Get_XMin()) / Get_Cellsize();
207
208 CSG_Rect Cell(xx - dSize, yy - dSize, xx + dSize, yy + dSize);
209
210 for(int iClass=0; iClass<pCoverages->Get_Grid_Count(); iClass++)
211 {
212 pCoverages->Get_Grid(iClass)->Set_Value(x, y, Get_Coverage(Cell, iClass));
213 }
214 }
215 }
216
217 //-------------------------------------------------
218 m_Classes.Destroy();
219
220 return( true );
221 }
222
223
224 ///////////////////////////////////////////////////////////
225 // //
226 ///////////////////////////////////////////////////////////
227
228 //---------------------------------------------------------
Initialize(const CSG_Grid_System & System)229 bool CCoverage_of_Categories::Initialize(const CSG_Grid_System &System)
230 {
231 m_Classes.Destroy();
232
233 m_Classes.Add_Field("NAM", SG_DATATYPE_String);
234 m_Classes.Add_Field("VAL", m_pClasses->Get_Type());
235
236 //-----------------------------------------------------
237 if( Parameters("LUT")->asTable() )
238 {
239 CSG_Table &Classes = *Parameters("LUT")->asTable();
240
241 int fVal = Parameters("LUT_VAL" )->asInt();
242 int fMax = Parameters("LUT_MAX" )->asInt();
243 int fNam = Parameters("LUT_NAME")->asInt();
244
245 if( fMax >= 0 )
246 {
247 m_Classes.Add_Field("MAX", m_pClasses->Get_Type());
248 }
249
250 m_Classes.Set_Count(Classes.Get_Count());
251
252 for(int iClass=0; iClass<Classes.Get_Count(); iClass++)
253 {
254 m_Classes[iClass].Set_Value(1, Classes[iClass].asDouble(fVal));
255
256 if( fMax >= 0 )
257 {
258 m_Classes[iClass].Set_Value(2, Classes[iClass].asDouble(fMax));
259 }
260
261 if( fNam >= 0 )
262 {
263 m_Classes[iClass].Set_Value(0, Classes[iClass].asString(fNam));
264 }
265 else
266 {
267 m_Classes[iClass].Set_Value(0, SG_Get_String(Classes[iClass].asDouble(fVal), -6));
268 }
269 }
270 }
271
272 //-----------------------------------------------------
273 else
274 {
275 CSG_Unique_Number_Statistics Classes;
276
277 for(sLong iCell=0; iCell<Get_NCells() && Set_Progress_NCells(iCell); iCell++)
278 {
279 if( !m_pClasses->is_NoData(iCell) )
280 {
281 Classes += m_pClasses->asDouble(iCell);
282 }
283 }
284
285 //-------------------------------------------------
286 m_Classes.Set_Count(Classes.Get_Count());
287
288 for(int iClass=0; iClass<Classes.Get_Count(); iClass++)
289 {
290 m_Classes[iClass].Set_Value(0, SG_Get_String(Classes.Get_Value(iClass), -6));
291 m_Classes[iClass].Set_Value(1, Classes.Get_Value(iClass) );
292 }
293
294 m_Classes.Set_Index(1, TABLE_INDEX_Ascending);
295 }
296
297 //-----------------------------------------------------
298 Message_Fmt("\n%s: %d", _TL("Number of Classes"), m_Classes.Get_Count());
299
300 if( m_Classes.Get_Count() < 1 )
301 {
302 Error_Set(_TL("No valid cells found"));
303
304 return( false );
305 }
306
307 if( m_Classes.Get_Count() > 32 && !Message_Dlg_Confirm(CSG_String::Format("%s: %s [%d]!", _TL("Warning"), _TL("There are many unique values"), m_Classes.Get_Count()), _TL("Do you really want to proceed?")) )
308 {
309 return( false );
310 }
311
312 //-----------------------------------------------------
313 TSG_Data_Type Type; double Scaling;
314
315 switch( Parameters("DATADEPTH")->asInt() )
316 {
317 case 0: Type = SG_DATATYPE_Byte ; Scaling = 1. / 250.; break; // 0.004
318 default: Type = SG_DATATYPE_Word ; Scaling = 1. / 62500.; break; // 0.000016
319 case 2: Type = SG_DATATYPE_Float ; Scaling = 1. ; break;
320 case 3: Type = SG_DATATYPE_Double; Scaling = 1. ; break;
321 }
322
323 CSG_Parameter_Grid_List *pCoverages = Parameters("COVERAGES")->asGridList();
324
325 pCoverages->Del_Items();
326
327 for(int iClass=0; iClass<m_Classes.Get_Count(); iClass++)
328 {
329 CSG_Grid *pGrid = SG_Create_Grid(System, Type);
330
331 if( !pGrid )
332 {
333 Error_Set(_TL("Failed to allocate memory for coverage grid"));
334
335 return( false );
336 }
337
338 pGrid->Fmt_Name("%s [%s]", m_pClasses->Get_Name(), m_Classes[iClass].asString(0));
339 pGrid->Set_NoData_Value(Parameters("NO_DATA")->asBool() ? 0. : -1.);
340 pGrid->Set_Scaling(Scaling);
341
342 pCoverages->Add_Item(pGrid);
343 }
344
345 //-----------------------------------------------------
346 return( true );
347 }
348
349
350 ///////////////////////////////////////////////////////////
351 // //
352 ///////////////////////////////////////////////////////////
353
354 //---------------------------------------------------------
Cmp_Class(int x,int y,int iClass)355 inline bool CCoverage_of_Categories::Cmp_Class(int x, int y, int iClass)
356 {
357 if( m_pClasses->is_InGrid(x, y) )
358 {
359 double Value = m_pClasses->asDouble(x, y);
360
361 if( m_Classes.Get_Field_Count() > 2 )
362 {
363 return( Value >= m_Classes[iClass].asDouble(1)
364 && Value < m_Classes[iClass].asDouble(2)
365 );
366 }
367
368 return( Value == m_Classes[iClass].asDouble(1) );
369 }
370
371 return( false );
372 }
373
374 //---------------------------------------------------------
Get_Coverage(const CSG_Rect & Cell,int x,int y)375 inline double CCoverage_of_Categories::Get_Coverage(const CSG_Rect &Cell, int x, int y)
376 {
377 CSG_Rect c(x - 0.5, y - 0.5, x + 0.5, y + 0.5);
378
379 return( c.Intersect(Cell) ? c.Get_Area() : 0. );
380 }
381
382 //---------------------------------------------------------
Get_Coverage(const CSG_Rect & Cell,int iClass)383 double CCoverage_of_Categories::Get_Coverage(const CSG_Rect &Cell, int iClass)
384 {
385 double Coverage = 0.;
386
387 for(int y=(int)Cell.Get_YMin()-1; y<=(int)Cell.Get_YMax()+1; y++)
388 {
389 for(int x=(int)Cell.Get_XMin()-1; x<=(int)Cell.Get_XMax()+1; x++)
390 {
391 if( Cmp_Class(x, y, iClass) )
392 {
393 Coverage += Get_Coverage(Cell, x, y);
394 }
395 }
396 }
397
398 return( Coverage / Cell.Get_Area() );
399 }
400
401
402 ///////////////////////////////////////////////////////////
403 // //
404 // //
405 // //
406 ///////////////////////////////////////////////////////////
407
408 //---------------------------------------------------------
409