1
2 ///////////////////////////////////////////////////////////
3 // //
4 // SAGA //
5 // //
6 // System for an Automated Geo-Scientific Analysis //
7 // //
8 // Tool Library //
9 // grid_analysis //
10 // //
11 //-------------------------------------------------------//
12 // //
13 // Soil_Texture.cpp //
14 // //
15 // Copyright (C) 2007 by //
16 // Gianluca Massei //
17 // //
18 //-------------------------------------------------------//
19 // //
20 // This file is part of 'SAGA - System for an Automated //
21 // Geo-Scientific Analysis'. 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: g_massa@libero.it //
40 // //
41 // contact: Gianluca Massei //
42 // Department of Economics and Appraisal //
43 // University of Perugia - Italy //
44 // www.unipg.it //
45 // //
46 ///////////////////////////////////////////////////////////
47
48 //---------------------------------------------------------
49 #include "Soil_Texture.h"
50
51
52 ///////////////////////////////////////////////////////////
53 // //
54 // //
55 // //
56 ///////////////////////////////////////////////////////////
57
58 //---------------------------------------------------------
59 const CSG_String Definition_USDA[][4] =
60 { { "000, 000, 255", "C" , _TL("Clay" ), " 0 100, 0 60, 20 40, 45 40, 45 55, 0 100"
61 },{ "000, 200, 255", "SiC" , _TL("Silty Clay" ), " 0 100, 0 60, 20 40, 0 40, 0 100"
62 },{ "000, 200, 200", "SiCL", _TL("Silty Clay Loam"), " 0 40, 0 27, 20 27, 20 40, 0 40"
63 },{ "200, 000, 255", "SC" , _TL("Sandy Clay" ), " 45 55, 45 35, 65 35, 45 55"
64 },{ "200, 200, 200", "SCL" , _TL("Sandy Clay Loam"), " 45 35, 45 27, 52 20, 80 20, 65 35, 45 35"
65 },{ "127, 127, 200", "CL" , _TL("Clay Loam" ), " 20 40, 20 27, 45 27, 45 40, 20 40"
66 },{ "000, 255, 000", "Si" , _TL("Silt" ), " 0 12, 0 0, 20 0, 8 12, 0 12"
67 },{ "127, 255, 127", "SiL" , _TL("Silt Loam" ), " 8 12, 20 0, 50 0, 23 27, 0 27, 0 12, 8 12"
68 },{ "127, 127, 127", "L" , _TL("Loam" ), " 23 27, 43 7, 52 7, 52 20, 45 27, 23 27"
69 },{ "255, 000, 000", "S" , _TL("Sand" ), " 85 0, 100 0, 90 10, 85 0"
70 },{ "255, 000, 127", "LS" , _TL("Loamy Sand" ), " 70 0, 85 0, 90 10, 85 15, 70 0"
71 },{ "200, 127, 127", "SL" , _TL("Sandy Loam" ), " 43 7, 50 0, 70 0, 85 15, 80 20, 52 20, 52 7, 43 7"
72 },{ "", "", "", "" } };
73
74 //---------------------------------------------------------
75 const CSG_String Definition_Belgium[][4] =
76 { { "", "U", _TL("Heavy Clay" ), " 65.000 35.000, 10.000 35.000, 0.000 45.000, 0.000 100.000, 65.000 35.000"
77 },{ "", "E", _TL("Clay" ), " 82.500 17.500, 67.500 17.500, 30.000 17.500, 25.000 18.125, 20.000 20.000, 15.000 22.500, 0.000 30.000, 0.000 45.000, 10.000 35.000, 65.000 35.000, 82.500 17.500"
78 },{ "", "A", _TL("Silt Loam" ), " 15.000 0.000, 0.000 0.000, 0.000 30.000, 15.000 22.500, 15.000 0.000"
79 },{ "", "L", _TL("Sandy Loam" ), " 50.000 0.000, 15.000 0.000, 15.000 22.500, 20.000 20.000, 25.000 18.125, 30.000 17.500, 67.500 17.500, 67.500 11.250, 50.000 11.250, 50.000 0.000"
80 },{ "", "P", _TL("Light Sandy Loam"), " 67.500 0.000, 50.000 0.000, 50.000 11.250, 67.500 11.250, 67.500 0.000"
81 },{ "", "S", _TL("Loamy Sand" ), " 82.500 0.000, 67.500 0.000, 67.500 11.250, 67.500 17.500, 82.500 17.500, 91.250 8.750, 82.500 8.750, 82.500 0.000"
82 },{ "", "Z", _TL("Sand" ), "100.000 0.000, 82.500 0.000, 82.500 8.750, 91.250 8.750, 100.000 0.000"
83 },{ "", "", "", "" } };
84
85 //---------------------------------------------------------
86 const CSG_String Definition_KA5[][4] =
87 { { "", "Ss" , _TL("Reiner Sand" ), "100 0, 95 5, 85 5, 90 0, 100 0"
88
89 },{ "", "Su2", _TL("Schwach schluffiger Sand"), " 90 0, 85 5, 70 5, 75 0, 90 0"
90 },{ "", "Sl2", _TL("Schwach lehmiger Sand" ), " 85 5, 82 8, 67 8, 70 5, 85 5"
91 },{ "", "Sl3", _TL("Mittel lehmiger Sand" ), " 82 8, 78 12, 48 12, 52 8, 82 8"
92 },{ "", "St2", _TL("Schwach toniger Sand" ), " 95 5, 83 17, 73 17, 85 5, 95 5"
93
94 },{ "", "Su3", _TL("Mittel schluffiger Sand" ), " 75 0, 67 8, 52 8, 60 0, 75 0"
95 },{ "", "Su4", _TL("Stark schluffiger Sand" ), " 60 0, 52 8, 42 8, 50 0, 60 0"
96
97 },{ "", "Slu", _TL("Schluffig-lemiger Sand" ), " 52 8, 43 17, 33 17, 42 8, 52 8"
98 },{ "", "Sl4", _TL("Stark lehmiger Sand" ), " 78 12, 73 17, 43 17, 48 12, 78 12"
99 },{ "", "St3", _TL("Mittel toniger Sand" ), " 83 17, 75 25, 60 25, 68 17, 83 17"
100
101 },{ "", "Ls2", _TL("Schwach sandiger Lehm" ), " 43 17, 35 25, 25 25, 33 17, 43 17"
102 },{ "", "Ls3", _TL("Mittel sandiger Lehm" ), " 53 17, 45 25, 35 25, 43 17, 53 17"
103 },{ "", "Ls4", _TL("Stark sandiger Lehm" ), " 68 17, 60 25, 45 25, 53 17, 68 17"
104 },{ "", "Lt2", _TL("Schwach toniger Lehm" ), " 45 25, 35 35, 15 35, 25 25, 45 25"
105
106 },{ "", "Lts", _TL("Sandig-toniger Lehm" ), " 60 25, 40 45, 25 45, 45 25, 60 25"
107 },{ "", "Ts4", _TL("Stark sandiger Ton" ), " 75 25, 65 35, 50 35, 60 25, 75 25"
108 },{ "", "Ts3", _TL("Mittel sandiger Ton" ), " 65 35, 55 45, 40 45, 50 35, 65 35"
109
110 },{ "", "Uu" , _TL("Reiner Schluff" ), " 20 0, 12 8, 0 8, 0 0, 20 0"
111 },{ "", "Us" , _TL("Sandiger Schluff" ), " 50 0, 42 8, 12 8, 20 0, 50 0"
112
113 },{ "", "Ut2", _TL("Schwach toniger Schluff" ), " 27 8, 23 12, 0 12, 0 8, 27 8"
114 },{ "", "Ut3", _TL("Mittel toniger Schluff" ), " 23 12, 18 17, 0 17, 0 12, 23 12"
115 },{ "", "Uls", _TL("Sandig-lehmiger Schluff" ), " 42 8, 33 17, 18 17, 27 8, 42 8"
116
117 },{ "", "Ut4", _TL("Stark toniger Schluff" ), " 18 17, 10 25, 0 25, 0 17, 18 17"
118 },{ "", "Lu" , _TL("Schluffiger Lehm" ), " 33 17, 20 30, 5 30, 18 17, 33 17"
119
120 },{ "", "Lt3", _TL("Mittel toniger Lehm" ), " 35 35, 25 45, 5 45, 15 35, 35 35"
121 },{ "", "Tu3", _TL("Mittel schluffiger Ton" ), " 20 30, 5 45, 0 45, 0 35, 5 30, 20 30"
122 },{ "", "Tu4", _TL("Stark schluffiger Ton" ), " 10 25, 0 35, 0 25, 10 25"
123
124 },{ "", "Ts2", _TL("Schwach sandiger Ton" ), " 55 45, 35 65, 20 65, 40 45, 55 45"
125 },{ "", "Tl" , _TL("Lehmiger Ton" ), " 40 45, 20 65, 5 65, 25 45, 40 45"
126 },{ "", "Tu2", _TL("Schwach schluffiger Ton" ), " 25 45, 5 65, 0 65, 0 45, 25 45"
127 },{ "", "Tt" , _TL("Reiner Ton" ), " 35 65, 0 100, 0 65, 35 65"
128
129 },{ "", "", "", "" } };
130
131
132 ///////////////////////////////////////////////////////////
133 // //
134 ///////////////////////////////////////////////////////////
135
136 //---------------------------------------------------------
137 class CSoil_Texture_Classifier
138 {
139 public:
CSoil_Texture_Classifier(void)140 CSoil_Texture_Classifier(void) {}
141
CSoil_Texture_Classifier(int Scheme,int Colors_Default)142 CSoil_Texture_Classifier(int Scheme, int Colors_Default) { Initialize(Scheme, Colors_Default); }
143
144 //-----------------------------------------------------
Get_Description(void)145 static CSG_String Get_Description (void)
146 {
147 return( _TW(
148 "Derive soil texture classes from sand, silt and clay contents. "
149 "Currently supported schemes are USDA and German Kartieranleitung 5. "
150 ));
151 }
152
153 //-----------------------------------------------------
Get_Count(void) const154 int Get_Count (void) const { return( m_Classes.Get_Count() ); }
155
Get_ID(int i) const156 int Get_ID (int i) const { return( i >= 0 && i < Get_Count() ? m_Classes[i].asInt (0) : 0 ); }
Get_Color(int i) const157 int Get_Color (int i) const { return( i >= 0 && i < Get_Count() ? m_Classes[i].asInt (1) : 0 ); }
Get_Key(int i) const158 CSG_String Get_Key (int i) const { return( i >= 0 && i < Get_Count() ? m_Classes[i].asString(2) : SG_T("") ); }
Get_Name(int i) const159 CSG_String Get_Name (int i) const { return( i >= 0 && i < Get_Count() ? m_Classes[i].asString(3) : SG_T("") ); }
160
Get_Polygons(CSG_Shapes * pPolygons,int Axes,bool bIsosceles) const161 bool Get_Polygons (CSG_Shapes *pPolygons, int Axes, bool bIsosceles) const
162 {
163 if( !pPolygons || !m_Classes.is_Valid() )
164 {
165 return( false );
166 }
167
168 pPolygons->Create(m_Classes);
169
170 for(int i=0; (Axes!=0 || bIsosceles) && i<pPolygons->Get_Count(); i++)
171 {
172 CSG_Shape *pPolygon = pPolygons->Get_Shape(i);
173
174 for(int iPoint=0; iPoint<pPolygon->Get_Point_Count(0); iPoint++)
175 {
176 TSG_Point p = pPolygon->Get_Point(iPoint);
177
178 double Sand = p.x;
179 double Silt = 100 - (p.x + p.y);
180 double Clay = p.y;
181
182 switch( Axes )
183 {
184 case 0: p.x = Sand; p.y = Clay; break;
185 case 1: p.x = Sand; p.y = Silt; break;
186 case 2: p.x = Silt; p.y = Sand; break;
187 case 3: p.x = Silt; p.y = Clay; break;
188 case 4: p.x = Clay; p.y = Sand; break;
189 case 5: p.x = Clay; p.y = Silt; break;
190 }
191
192 if( bIsosceles )
193 {
194 p.x += 0.5 * p.y;
195 p.y *= 0.8660254038; // sqrt(100*100 - 50*50) / 100.
196 }
197
198 pPolygon->Set_Point(p, iPoint, 0);
199 }
200 }
201
202 return( true );
203 }
204
205 //-----------------------------------------------------
Get_Table(CSG_Table & Classes,int Definition)206 static bool Get_Table (CSG_Table &Classes, int Definition)
207 {
208 if( Definition < 0 || Definition > 2 )
209 {
210 return( false );
211 }
212
213 Classes.Destroy();
214
215 Classes.Add_Field("COLOR" , SG_DATATYPE_String);
216 Classes.Add_Field("KEY" , SG_DATATYPE_String);
217 Classes.Add_Field("NAME" , SG_DATATYPE_String);
218 Classes.Add_Field("POLYGON", SG_DATATYPE_String);
219
220 for(int i=0; ; i++)
221 {
222 const CSG_String *Class;
223
224 switch( Definition )
225 {
226 case 0: Class = Definition_USDA [i]; break;
227 case 1: Class = Definition_KA5 [i]; break;
228 case 2: Class = Definition_Belgium[i]; break;
229 }
230
231 if( Class[1].is_Empty() ) { break; } else
232 {
233 CSG_Table_Record *pClass = Classes.Add_Record();
234
235 pClass->Set_Value(0, Class[0]);
236 pClass->Set_Value(1, Class[1]);
237 pClass->Set_Value(2, Class[2]);
238 pClass->Set_Value(3, Class[3]);
239 }
240 }
241
242 return( Classes.Get_Count() > 0 );
243 }
244
245 //-----------------------------------------------------
Initialize(int Definition,int Colors_Default)246 bool Initialize (int Definition, int Colors_Default)
247 {
248 CSG_Table Classes; return( Get_Table(Classes, Definition) && Initialize(Classes, Colors_Default) );
249 }
250
251 //-----------------------------------------------------
Initialize(const CSG_Table & Classes,int Colors_Default)252 bool Initialize (const CSG_Table &Classes, int Colors_Default)
253 {
254 m_Classes.Create(SHAPE_TYPE_Polygon);
255
256 m_Classes.Add_Field("ID" , SG_DATATYPE_Int );
257 m_Classes.Add_Field("COLOR", SG_DATATYPE_Color );
258 m_Classes.Add_Field("KEY" , SG_DATATYPE_String);
259 m_Classes.Add_Field("NAME" , SG_DATATYPE_String);
260
261 //-------------------------------------------------
262 for(int i=0; i<Classes.Get_Count(); i++)
263 {
264 CSG_String_Tokenizer Items(Classes[i].asString(3), ",");
265
266 if( Items.Get_Tokens_Count() >= 3 )
267 {
268 CSG_Shape_Polygon *pClass = (CSG_Shape_Polygon *)m_Classes.Add_Shape();
269
270 pClass->Set_Value(0, i + 1);
271 pClass->Set_Value(2, Classes[i].asString(1));
272 pClass->Set_Value(3, Classes[i].asString(2));
273
274 do
275 {
276 CSG_String Point(Items.Get_Next_Token()); Point.Trim();
277
278 double Sand = Point.BeforeFirst(' ').asDouble();
279 double Clay = Point.AfterFirst (' ').asDouble();
280
281 pClass->Add_Point(Sand, Clay);
282 }
283 while( Items.Has_More_Tokens() );
284
285 Items.Set_String(Classes[i].asString(0), ",");
286
287 if( Items.Get_Tokens_Count() == 3 )
288 {
289 int r = Items.Get_Next_Token().asInt();
290 int g = Items.Get_Next_Token().asInt();
291 int b = Items.Get_Next_Token().asInt();
292
293 pClass->Set_Value(1, SG_GET_RGB(r, g, b));
294 }
295 else
296 {
297 TSG_Point c = pClass->Get_Centroid();
298
299 double Sand, Silt, Clay, r, g, b;
300
301 Sand = 0.01 * c.x;
302 Silt = 0.01 * (100 - (c.x + c.y));
303 Clay = 0.01 * c.y;
304
305 switch( Colors_Default )
306 {
307 default: r = Sand + Silt; g = Silt + Silt; b = Clay + Silt; break;
308 case 1: r = Sand + Silt; g = Silt ; b = Clay ; break;
309 case 2: r = Sand ; g = Silt ; b = Clay ; break;
310 }
311
312 pClass->Set_Value(1, SG_GET_RGB(
313 (int)(255 * (r < 1 ? r : 1.)),
314 (int)(255 * (g < 1 ? g : 1.)),
315 (int)(255 * (b < 1 ? b : 1.))
316 ));
317 }
318 }
319 }
320
321 return( Get_Count() > 0 );
322 }
323
324 //-----------------------------------------------------
Get_Texture(double Sand,double Silt,double Clay,double & Sum) const325 int Get_Texture (double Sand, double Silt, double Clay, double &Sum) const
326 {
327 if( ((Sand < 0 ? 1 : 0) + (Silt < 0 ? 1 : 0) + (Clay < 0 ? 1 : 0)) > 1 )
328 {
329 return( -1 );
330 }
331
332 if( Sand < 0 ) Sand = 100 - ( Silt + Clay);
333 if( Silt < 0 ) Silt = 100 - (Sand + Clay);
334 if( Clay < 0 ) Clay = 100 - (Sand + Silt );
335
336 Sum = Sand + Silt + Clay;
337
338 if( Sum > 0.0 && Sum != 100.0 )
339 {
340 Sand *= 100.0 / Sum;
341 Clay *= 100.0 / Sum;
342 }
343
344 return( Get_Texture_From_Sand_and_Clay(Sand, Clay) );
345 }
346
347 //-----------------------------------------------------
Set_LUT(CSG_Table * pClasses,bool bID) const348 bool Set_LUT (CSG_Table *pClasses, bool bID) const
349 {
350 pClasses->Set_Record_Count(Get_Count());
351
352 for(int i=0; i<Get_Count(); i++)
353 {
354 CSG_Table_Record *pClass = pClasses->Get_Record(i);
355
356 pClasses->Set_Value(i, 0, Get_Color(i));
357 pClasses->Set_Value(i, 1, Get_Key (i));
358 pClasses->Set_Value(i, 2, Get_Name (i));
359
360 if( bID )
361 {
362 pClasses->Set_Value(i, 3, Get_ID(i));
363 pClasses->Set_Value(i, 4, Get_ID(i));
364 }
365 else
366 {
367 pClasses->Set_Value(i, 3, Get_Key(i));
368 pClasses->Set_Value(i, 4, Get_Key(i));
369 }
370 }
371
372 return( true );
373 }
374
375
376 private: //////////////////////////////////////////////////
377
378 CSG_Shapes m_Classes;
379
380
Get_Texture_From_Sand_and_Clay(double Sand,double Clay) const381 int Get_Texture_From_Sand_and_Clay (double Sand, double Clay) const
382 {
383 if( Sand < 0.001 ) Sand = 0.001; else if( Sand > 99.99 ) Sand = 99.99;
384 if( Clay < 0.001 ) Clay = 0.001; else if( Clay > 99.99 ) Clay = 99.99;
385
386 if( Sand + Clay >= 99.99 )
387 {
388 double Sum = 99.99 / (Sand + Clay);
389
390 Sand *= Sum;
391 Clay *= Sum;
392 }
393
394 for(int i=0; i<Get_Count(); i++)
395 {
396 if( ((CSG_Shape_Polygon *)m_Classes.Get_Shape(i))->Contains(Sand, Clay) )
397 {
398 return( i );
399 }
400 }
401
402 return( -1 );
403 }
404
405 };
406
407
408 ///////////////////////////////////////////////////////////
409 // //
410 // //
411 // //
412 ///////////////////////////////////////////////////////////
413
414 //---------------------------------------------------------
CSoil_Texture(void)415 CSoil_Texture::CSoil_Texture(void)
416 {
417 Set_Name (_TL("Soil Texture Classification"));
418
419 Set_Author ("Gianluca Massei (c) 2007 (g_massa@libero.it), L.Landschreiber, O.Conrad (c) 2017");
420
421 Set_Description (CSoil_Texture_Classifier::Get_Description());
422
423 Add_Reference(
424 "http://soils.usda.gov/technical/aids/investigations/texture/",
425 SG_T("USDA NRCS Soils Website")
426 );
427
428 //-----------------------------------------------------
429 Parameters.Add_Grid("",
430 "SAND" , _TL("Sand"),
431 _TL("sand content given as percentage"),
432 PARAMETER_INPUT_OPTIONAL
433 );
434
435 Parameters.Add_Grid("",
436 "SILT" , _TL("Silt"),
437 _TL("silt content given as percentage"),
438 PARAMETER_INPUT_OPTIONAL
439 );
440
441 Parameters.Add_Grid("",
442 "CLAY" , _TL("Clay"),
443 _TL("clay content given as percentage"),
444 PARAMETER_INPUT_OPTIONAL
445 );
446
447 Parameters.Add_Grid("",
448 "TEXTURE" , _TL("Soil Texture"),
449 _TL("soil texture"),
450 PARAMETER_OUTPUT, true, SG_DATATYPE_Char
451 );
452
453 Parameters.Add_Grid("",
454 "SUM" , _TL("Sum"),
455 _TL("Sum of percentages"),
456 PARAMETER_OUTPUT_OPTIONAL
457 );
458
459 Parameters.Add_Choice("",
460 "SCHEME" , _TL("Classification"),
461 _TL(""),
462 CSG_String::Format("%s|%s|%s|%s|",
463 _TL("USDA"),
464 _TL("Germany KA5"),
465 _TL("Belgium/France"),
466 _TL("user defined")
467 )
468 );
469
470 Parameters.Add_Choice("",
471 "COLORS" , _TL("Default Colour Scheme"),
472 _TL(""),
473 CSG_String::Format("%s 1|%s 2|%s 3|",
474 _TL("Scheme"),
475 _TL("Scheme"),
476 _TL("Scheme")
477 )
478 );
479
480 Parameters.Add_FixedTable("SCHEME",
481 "USER" , _TL("User Definition"),
482 _TW("The colour is defined as comma separated red, green and blue values (in the range 0 to 255). "
483 "If the colour field is empty it will be generated from the chosen default colour scheme. "
484 "Key and name are simple text labels specifying each class. The polygon is defined as pairs of "
485 "sand (=x) and clay (=y) separated by a blank and separated from the next pair by a comma. "
486 )
487 );
488
489 CSoil_Texture_Classifier::Get_Table(*Parameters("USER")->asTable(), 0);
490
491 Parameters.Add_Shapes("",
492 "POLYGONS" , _TL("Scheme as Polygons"),
493 _TL(""),
494 PARAMETER_OUTPUT_OPTIONAL, SHAPE_TYPE_Polygon
495 );
496
497 Parameters.Add_Choice("POLYGONS",
498 "XY_AXES" , _TL("X/Y Axes"),
499 _TL(""),
500 CSG_String::Format("%s|%s|%s|%s|%s|%s|",
501 _TL("Sand and Clay"),
502 _TL("Sand and Silt"),
503 _TL("Silt and Sand"),
504 _TL("Silt and Clay"),
505 _TL("Clay and Sand"),
506 _TL("Clay and Silt")
507 ), 3
508 );
509
510 Parameters.Add_Choice("POLYGONS",
511 "TRIANGLE" , _TL("Triangle"),
512 _TL(""),
513 CSG_String::Format("%s|%s|",
514 _TL("right-angled"),
515 _TL("isosceles")
516 ), 1
517 );
518 }
519
520
521 ///////////////////////////////////////////////////////////
522 // //
523 ///////////////////////////////////////////////////////////
524
525 //---------------------------------------------------------
On_Parameter_Changed(CSG_Parameters * pParameters,CSG_Parameter * pParameter)526 int CSoil_Texture::On_Parameter_Changed(CSG_Parameters *pParameters, CSG_Parameter *pParameter)
527 {
528 if( pParameter->Cmp_Identifier("SCHEME") )
529 {
530 CSoil_Texture_Classifier::Get_Table(*pParameters->Get_Parameter("USER")->asTable(), pParameter->asInt());
531 }
532
533 return( CSG_Tool_Grid::On_Parameter_Changed(pParameters, pParameter) );
534 }
535
536 //---------------------------------------------------------
On_Parameters_Enable(CSG_Parameters * pParameters,CSG_Parameter * pParameter)537 int CSoil_Texture::On_Parameters_Enable(CSG_Parameters *pParameters, CSG_Parameter *pParameter)
538 {
539 if( pParameter->Cmp_Identifier("POLYGONS") )
540 {
541 pParameters->Set_Enabled("XY_AXES" , pParameter->asPointer() != NULL);
542 pParameters->Set_Enabled("TRIANGLE", pParameter->asPointer() != NULL);
543 }
544
545 if( pParameter->Cmp_Identifier("SCHEME") )
546 {
547 pParameters->Set_Enabled("COLORS" , pParameter->asInt() != 0);
548 pParameters->Set_Enabled("USER" , pParameter->asInt() == 3);
549 }
550
551 return( CSG_Tool_Grid::On_Parameters_Enable(pParameters, pParameter) );
552 }
553
554
555 ///////////////////////////////////////////////////////////
556 // //
557 ///////////////////////////////////////////////////////////
558
559 //---------------------------------------------------------
On_Execute(void)560 bool CSoil_Texture::On_Execute(void)
561 {
562 //-----------------------------------------------------
563 CSG_Grid *pSand = Parameters("SAND" )->asGrid();
564 CSG_Grid *pSilt = Parameters("SILT" )->asGrid();
565 CSG_Grid *pClay = Parameters("CLAY" )->asGrid();
566 CSG_Grid *pClass = Parameters("TEXTURE")->asGrid();
567 CSG_Grid *pSum = Parameters("SUM" )->asGrid();
568
569 //-----------------------------------------------------
570 if( (pSand ? 1 : 0) + (pSilt ? 1 : 0) + (pClay ? 1 : 0) < 2 )
571 {
572 Error_Set(_TL("at least two contents (sand, silt, clay) have to be given"));
573
574 return( false );
575 }
576
577 //-----------------------------------------------------
578 CSoil_Texture_Classifier Classifier(Parameters("SCHEME")->asInt(), Parameters("COLORS")->asInt());
579
580 if( Parameters("SCHEME")->asInt() == 3 && !Classifier.Initialize(*Parameters("USER")->asTable(), Parameters("COLORS")->asInt()) ) // user defined
581 {
582 return( false );
583 }
584
585 //-----------------------------------------------------
586 pClass->Set_NoData_Value(0.0);
587
588 CSG_Parameter *pLUT = DataObject_Get_Parameter(pClass, "LUT");
589
590 if( pLUT && pLUT->asTable() )
591 {
592 Classifier.Set_LUT(pLUT->asTable(), true);
593
594 DataObject_Set_Parameter(pClass, pLUT ); // Lookup Table
595 DataObject_Set_Parameter(pClass, "COLORS_TYPE", 1); // Color Classification Type: Lookup Table
596 }
597
598 if( Classifier.Get_Polygons(Parameters("POLYGONS")->asShapes(), Parameters("XY_AXES")->asInt(), Parameters("TRIANGLE")->asInt() == 1)
599 && (pLUT = DataObject_Get_Parameter(pClass, "LUT")) != NULL && pLUT->asTable() )
600 {
601 Classifier.Set_LUT(pLUT->asTable(), true);
602
603 DataObject_Set_Parameter(Parameters("POLYGONS")->asShapes(), pLUT ); // Lookup Table
604 DataObject_Set_Parameter(Parameters("POLYGONS")->asShapes(), "COLORS_TYPE", 1); // Color Classification Type: Lookup Table
605 DataObject_Set_Parameter(Parameters("POLYGONS")->asShapes(), "LUT_ATTRIB" , 0); // Lookup Table Attribute
606 }
607
608 //-----------------------------------------------------
609 for(int y=0; y<Get_NY() && Set_Progress(y); y++)
610 {
611 #pragma omp parallel for
612 for(int x=0; x<Get_NX(); x++)
613 {
614 if( (pSand && pSand->is_NoData(x, y))
615 || (pSilt && pSilt->is_NoData(x, y))
616 || (pClay && pClay->is_NoData(x, y)) )
617 {
618 SG_GRID_PTR_SAFE_SET_NODATA(pClass, x, y);
619 SG_GRID_PTR_SAFE_SET_NODATA(pSum , x, y);
620 }
621 else
622 {
623 double Sum;
624
625 int Class = Classifier.Get_Texture(
626 pSand ? pSand->asDouble(x, y) : -1.0,
627 pSilt ? pSilt->asDouble(x, y) : -1.0,
628 pClay ? pClay->asDouble(x, y) : -1.0, Sum
629 );
630
631 SG_GRID_PTR_SAFE_SET_VALUE(pClass, x, y, Classifier.Get_ID(Class));
632 SG_GRID_PTR_SAFE_SET_VALUE(pSum , x, y, Sum);
633 }
634 }
635 }
636
637 //-----------------------------------------------------
638 return( true );
639 }
640
641
642 ///////////////////////////////////////////////////////////
643 // //
644 // //
645 // //
646 ///////////////////////////////////////////////////////////
647
648 //---------------------------------------------------------
CSoil_Texture_Table(void)649 CSoil_Texture_Table::CSoil_Texture_Table(void)
650 {
651 Set_Name (_TL("Soil Texture Classification for Tables"));
652
653 Set_Author ("Gianluca Massei (c) 2007 (g_massa@libero.it), L.Landschreiber, O.Conrad (c) 2017");
654
655 Set_Description (CSoil_Texture_Classifier::Get_Description());
656
657 Add_Reference(
658 "http://soils.usda.gov/technical/aids/investigations/texture/",
659 SG_T("USDA NRCS Soils Website")
660 );
661
662 //-----------------------------------------------------
663 Parameters.Add_Table("",
664 "TABLE" , _TL("Table"),
665 _TL(""),
666 PARAMETER_INPUT
667 );
668
669 Parameters.Add_Table_Field("TABLE",
670 "SAND" , _TL("Sand"),
671 _TL("sand content given as percentage"),
672 true
673 );
674
675 Parameters.Add_Table_Field("TABLE",
676 "SILT" , _TL("Silt"),
677 _TL("silt content given as percentage"),
678 true
679 );
680
681 Parameters.Add_Table_Field("TABLE",
682 "CLAY" , _TL("Clay"),
683 _TL("clay content given as percentage"),
684 true
685 );
686
687 Parameters.Add_Table_Field("TABLE",
688 "TEXTURE" , _TL("Texture"),
689 _TL("soil texture"),
690 true
691 );
692
693 Parameters.Add_Choice("",
694 "SCHEME" , _TL("Classification"),
695 _TL(""),
696 CSG_String::Format("%s|%s|%s|%s|",
697 _TL("USDA"),
698 _TL("Germany KA5"),
699 _TL("Belgium/France"),
700 _TL("user defined")
701 )
702 );
703
704 Parameters.Add_Choice("",
705 "COLORS" , _TL("Default Colour Scheme"),
706 _TL(""),
707 CSG_String::Format("%s 1|%s 2|%s 3|",
708 _TL("Scheme"),
709 _TL("Scheme"),
710 _TL("Scheme")
711 )
712 );
713
714 Parameters.Add_FixedTable("SCHEME",
715 "USER" , _TL("User Definition"),
716 _TW("The colour is defined as comma separated red, green and blue values (in the range 0 to 255). "
717 "If the colour field is empty it will be generated from the chosen default colour scheme. "
718 "Key and name are simple text labels specifying each class. The polygon is defined as pairs of "
719 "sand (=x) and clay (=y) separated by a blank and separated from the next pair by a comma. "
720 )
721 );
722
723 CSoil_Texture_Classifier::Get_Table(*Parameters("USER")->asTable(), 0);
724
725 Parameters.Add_Shapes("",
726 "POLYGONS" , _TL("Scheme as Polygons"),
727 _TL(""),
728 PARAMETER_OUTPUT_OPTIONAL, SHAPE_TYPE_Polygon
729 );
730
731 Parameters.Add_Choice("POLYGONS",
732 "XY_AXES" , _TL("X/Y Axes"),
733 _TL(""),
734 CSG_String::Format("%s|%s|%s|%s|%s|%s|",
735 _TL("Sand and Clay"),
736 _TL("Sand and Silt"),
737 _TL("Silt and Sand"),
738 _TL("Silt and Clay"),
739 _TL("Clay and Sand"),
740 _TL("Clay and Silt")
741 ), 3
742 );
743
744 Parameters.Add_Choice("POLYGONS",
745 "TRIANGLE" , _TL("Triangle"),
746 _TL(""),
747 CSG_String::Format("%s|%s|",
748 _TL("right-angled"),
749 _TL("isosceles")
750 ), 1
751 );
752 }
753
754
755 ///////////////////////////////////////////////////////////
756 // //
757 ///////////////////////////////////////////////////////////
758
759 //---------------------------------------------------------
On_Parameter_Changed(CSG_Parameters * pParameters,CSG_Parameter * pParameter)760 int CSoil_Texture_Table::On_Parameter_Changed(CSG_Parameters *pParameters, CSG_Parameter *pParameter)
761 {
762 if( pParameter->Cmp_Identifier("SCHEME") )
763 {
764 CSoil_Texture_Classifier::Get_Table(*pParameters->Get_Parameter("USER")->asTable(), pParameter->asInt());
765 }
766
767 return( CSG_Tool::On_Parameter_Changed(pParameters, pParameter) );
768 }
769
770 //---------------------------------------------------------
On_Parameters_Enable(CSG_Parameters * pParameters,CSG_Parameter * pParameter)771 int CSoil_Texture_Table::On_Parameters_Enable(CSG_Parameters *pParameters, CSG_Parameter *pParameter)
772 {
773 if( pParameter->Cmp_Identifier("POLYGONS") )
774 {
775 pParameters->Set_Enabled("XY_AXES" , pParameter->asPointer() != NULL);
776 pParameters->Set_Enabled("TRIANGLE", pParameter->asPointer() != NULL);
777 }
778
779 if( pParameter->Cmp_Identifier("SCHEME") )
780 {
781 pParameters->Set_Enabled("COLORS" , pParameter->asInt() != 0);
782 pParameters->Set_Enabled("USER" , pParameter->asInt() == 3);
783 }
784
785 return( CSG_Tool::On_Parameters_Enable(pParameters, pParameter) );
786 }
787
788
789 ///////////////////////////////////////////////////////////
790 // //
791 ///////////////////////////////////////////////////////////
792
793 //---------------------------------------------------------
On_Execute(void)794 bool CSoil_Texture_Table::On_Execute(void)
795 {
796 //-----------------------------------------------------
797 CSG_Table *pTable = Parameters("TABLE")->asTable();
798
799 int iSand = Parameters("SAND" )->asInt();
800 int iSilt = Parameters("SILT" )->asInt();
801 int iClay = Parameters("CLAY" )->asInt();
802 int iTexture = Parameters("TEXTURE")->asInt();
803
804 //-----------------------------------------------------
805 if( (iSand >= 0 ? 1 : 0) + (iSilt >= 0 ? 1 : 0) + (iClay >= 0 ? 1 : 0) < 2 )
806 {
807 Error_Set(_TL("at least two contents (sand, silt, clay) have to be given"));
808
809 return( false );
810 }
811
812 //-----------------------------------------------------
813 CSoil_Texture_Classifier Classifier(Parameters("SCHEME")->asInt(), Parameters("COLORS")->asInt());
814
815 if( Parameters("SCHEME")->asInt() == 3 && !Classifier.Initialize(*Parameters("USER")->asTable(), Parameters("COLORS")->asInt()) ) // user defined
816 {
817 return( false );
818 }
819
820 //-----------------------------------------------------
821 if( iTexture < 0 )
822 {
823 iTexture = pTable->Get_Field_Count();
824
825 pTable->Add_Field("TEXTURE", SG_DATATYPE_String);
826 }
827
828 //-----------------------------------------------------
829 for(int i=0; i<pTable->Get_Count() && Set_Progress(i, pTable->Get_Count()); i++)
830 {
831 CSG_Table_Record *pRecord = pTable->Get_Record(i);
832
833 if( (iSand >= 0 && pRecord->is_NoData(iSand))
834 || (iSilt >= 0 && pRecord->is_NoData(iSilt))
835 || (iClay >= 0 && pRecord->is_NoData(iClay)) )
836 {
837 pRecord->Set_NoData(iTexture);
838 }
839 else
840 {
841 double Sum;
842
843 int Class = Classifier.Get_Texture(
844 iSand >= 0 ? pRecord->asDouble(iSand) : -1.0,
845 iSilt >= 0 ? pRecord->asDouble(iSilt) : -1.0,
846 iClay >= 0 ? pRecord->asDouble(iClay) : -1.0, Sum
847 );
848
849 pRecord->Set_Value (iTexture, Classifier.Get_Key(Class));
850 }
851 }
852
853 DataObject_Update(pTable);
854
855 //-----------------------------------------------------
856 CSG_Parameter *pLUT = DataObject_Get_Parameter(pTable, "LUT");
857
858 if( pLUT && pLUT->asTable() )
859 {
860 Classifier.Set_LUT(pLUT->asTable(), false);
861
862 DataObject_Set_Parameter(pTable, pLUT ); // Lookup Table
863 DataObject_Set_Parameter(pTable, "COLORS_TYPE", 1 ); // Color Classification Type: Lookup Table
864 DataObject_Set_Parameter(pTable, "LUT_ATTRIB" , iTexture); // Lookup Table Attribute
865 }
866
867 if( Classifier.Get_Polygons(Parameters("POLYGONS")->asShapes(), Parameters("XY_AXES")->asInt(), Parameters("TRIANGLE")->asInt() == 1)
868 && (pLUT = DataObject_Get_Parameter(pTable, "LUT")) != NULL && pLUT->asTable() )
869 {
870 Classifier.Set_LUT(pLUT->asTable(), true);
871
872 DataObject_Set_Parameter(Parameters("POLYGONS")->asShapes(), pLUT ); // Lookup Table
873 DataObject_Set_Parameter(Parameters("POLYGONS")->asShapes(), "COLORS_TYPE", 1); // Color Classification Type: Lookup Table
874 DataObject_Set_Parameter(Parameters("POLYGONS")->asShapes(), "LUT_ATTRIB" , 0); // Lookup Table Attribute
875 }
876
877 //-----------------------------------------------------
878 return( true );
879 }
880
881
882 ///////////////////////////////////////////////////////////
883 // //
884 // //
885 // //
886 ///////////////////////////////////////////////////////////
887
888 //---------------------------------------------------------
889