1 
2 ///////////////////////////////////////////////////////////
3 //                                                       //
4 //                         SAGA                          //
5 //                                                       //
6 //      System for Automated Geoscientific Analyses      //
7 //                                                       //
8 //                     Tool Library                      //
9 //                    ta_morphometry                     //
10 //                                                       //
11 //-------------------------------------------------------//
12 //                                                       //
13 //                        tpi.cpp                        //
14 //                                                       //
15 //                 Copyright (C) 2011 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 "tpi.h"
50 
51 
52 ///////////////////////////////////////////////////////////
53 //														 //
54 //														 //
55 //														 //
56 ///////////////////////////////////////////////////////////
57 
58 //---------------------------------------------------------
CTPI(void)59 CTPI::CTPI(void)
60 {
61 	//-----------------------------------------------------
62 	Set_Name		(_TL("Topographic Position Index (TPI)"));
63 
64 	Set_Author		("O.Conrad (c) 2011");
65 
66 	Set_Description	(_TW(
67 		"Topographic Position Index (TPI) calculation as proposed by Guisan et al. (1999). "
68 		"This is literally the same as the difference to the mean calculation (residual analysis) "
69 		"proposed by Wilson & Gallant (2000). "
70 		"The bandwidth parameter for distance weighting is given as percentage of the (outer) radius."
71 	));
72 
73 	Add_Reference(
74 		"Guisan, A., Weiss, S.B., Weiss, A.D.", "1999",
75 		"GLM versus CCA spatial modeling of plant species distribution",
76 		"Plant Ecology 143: 107-122."
77 	);
78 
79 	Add_Reference(
80 		"Weiss, A.D.", "2000",
81 		"Topographic Position and Landforms Analysis",
82 		"Poster", SG_T("http://www.jennessent.com/downloads/tpi-poster-tnc_18x22.pdf")
83 	);
84 
85 	Add_Reference(
86 		"Wilson, J.P. & Gallant, J.C.", "2000",
87 		"Primary Topographic Attributes",
88 		"In: Wilson, J.P. & Gallant, J.C. [Eds.]: Terrain Analysis: Principles and Applications, John Wiley & Sons, p.51-85."
89 	);
90 
91 	//-----------------------------------------------------
92 	Parameters.Add_Grid(
93 		"", "DEM"		, _TL("Elevation"),
94 		_TL(""),
95 		PARAMETER_INPUT
96 	);
97 
98 	Parameters.Add_Grid(
99 		"", "TPI"		, _TL("Topographic Position Index"),
100 		_TL(""),
101 		PARAMETER_OUTPUT
102 	);
103 
104 	Parameters.Add_Bool(
105 		"", "STANDARD"	, _TL("Standardize"),
106 		_TL(""),
107 		false
108 	);
109 
110 	Parameters.Add_Range(
111 		"", "RADIUS"	, _TL("Scale"),
112 		_TL("kernel radius in map units; defines an annulus if inner radius is greater than zero"),
113 		0., 100., 0., true
114 	);
115 
116 	m_Kernel.Get_Weighting().Set_BandWidth(75.);	// 75%
117 	m_Kernel.Get_Weighting().Create_Parameters(Parameters);
118 }
119 
120 
121 ///////////////////////////////////////////////////////////
122 //														 //
123 ///////////////////////////////////////////////////////////
124 
125 //---------------------------------------------------------
On_Parameters_Enable(CSG_Parameters * pParameters,CSG_Parameter * pParameter)126 int CTPI::On_Parameters_Enable(CSG_Parameters *pParameters, CSG_Parameter *pParameter)
127 {
128 	m_Kernel.Get_Weighting().Enable_Parameters(*pParameters);
129 
130 	return( CSG_Tool_Grid::On_Parameters_Enable(pParameters, pParameter) );
131 }
132 
133 
134 ///////////////////////////////////////////////////////////
135 //														 //
136 ///////////////////////////////////////////////////////////
137 
138 //---------------------------------------------------------
On_Execute(void)139 bool CTPI::On_Execute(void)
140 {
141 	m_pDEM	= Parameters("DEM")->asGrid();
142 	m_pTPI	= Parameters("TPI")->asGrid();
143 
144 	DataObject_Set_Colors(m_pTPI, 11, SG_COLORS_RED_GREY_BLUE, true);
145 
146 	//-----------------------------------------------------
147 	double	r_inner	= Parameters("RADIUS")->asRange()->Get_Min() / Get_Cellsize();
148 	double	r_outer	= Parameters("RADIUS")->asRange()->Get_Max() / Get_Cellsize();
149 
150 	m_Kernel.Get_Weighting().Set_Parameters(Parameters);
151 	m_Kernel.Get_Weighting().Set_BandWidth(r_outer * m_Kernel.Get_Weighting().Get_BandWidth() / 100.);
152 
153 	if( !m_Kernel.Set_Annulus(r_inner, r_outer) )
154 	{
155 		return( false );
156 	}
157 
158 	//-----------------------------------------------------
159 	for(int y=0; y<Get_NY() && Set_Progress(y); y++)
160 	{
161 		#pragma omp parallel for
162 		for(int x=0; x<Get_NX(); x++)
163 		{
164 			Get_Statistics(x, y);
165 		}
166 	}
167 
168 	//-----------------------------------------------------
169 	m_Kernel.Destroy();
170 
171 	if( Parameters("STANDARD")->asBool() )
172 	{
173 		m_pTPI->Standardise();
174 	}
175 
176 	return( true );
177 }
178 
179 
180 ///////////////////////////////////////////////////////////
181 //														 //
182 ///////////////////////////////////////////////////////////
183 
184 //---------------------------------------------------------
Get_Statistics(int x,int y)185 bool CTPI::Get_Statistics(int x, int y)
186 {
187 	if( m_pDEM->is_InGrid(x, y) )
188 	{
189 		int		i, ix, iy;
190 		double	z, id, iw;
191 
192 		CSG_Simple_Statistics	Statistics;
193 
194 		for(i=0, z=m_pDEM->asDouble(x, y); i<m_Kernel.Get_Count(); i++)
195 		{
196 			if( m_Kernel.Get_Values(i, ix = x, iy = y, id, iw, true) && id >= 0. && m_pDEM->is_InGrid(ix, iy) )
197 			{
198 				Statistics.Add_Value(m_pDEM->asDouble(ix, iy), iw);
199 			}
200 		}
201 
202 		//-------------------------------------------------
203 		if( Statistics.Get_Weights() > 0. )
204 		{
205 			m_pTPI->Set_Value(x, y, z - Statistics.Get_Mean());
206 
207 			return( true );
208 		}
209 	}
210 
211 	//-----------------------------------------------------
212 	m_pTPI->Set_NoData(x, y);
213 
214 	return( false );
215 }
216 
217 
218 ///////////////////////////////////////////////////////////
219 //														 //
220 //														 //
221 //														 //
222 ///////////////////////////////////////////////////////////
223 
224 //---------------------------------------------------------
CTPI_Classification(void)225 CTPI_Classification::CTPI_Classification(void)
226 {
227 	//-----------------------------------------------------
228 	Set_Name		(_TL("TPI Based Landform Classification"));
229 
230 	Set_Author		("O.Conrad (c) 2011");
231 
232 	Set_Description	(_TW(
233 		"Topographic Position Index (TPI) calculation as proposed by Guisan et al. (1999). "
234 		"This is literally the same as the difference to the mean calculation (residual analysis) "
235 		"proposed by Wilson & Gallant (2000). "
236 		"The bandwidth parameter for distance weighting is given as percentage of the (outer) radius."
237 	));
238 
239 	Add_Reference(
240 		"Guisan, A., Weiss, S.B., Weiss, A.D.", "1999",
241 		"GLM versus CCA spatial modeling of plant species distribution",
242 		"Plant Ecology 143: 107-122."
243 	);
244 
245 	Add_Reference(
246 		"Weiss, A.D.", "2000",
247 		"Topographic Position and Landforms Analysis",
248 		"Poster", SG_T("http://www.jennessent.com/downloads/tpi-poster-tnc_18x22.pdf")
249 	);
250 
251 	Add_Reference(
252 		"Wilson, J.P. & Gallant, J.C.", "2000",
253 		"Primary Topographic Attributes",
254 		"In: Wilson, J.P. & Gallant, J.C. [Eds.]: Terrain Analysis: Principles and Applications, John Wiley & Sons, p.51-85."
255 	);
256 
257 	//-----------------------------------------------------
258 	Parameters.Add_Grid(
259 		"", "DEM"		, _TL("Elevation"),
260 		_TL(""),
261 		PARAMETER_INPUT
262 	);
263 
264 	Parameters.Add_Grid(
265 		"", "LANDFORMS"	, _TL("Landforms"),
266 		_TL(""),
267 		PARAMETER_OUTPUT, true, SG_DATATYPE_Byte
268 	);
269 
270 	Parameters.Add_Range(
271 		"", "RADIUS_A"	, _TL("Small Scale"),
272 		_TL("kernel radius in map units; defines an annulus if inner radius is greater than zero"),
273 		0., 100., 0., true
274 	);
275 
276 	Parameters.Add_Range(
277 		"", "RADIUS_B"	, _TL("Large Scale"),
278 		_TL("kernel radius in map units; defines an annulus if inner radius is greater than zero"),
279 		0., 1000., 0., true
280 	);
281 
282 	m_Weighting.Set_BandWidth(75.);	// 75%
283 	m_Weighting.Create_Parameters(Parameters);
284 }
285 
286 
287 ///////////////////////////////////////////////////////////
288 //														 //
289 ///////////////////////////////////////////////////////////
290 
291 //---------------------------------------------------------
292 enum
293 {
294 	LF_CANYON	= 1,
295 	LF_MID_SLOPE,
296 	LF_UPLAND,
297 	LF_VALLEY,
298 	LF_PLAIN,
299 	LF_OPEN_SLOPE,
300 	LF_UPPER_SLOPE,
301 	LF_LOCAL_RIDGE,
302 	LF_MIDSLOPE_RIDGE,
303 	LF_HIGH_RIDGE,
304 	LF_COUNT	= LF_HIGH_RIDGE
305 };
306 
307 
308 ///////////////////////////////////////////////////////////
309 //														 //
310 ///////////////////////////////////////////////////////////
311 
312 //---------------------------------------------------------
On_Parameters_Enable(CSG_Parameters * pParameters,CSG_Parameter * pParameter)313 int CTPI_Classification::On_Parameters_Enable(CSG_Parameters *pParameters, CSG_Parameter *pParameter)
314 {
315 	m_Weighting.Enable_Parameters(*pParameters);
316 
317 	return( CSG_Tool_Grid::On_Parameters_Enable(pParameters, pParameter) );
318 }
319 
320 
321 ///////////////////////////////////////////////////////////
322 //														 //
323 ///////////////////////////////////////////////////////////
324 
325 //---------------------------------------------------------
On_Execute(void)326 bool CTPI_Classification::On_Execute(void)
327 {
328 	//-----------------------------------------------------
329 	CSG_Grid	*pDEM		= Parameters("DEM"      )->asGrid();
330 	CSG_Grid	*pLandforms	= Parameters("LANDFORMS")->asGrid();
331 
332 	pLandforms->Set_NoData_Value(0);
333 
334 	//-----------------------------------------------------
335 	CSG_Parameter	*pLUT	= DataObject_Get_Parameter(pLandforms, "LUT");
336 
337 	if( pLUT )
338 	{
339 		const int LF_Colors[LF_COUNT]	=
340 		{
341 			SG_GET_RGB(  0,   0, 127),	// LF_CANYON
342 			SG_GET_RGB(200, 200, 255),	// LF_MID_SLOPE
343 			SG_GET_RGB(  0, 200, 255),	// LF_UPLAND
344 			SG_GET_RGB(127, 127, 255),	// LF_VALLEY
345 			SG_GET_RGB(255, 255, 128),	// LF_PLAIN
346 			SG_GET_RGB(128, 255,   0),	// LF_OPEN_SLOPE
347 			SG_GET_RGB(  0, 255,   0),	// LF_UPPER_SLOPE
348 			SG_GET_RGB(255, 200, 127),	// LF_LOCAL_RIDGE
349 			SG_GET_RGB(255, 127,   0),	// LF_MIDSLOPE_RIDGE
350 			SG_GET_RGB(255,   0,   0)	// LF_HIGH_RIDGE
351 		};
352 
353 		//-------------------------------------------------
354 		CSG_Strings	Name, Desc;
355 
356 		Name	+= _TL("Streams"           );	Desc	+= _TL("Canyons, Deeply Incised Streams"       );
357 		Name	+= _TL("Midslope Drainages");	Desc	+= _TL("Midslope Drainages, Shallow Valleys"   );
358 		Name	+= _TL("Upland Drainages"  );	Desc	+= _TL("Upland Drainages, Headwaters"          );
359 		Name	+= _TL("Valleys"           );	Desc	+= _TL("U-shaped Valleys"                      );
360 		Name	+= _TL("Plains"            );	Desc	+= _TL("Plains"                                );
361 		Name	+= _TL("Open Slopes"       );	Desc	+= _TL("Open Slopes"                           );
362 		Name	+= _TL("Upper Slopes"      );	Desc	+= _TL("Upper Slopes, Mesas"                   );
363 		Name	+= _TL("Local Ridges"      );	Desc	+= _TL("Local Ridges, Hills in Valleys"        );
364 		Name	+= _TL("Midslope Ridges"   );	Desc	+= _TL("Midslope Ridges, Small Hills in Plains");
365 		Name	+= _TL("High Ridges"       );	Desc	+= _TL("Mountain Tops, High Ridges"            );
366 
367 		//-------------------------------------------------
368 		CSG_Table	*pTable	= pLUT->asTable();
369 
370 		pLUT->asTable()->Del_Records();
371 
372 		for(int i=0; i<LF_COUNT; i++)
373 		{
374 			CSG_Table_Record	*pRecord	= pLUT->asTable()->Add_Record();
375 
376 			pRecord->Set_Value(0, LF_Colors[i]);
377 			pRecord->Set_Value(1, Name[i].c_str());
378 			pRecord->Set_Value(2, Desc[i].c_str());
379 			pRecord->Set_Value(3, i + 1);
380 			pRecord->Set_Value(4, i + 1);
381 		}
382 
383 		DataObject_Set_Parameter(pLandforms, pLUT);
384 		DataObject_Set_Parameter(pLandforms, "COLORS_TYPE", 1);	// Color Classification Type: Lookup Table
385 	}
386 
387 	//-----------------------------------------------------
388 	CTPI	Calculator;	Calculator.Set_Manager(NULL);
389 
390 	Calculator.Get_Parameters()->Assign_Values(&Parameters);	// set DEM and Weighting scheme
391 
392 	Calculator.Set_Parameter("STANDARD", true);
393 
394 	//-----------------------------------------------------
395 	CSG_Grid	gA(Get_System());
396 
397 	Calculator.Set_Parameter("TPI"   , &gA);
398 	Calculator.Set_Parameter("RADIUS", Parameters("RADIUS_A"));
399 
400 	if( !Calculator.Execute() )
401 	{
402 		return( false );
403 	}
404 
405 	//-----------------------------------------------------
406 	CSG_Grid	gB(Get_System());
407 
408 	Calculator.Set_Parameter("TPI"   , &gB);
409 	Calculator.Set_Parameter("RADIUS", Parameters("RADIUS_B"));
410 
411 	if( !Calculator.Execute() )
412 	{
413 		return( false );
414 	}
415 
416 	//-----------------------------------------------------
417 	for(int y=0; y<Get_NY() && Set_Progress(y); y++)
418 	{
419 		#pragma omp parallel for
420 		for(int x=0; x<Get_NX(); x++)
421 		{
422 			if( pDEM->is_NoData(x, y) )
423 			{
424 				pLandforms->Set_Value(x, y, 0.);
425 			}
426 			else
427 			{
428 				double	A	= gA.asDouble(x, y);
429 				double	B	= gB.asDouble(x, y);
430 
431 				if( A <= -1. )
432 				{
433 					if( B <= -1. )
434 					{	// Canyons, Deeply Incised Streams
435 						pLandforms->Set_Value(x, y, LF_CANYON);
436 					}
437 					else if( B < 1. )
438 					{	// Midslope Drainages, Shallow Valleys
439 						pLandforms->Set_Value(x, y, LF_MID_SLOPE);
440 					}
441 					else // if( B >= 1. )
442 					{	// Upland Drainages, Headwaters
443 						pLandforms->Set_Value(x, y, LF_UPLAND);
444 					}
445 				}
446 				else if( A < 1. )
447 				{
448 					if( B <= -1. )
449 					{	// U-shaped Valleys
450 						pLandforms->Set_Value(x, y, LF_VALLEY);
451 					}
452 					else if( B < 1. )
453 					{
454 						double	Slope, Aspect;
455 
456 						pDEM->Get_Gradient(x, y, Slope, Aspect);
457 
458 						if( Slope <= 5. * M_DEG_TO_RAD )
459 						{	// Plains
460 							pLandforms->Set_Value(x, y, LF_PLAIN);
461 						}
462 						else
463 						{	// Open Slopes
464 							pLandforms->Set_Value(x, y, LF_OPEN_SLOPE);
465 						}
466 					}
467 					else // if( B >= 1. )
468 					{	// Upper Slopes, Mesas
469 						pLandforms->Set_Value(x, y, LF_UPPER_SLOPE);
470 					}
471 				}
472 				else // if( A >= 1. )
473 				{
474 					if( B <= -1. )
475 					{	// Local Ridges, Hills in Valleys
476 						pLandforms->Set_Value(x, y, LF_LOCAL_RIDGE);
477 					}
478 					else if( B < 1. )
479 					{	// Midslope Ridges, Small Hills in Plains
480 						pLandforms->Set_Value(x, y, LF_MIDSLOPE_RIDGE);
481 					}
482 					else // if( B >= 1. )
483 					{	// Mountain Tops, High Ridges
484 						pLandforms->Set_Value(x, y, LF_HIGH_RIDGE);
485 					}
486 				}
487 			}
488 		}
489 	}
490 
491 	//-----------------------------------------------------
492 	return( true );
493 }
494 
495 
496 ///////////////////////////////////////////////////////////
497 //														 //
498 //														 //
499 //														 //
500 ///////////////////////////////////////////////////////////
501 
502 //---------------------------------------------------------
CTPI_MultiScale(void)503 CTPI_MultiScale::CTPI_MultiScale(void)
504 {
505 	//-----------------------------------------------------
506 	Set_Name		(_TL("Multi-Scale Topographic Position Index (TPI)"));
507 
508 	Set_Author		("O.Conrad (c) 2016");
509 
510 	Set_Description	(_TW(
511 		"Topographic Position Index (TPI) calculation as proposed by Guisan et al. (1999).\n"
512 		"\n"
513 		"This implementation calculates the TPI for different scales and integrates these into one "
514 		"single grid. The hierarchical integration is achieved by starting with the standardized "
515 		"TPI values of the largest scale, then adding standardized values from smaller scales "
516 		"where the (absolute) values from the smaller scale exceed those from the larger scale. "
517 		"This integration scheme has been proposed by N. Zimmermann."
518 	));
519 
520 	Add_Reference(
521 		"Guisan, A., Weiss, S.B., Weiss, A.D.", "1999",
522 		"GLM versus CCA spatial modeling of plant species distribution",
523 		"Plant Ecology 143: 107-122."
524 	);
525 
526 	Add_Reference(
527 		"Weiss, A.D.", "2000",
528 		"Topographic Position and Landforms Analysis",
529 		"Poster", SG_T("http://www.jennessent.com/downloads/tpi-poster-tnc_18x22.pdf")
530 	);
531 
532 	Add_Reference(
533 		"Wilson, J.P. & Gallant, J.C.", "2000",
534 		"Primary Topographic Attributes",
535 		"In: Wilson, J.P. & Gallant, J.C. [Eds.]: Terrain Analysis: Principles and Applications, John Wiley & Sons, p.51-85."
536 	);
537 
538 	Add_Reference(
539 		"www.wsl.ch/staff/niklaus.zimmermann/programs/aml4_1.html",
540 		SG_T("toposcale.aml script by N.Zimmermann")
541 	);
542 
543 	//-----------------------------------------------------
544 	Parameters.Add_Grid(
545 		"", "DEM"		, _TL("Elevation"),
546 		_TL(""),
547 		PARAMETER_INPUT
548 	);
549 
550 	Parameters.Add_Grid(
551 		"", "TPI"		, _TL("Topographic Position Index"),
552 		_TL(""),
553 		PARAMETER_OUTPUT
554 	);
555 
556 	Parameters.Add_Int(
557 		"", "SCALE_MIN"	, _TL("Minimum Scale"),
558 		_TL("kernel radius in cells"),
559 		1, 1, true
560 	);
561 
562 	Parameters.Add_Int(
563 		"", "SCALE_MAX"	, _TL("Maximum Scale"),
564 		_TL("kernel radius in cells"),
565 		8, 1, true
566 	);
567 
568 	Parameters.Add_Int(
569 		"", "SCALE_NUM"	, _TL("Number of Scales"),
570 		_TL(""),
571 		3, 2, true
572 	);
573 
574 	Parameters.Add_Bool(
575 		"", "UPDATE"	, _TL("Update"),
576 		_TL("update view for each integration step"),
577 		false
578 	)->Set_UseInCMD(false);
579 }
580 
581 
582 ///////////////////////////////////////////////////////////
583 //														 //
584 ///////////////////////////////////////////////////////////
585 
586 //---------------------------------------------------------
On_Parameter_Changed(CSG_Parameters * pParameters,CSG_Parameter * pParameter)587 int CTPI_MultiScale::On_Parameter_Changed(CSG_Parameters *pParameters, CSG_Parameter *pParameter)
588 {
589 	if( pParameter->Cmp_Identifier("SCALE_MIN") )
590 	{
591 		if( pParameter->asInt() > pParameters->Get_Parameter("SCALE_MAX")->asInt() )
592 		{
593 			pParameter->Set_Value(pParameters->Get_Parameter("SCALE_MAX")->asInt());
594 		}
595 	}
596 
597 	if( pParameter->Cmp_Identifier("SCALE_MAX") )
598 	{
599 		if( pParameter->asInt() < pParameters->Get_Parameter("SCALE_MIN")->asInt() )
600 		{
601 			pParameter->Set_Value(pParameters->Get_Parameter("SCALE_MIN")->asInt());
602 		}
603 	}
604 
605 	//-----------------------------------------------------
606 	int	Range	= pParameters->Get_Parameter("SCALE_MAX")->asInt()
607 				- pParameters->Get_Parameter("SCALE_MIN")->asInt();
608 
609 	if( Range > 0 && Range + 1 < pParameters->Get_Parameter("SCALE_NUM")->asInt() )
610 	{
611 		pParameters->Set_Parameter("SCALE_NUM", Range + 1);
612 	}
613 
614 	//-----------------------------------------------------
615 	return( CSG_Tool_Grid::On_Parameter_Changed(pParameters, pParameter) );
616 }
617 
618 //---------------------------------------------------------
On_Parameters_Enable(CSG_Parameters * pParameters,CSG_Parameter * pParameter)619 int CTPI_MultiScale::On_Parameters_Enable(CSG_Parameters *pParameters, CSG_Parameter *pParameter)
620 {
621 	pParameters->Set_Enabled("SCALE_NUM",
622 		pParameters->Get_Parameter("SCALE_MIN")->asInt() <
623 		pParameters->Get_Parameter("SCALE_MAX")->asInt()
624 	);
625 
626 	//-----------------------------------------------------
627 	return( CSG_Tool_Grid::On_Parameters_Enable(pParameters, pParameter) );
628 }
629 
630 
631 ///////////////////////////////////////////////////////////
632 //														 //
633 ///////////////////////////////////////////////////////////
634 
635 //---------------------------------------------------------
On_Execute(void)636 bool CTPI_MultiScale::On_Execute(void)
637 {
638 	//-----------------------------------------------------
639 	int	Scale_Min	= Parameters("SCALE_MIN")->asInt();
640 	int	Scale_Max	= Parameters("SCALE_MAX")->asInt();
641 	int	nScales		= Parameters("SCALE_NUM")->asInt();
642 
643 	if( Scale_Min > Scale_Max || nScales < 2 )
644 	{
645 		Error_Fmt("%s (min=%d, max=%d, num=%d)", _TL("invalid parameters"), Scale_Min, Scale_Max, nScales);
646 
647 		return( false );
648 	}
649 
650 	double	Scale	= Get_Cellsize() *  Scale_Max;
651 	double	dScale	= Get_Cellsize() * (Scale_Max - Scale_Min) / (nScales - 1.);
652 
653 	if( dScale <= 0. )
654 	{
655 		nScales	= 1;
656 	}
657 
658 	//-----------------------------------------------------
659 	CSG_Grid	TPI(Get_System()), *pTPI	= Parameters("TPI")->asGrid();
660 
661 	CTPI	Calculator;	Calculator.Set_Manager(NULL);
662 
663 	Calculator.Set_Parameter("DEM"     , Parameters("DEM")->asGrid());
664 	Calculator.Set_Parameter("TPI"     , pTPI);
665 	Calculator.Set_Parameter("STANDARD", true);
666 
667 	Calculator.Get_Parameters()->Get_Parameter("RADIUS")->asRange()->Set_Min(  0.);
668 	Calculator.Get_Parameters()->Get_Parameter("RADIUS")->asRange()->Set_Max(Scale);
669 
670 	Process_Set_Text(  "%s: %.*f [%d/%d]", _TL("Scale"), SG_Get_Significant_Decimals(Scale), Scale, 1, nScales);
671 	Message_Fmt     ("\n%s: %.*f [%d/%d]", _TL("Scale"), SG_Get_Significant_Decimals(Scale), Scale, 1, nScales);
672 
673 	SG_UI_Msg_Lock(true);
674 	Calculator.Execute();
675 	SG_UI_Msg_Lock(false);
676 
677 	Calculator.Set_Parameter("TPI", &TPI);
678 
679 	//-----------------------------------------------------
680 	for(int iScale=1; iScale<nScales && Process_Get_Okay(); iScale++)
681 	{
682 		if( Parameters("UPDATE")->asBool() )
683 		{
684 			DataObject_Update(pTPI);
685 		}
686 
687 		(*Calculator.Get_Parameters())("RADIUS")->asRange()->Set_Max(Scale = Scale - dScale);
688 
689 		Process_Set_Text(  "%s: %.*f [%d/%d]", _TL("Scale"), SG_Get_Significant_Decimals(Scale), Scale, 1 + iScale, nScales);
690 		Message_Fmt     ("\n%s: %.*f [%d/%d]", _TL("Scale"), SG_Get_Significant_Decimals(Scale), Scale, 1 + iScale, nScales);
691 
692 		SG_UI_Msg_Lock(true);
693 		Calculator.Execute();
694 		SG_UI_Msg_Lock(false);
695 
696 		//-------------------------------------------------
697 		#pragma omp parallel for
698 		for(int y=0; y<Get_NY(); y++)
699 		{
700 			for(int x=0; x<Get_NX(); x++)
701 			{
702 				if( !pTPI->is_NoData(x, y) && fabs(pTPI->asDouble(x, y)) < fabs(TPI.asDouble(x, y)) )
703 				{
704 					pTPI->Set_Value(x, y, TPI.asDouble(x, y));
705 				}
706 			}
707 		}
708 	}
709 
710 	//-----------------------------------------------------
711 	return( true );
712 }
713 
714 
715 ///////////////////////////////////////////////////////////
716 //														 //
717 //														 //
718 //														 //
719 ///////////////////////////////////////////////////////////
720 
721 //---------------------------------------------------------
722