1 
2 ///////////////////////////////////////////////////////////
3 //                                                       //
4 //                         SAGA                          //
5 //                                                       //
6 //      System for Automated Geoscientific Analyses      //
7 //                                                       //
8 //                    User Interface                     //
9 //                                                       //
10 //                    Program: SAGA                      //
11 //                                                       //
12 //-------------------------------------------------------//
13 //                                                       //
14 //                WKSP_Layer_Classify.cpp                //
15 //                                                       //
16 //          Copyright (C) 2005 by 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 //    contact:    Olaf Conrad                            //
40 //                Institute of Geography                 //
41 //                University of Goettingen               //
42 //                Goldschmidtstr. 5                      //
43 //                37077 Goettingen                       //
44 //                Germany                                //
45 //                                                       //
46 //    e-mail:     oconrad@saga-gis.org                   //
47 //                                                       //
48 ///////////////////////////////////////////////////////////
49 
50 //---------------------------------------------------------
51 #include "helper.h"
52 
53 #include "wksp_layer.h"
54 #include "wksp_layer_classify.h"
55 #include "wksp_grid.h"
56 #include "wksp_grids.h"
57 #include "wksp_shapes.h"
58 #include "wksp_pointcloud.h"
59 
60 
61 ///////////////////////////////////////////////////////////
62 //														 //
63 //														 //
64 //														 //
65 ///////////////////////////////////////////////////////////
66 
67 //---------------------------------------------------------
CSG_Scaler(void)68 CSG_Scaler::CSG_Scaler(void)
69 {
70 	Create(0., 0.);
71 }
72 
73 //-----------------------------------------------------
CSG_Scaler(double Minimum,double Maximum,double Interval)74 CSG_Scaler::CSG_Scaler(double Minimum, double Maximum, double Interval)
75 {
76 	Create(Minimum, Maximum, Interval);
77 }
78 
79 //-----------------------------------------------------
Create(double Minimum,double Maximum,double Interval)80 bool CSG_Scaler::Create(double Minimum, double Maximum, double Interval)
81 {
82 	return( Set_Interval(Interval) && Set_Range(Minimum, Maximum) );
83 }
84 
85 //-----------------------------------------------------
Set_Range(double Minimum,double Maximum)86 bool CSG_Scaler::Set_Range(double Minimum, double Maximum)
87 {
88 	m_Minimum	= Minimum < Maximum ? Minimum : Maximum;
89 	m_Range		= Minimum < Maximum ? Maximum - Minimum : Minimum - Maximum;
90 
91 	return( m_Range > 0. );
92 }
93 
Set_Interval(double Interval)94 bool CSG_Scaler::Set_Interval(double Interval)
95 {
96 	m_Interval	= Interval < 0. ? DECREASING : Interval > 0. ? INCREASING : LINEAR;
97 	m_LogRange	= fabs(Interval);
98 
99 	return( true );
100 }
101 
102 //-----------------------------------------------------
Set_Linear(CSG_Table * pTable,int Field,double Interval,double Minimum,double Maximum)103 bool CSG_Scaler::Set_Linear(CSG_Table *pTable, int Field, double Interval, double Minimum, double Maximum)
104 {
105 	Minimum	= pTable->Get_Minimum(Field) + pTable->Get_Range(Field) * Minimum / 100.;
106 	Maximum	= pTable->Get_Minimum(Field) + pTable->Get_Range(Field) * Maximum / 100.;
107 
108 	return( Create(Minimum, Maximum, Interval) );
109 }
110 
Set_StdDev(CSG_Table * pTable,int Field,double Interval,double StdDev,bool bKeepInRange)111 bool CSG_Scaler::Set_StdDev(CSG_Table *pTable, int Field, double Interval, double StdDev, bool bKeepInRange)
112 {
113 	double	Minimum	= pTable->Get_Mean(Field) - StdDev * pTable->Get_StdDev(Field); if( bKeepInRange && Minimum < pTable->Get_Minimum(Field) ) Minimum = pTable->Get_Minimum(Field);
114 	double	Maximum	= pTable->Get_Mean(Field) + StdDev * pTable->Get_StdDev(Field); if( bKeepInRange && Maximum > pTable->Get_Maximum(Field) ) Maximum = pTable->Get_Maximum(Field);
115 
116 	return( Create(Minimum, Maximum, Interval) );
117 }
118 
Set_Percentile(CSG_Table * pTable,int Field,double Interval,double Minimum,double Maximum)119 bool CSG_Scaler::Set_Percentile(CSG_Table *pTable, int Field, double Interval, double Minimum, double Maximum)
120 {
121 	return( false );
122 
123 	//	double	Minimum	= pTable->Get_Percentile(Field,        Percentile);
124 	//	double	Maximum	= pTable->Get_Percentile(Field, 100. - Percentile);
125 
126 	//	return( Create(Minimum, Maximum, Interval) );
127 }
128 
129 
130 //-----------------------------------------------------
Set_Linear(CSG_Grid * pGrid,double Interval,double Minimum,double Maximum)131 bool CSG_Scaler::Set_Linear(CSG_Grid *pGrid, double Interval, double Minimum, double Maximum)
132 {
133 	Minimum	= pGrid->Get_Min() + pGrid->Get_Range() * Minimum / 100.;
134 	Maximum	= pGrid->Get_Min() + pGrid->Get_Range() * Maximum / 100.;
135 
136 	return( Create(Minimum, Maximum, Interval) );
137 }
138 
Set_StdDev(CSG_Grid * pGrid,double Interval,double StdDev,bool bKeepInRange)139 bool CSG_Scaler::Set_StdDev(CSG_Grid *pGrid, double Interval, double StdDev, bool bKeepInRange)
140 {
141 	double	Minimum	= pGrid->Get_Mean() - StdDev * pGrid->Get_StdDev(); if( bKeepInRange && Minimum < pGrid->Get_Min() ) Minimum = pGrid->Get_Min();
142 	double	Maximum	= pGrid->Get_Mean() + StdDev * pGrid->Get_StdDev(); if( bKeepInRange && Maximum > pGrid->Get_Max() ) Maximum = pGrid->Get_Max();
143 
144 	return( Create(Minimum, Maximum, Interval) );
145 }
146 
Set_Percentile(CSG_Grid * pGrid,double Interval,double Minimum,double Maximum)147 bool CSG_Scaler::Set_Percentile(CSG_Grid *pGrid, double Interval, double Minimum, double Maximum)
148 {
149 	Minimum	= pGrid->Get_Percentile(Minimum);
150 	Maximum	= pGrid->Get_Percentile(Maximum);
151 
152 	return( Create(Minimum, Maximum, Interval) );
153 }
154 
155 //-----------------------------------------------------
Set_Linear(CSG_Grids * pGrids,double Interval,double Minimum,double Maximum)156 bool CSG_Scaler::Set_Linear(CSG_Grids *pGrids, double Interval, double Minimum, double Maximum)
157 {
158 	Minimum	= pGrids->Get_Min() + pGrids->Get_Range() * Minimum / 100.;
159 	Maximum	= pGrids->Get_Min() + pGrids->Get_Range() * Maximum / 100.;
160 
161 	return( Create(Minimum, Maximum, Interval) );
162 }
163 
Set_StdDev(CSG_Grids * pGrids,double Interval,double StdDev,bool bKeepInRange)164 bool CSG_Scaler::Set_StdDev(CSG_Grids *pGrids, double Interval, double StdDev, bool bKeepInRange)
165 {
166 	double	Minimum	= pGrids->Get_Mean() - StdDev * pGrids->Get_StdDev(); if( bKeepInRange && Minimum < pGrids->Get_Min() ) Minimum = pGrids->Get_Min();
167 	double	Maximum	= pGrids->Get_Mean() + StdDev * pGrids->Get_StdDev(); if( bKeepInRange && Maximum > pGrids->Get_Max() ) Maximum = pGrids->Get_Max();
168 
169 	return( Create(Minimum, Maximum, Interval) );
170 }
171 
Set_Percentile(CSG_Grids * pGrids,double Interval,double Minimum,double Maximum)172 bool CSG_Scaler::Set_Percentile(CSG_Grids *pGrids, double Interval, double Minimum, double Maximum)
173 {
174 	Minimum	= pGrids->Get_Percentile(Minimum);
175 	Maximum	= pGrids->Get_Percentile(Maximum);
176 
177 	return( Create(Minimum, Maximum, Interval) );
178 }
179 
180 
181 ///////////////////////////////////////////////////////////
182 //														 //
183 //														 //
184 //														 //
185 ///////////////////////////////////////////////////////////
186 
187 //---------------------------------------------------------
CWKSP_Layer_Classify(void)188 CWKSP_Layer_Classify::CWKSP_Layer_Classify(void)
189 {
190 	m_Count			= 64;
191 
192 	m_Mode			= CLASSIFY_SINGLE;
193 	m_Shade_Mode	= SHADE_MODE_DSC_GREY;
194 
195 	m_pLayer		= NULL;
196 	m_pColors		= NULL;
197 	m_pLUT			= NULL;
198 }
199 
200 //---------------------------------------------------------
~CWKSP_Layer_Classify(void)201 CWKSP_Layer_Classify::~CWKSP_Layer_Classify(void)
202 {}
203 
204 
205 ///////////////////////////////////////////////////////////
206 //														 //
207 //														 //
208 //														 //
209 ///////////////////////////////////////////////////////////
210 
211 //---------------------------------------------------------
Initialise(CWKSP_Layer * pLayer,CSG_Table * pLUT,CSG_Colors * pColors)212 bool CWKSP_Layer_Classify::Initialise(CWKSP_Layer *pLayer, CSG_Table *pLUT, CSG_Colors *pColors)
213 {
214 	m_pLayer	= pLayer;
215 	m_pLUT		= pLUT;
216 	m_pColors	= pColors;
217 
218 	m_Count		=  m_pLayer->Get_Object()->Get_ObjectType() == SG_DATAOBJECT_TYPE_Grid
219 				|| m_pLayer->Get_Object()->Get_ObjectType() == SG_DATAOBJECT_TYPE_Grids
220 				|| m_pLayer->Get_Object()->Get_ObjectType() == SG_DATAOBJECT_TYPE_PointCloud ? 64 : 16;
221 
222 	//-----------------------------------------------------
223 	if( m_pLUT && m_pLUT->Get_Count() == 0 )
224 	{
225 		CSG_Table_Record	*pRecord;
226 
227 		pRecord	= m_pLUT->Add_Record();
228 		pRecord->Set_Value(LUT_COLOR		, SG_GET_RGB(1, 1, 1));
229 		pRecord->Set_Value(LUT_TITLE		, _TL("Class 1"));
230 		pRecord->Set_Value(LUT_DESCRIPTION	, _TL("First Class"));
231 		pRecord->Set_Value(LUT_MIN			, 0.0);
232 		pRecord->Set_Value(LUT_MAX			, 1.0);
233 
234 		pRecord	= m_pLUT->Add_Record();
235 		pRecord->Set_Value(LUT_COLOR		, SG_GET_RGB(255, 0, 0));
236 		pRecord->Set_Value(LUT_TITLE		, _TL("Class 2"));
237 		pRecord->Set_Value(LUT_DESCRIPTION	, _TL("Second Class"));
238 		pRecord->Set_Value(LUT_MIN			, 1.0);
239 		pRecord->Set_Value(LUT_MAX			, 2.0);
240 	}
241 
242 	if( m_pLUT )
243 	{
244 		m_pLUT->Set_Index(LUT_MIN, TABLE_INDEX_Ascending);
245 	}
246 
247 	return( true );
248 }
249 
250 
251 ///////////////////////////////////////////////////////////
252 //														 //
253 //														 //
254 //														 //
255 ///////////////////////////////////////////////////////////
256 
257 //---------------------------------------------------------
Get_Class_Value_Minimum(int iClass)258 double CWKSP_Layer_Classify::Get_Class_Value_Minimum(int iClass)
259 {
260 	switch( m_Mode )
261 	{
262 	case CLASSIFY_LUT:
263 		if( iClass >= 0 && iClass < m_pLUT->Get_Record_Count() )
264 		{
265 			return( m_pLUT->Get_Record(iClass)->asDouble(LUT_MIN) );
266 		}
267 		break;
268 
269 	case CLASSIFY_GRADUATED:
270 	case CLASSIFY_DISCRETE:
271 	case CLASSIFY_SHADE:
272 	case CLASSIFY_OVERLAY:
273 		if( m_zRange > 0.0 )
274 		{
275 			return( Get_RelativeToMetric(iClass / (double)Get_Class_Count()) );
276 		}
277 		break;
278 
279 	default: break;
280 	}
281 
282 	return( m_zMin );
283 }
284 
Get_Class_Value_Maximum(int iClass)285 double CWKSP_Layer_Classify::Get_Class_Value_Maximum(int iClass)
286 {
287 	switch( m_Mode )
288 	{
289 	case CLASSIFY_LUT:
290 		if( iClass >= 0 && iClass < m_pLUT->Get_Record_Count() )
291 		{
292 			return( m_pLUT->Get_Record(iClass)->asDouble(LUT_MAX) );
293 		}
294 		break;
295 
296 	case CLASSIFY_GRADUATED:
297 	case CLASSIFY_DISCRETE:
298 	case CLASSIFY_SHADE:
299 	case CLASSIFY_OVERLAY:
300 		if( m_zRange > 0.0 )
301 		{
302 			return( Get_RelativeToMetric((1.0 + iClass) / (double)Get_Class_Count()) );
303 		}
304 		break;
305 
306 	default: break;
307 	}
308 
309 	return( m_zMin + m_zRange );
310 }
311 
Get_Class_Value_Center(int iClass)312 double CWKSP_Layer_Classify::Get_Class_Value_Center(int iClass)
313 {
314 	switch( m_Mode )
315 	{
316 	case CLASSIFY_LUT:
317 		if( iClass >= 0 && iClass < m_pLUT->Get_Record_Count() )
318 		{
319 			return( 0.5 * (m_pLUT->Get_Record(iClass)->asDouble(LUT_MIN) + m_pLUT->Get_Record(iClass)->asDouble(LUT_MAX)) );
320 		}
321 		break;
322 
323 	case CLASSIFY_GRADUATED:
324 	case CLASSIFY_DISCRETE:
325 	case CLASSIFY_SHADE:
326 	case CLASSIFY_OVERLAY:
327 		if( m_zRange > 0.0 )
328 		{
329 			return( Get_RelativeToMetric((0.5 + iClass) / (double)Get_Class_Count()) );
330 		}
331 		break;
332 
333 	default: break;
334 	}
335 
336 	return( m_zMin + 0.5 * m_zRange );
337 }
338 
339 //---------------------------------------------------------
Get_Class_Name(int iClass)340 wxString CWKSP_Layer_Classify::Get_Class_Name(int iClass)
341 {
342 	CSG_String	s;
343 
344 	switch( m_Mode )
345 	{
346 	case CLASSIFY_LUT:
347 		if( iClass >= 0 && iClass < m_pLUT->Get_Record_Count() )
348 		{
349 			s.Printf(SG_T("%s"), m_pLUT->Get_Record(iClass)->asString(LUT_TITLE));
350 		}
351 		break;
352 
353 	case CLASSIFY_GRADUATED:
354 	case CLASSIFY_DISCRETE:
355 	case CLASSIFY_SHADE:
356 	case CLASSIFY_OVERLAY:
357 		s	= SG_Get_String(Get_Class_Value_Minimum(iClass), -2) + SG_T(" < ")
358 			+ SG_Get_String(Get_Class_Value_Maximum(iClass), -2);
359 		break;
360 
361 	default: break;
362 	}
363 
364 	return( s.c_str() );
365 }
366 
367 //---------------------------------------------------------
Get_Class_Name_byValue(double Value)368 wxString CWKSP_Layer_Classify::Get_Class_Name_byValue(double Value)
369 {
370 	return( Get_Class_Name(Get_Class(Value)) );
371 }
372 
Get_Class_Name_byValue(const wxString & Value)373 wxString CWKSP_Layer_Classify::Get_Class_Name_byValue(const wxString &Value)
374 {
375 	return( SG_Data_Type_is_Numeric(m_pLUT->Get_Field_Type(LUT_MIN))
376 		? Get_Class_Name(Get_Class(CSG_String(&Value).asDouble()))
377 		: Get_Class_Name(Get_Class(CSG_String(&Value)))
378 	);
379 }
380 
381 
382 ///////////////////////////////////////////////////////////
383 //														 //
384 //						Unique							 //
385 //														 //
386 ///////////////////////////////////////////////////////////
387 
388 //---------------------------------------------------------
Set_Unique_Color(int Color)389 void CWKSP_Layer_Classify::Set_Unique_Color(int Color)
390 {
391 	m_UNI_Color	= Color;
392 }
393 
394 
395 ///////////////////////////////////////////////////////////
396 //														 //
397 //						Metric							 //
398 //														 //
399 ///////////////////////////////////////////////////////////
400 
401 //---------------------------------------------------------
Set_Class_Count(int Count)402 bool CWKSP_Layer_Classify::Set_Class_Count(int Count)
403 {
404 	if( Count > 0 && Count != m_Count )
405 	{
406 		m_Count	= Count;
407 
408 		return( Histogram_Update() );
409 	}
410 
411 	return( false );
412 }
413 
414 //---------------------------------------------------------
Set_Metric(int Mode,double LogFactor,double zMin,double zMax)415 void CWKSP_Layer_Classify::Set_Metric(int Mode, double LogFactor, double zMin, double zMax)
416 {
417 	m_zMode		= Mode;
418 	m_zMin		= zMin < zMax ? zMin : zMax;
419 	m_zRange	= zMin < zMax ? (zMax - zMin) : (zMin - zMax);
420 	m_zLogRange	= LogFactor;
421 	m_zLogMax	= log(1.0 + m_zLogRange);
422 
423 	if( m_zRange <= 0.0 || (m_zMode != 0 && m_zLogRange <= 0.0) )
424 	{
425 		m_zRange	= 0.0;
426 	}
427 }
428 
429 
430 ///////////////////////////////////////////////////////////
431 //														 //
432 //						Lookup Table					 //
433 //														 //
434 ///////////////////////////////////////////////////////////
435 
436 //---------------------------------------------------------
_LUT_Cmp_Class(double Value,int iClass)437 inline int CWKSP_Layer_Classify::_LUT_Cmp_Class(double Value, int iClass)
438 {
439 	CSG_Table_Record	*pClass	= m_pLUT->Get_Record_byIndex(iClass);
440 
441 	double	min	= pClass->asDouble(LUT_MIN);
442 
443 	if( Value == min )	{	return(  0 );	}
444 	if( Value  < min )	{	return(  1 );	}
445 
446 	double	max	= pClass->asDouble(LUT_MAX);
447 
448 	if( max    < min )	{	return( -1 );	}
449 	if( Value  < max )	{	return(  0 );	}
450 
451 	return( iClass == m_pLUT->Get_Count() - 1 && Value == max ? 0 : -1 );
452 }
453 
454 //---------------------------------------------------------
_LUT_Get_Class(double Value)455 int CWKSP_Layer_Classify::_LUT_Get_Class(double Value)
456 {
457 	int		a, b, i, c;
458 
459 	if( m_pLUT->Get_Record_Count() > 0 )
460 	{
461 		if( m_pLUT->Get_Index_Field(0) != LUT_MIN || m_pLUT->Get_Index_Order(0) != TABLE_INDEX_Ascending )
462 		{
463 			m_pLUT->Set_Index(LUT_MIN, TABLE_INDEX_Ascending);
464 		}
465 
466 		for(a=0, b=m_pLUT->Get_Record_Count()-1; a < b; )
467 		{
468 			i	= a + (b - a) / 2;
469 			c	= _LUT_Cmp_Class(Value, i);
470 
471 			if( c > 0 )
472 			{
473 				b	= b > i ? i : b - 1;
474 			}
475 			else if( c < 0 )
476 			{
477 				a	= a < i ? i : a + 1;
478 			}
479 			else
480 			{
481 				return( m_pLUT->Get_Record_byIndex(i)->Get_Index() );
482 			}
483 		}
484 
485 		if( _LUT_Cmp_Class(Value, a) == 0 )
486 		{
487 			return( m_pLUT->Get_Record_byIndex(a)->Get_Index() );
488 		}
489 
490 		if( a != b && _LUT_Cmp_Class(Value, b) == 0 )
491 		{
492 			return( m_pLUT->Get_Record_byIndex(b)->Get_Index() );
493 		}
494 	}
495 
496 	return( -1 );
497 }
498 
499 //---------------------------------------------------------
_LUT_Cmp_Class(const CSG_String & Value,int iClass)500 inline int CWKSP_Layer_Classify::_LUT_Cmp_Class(const CSG_String &Value, int iClass)
501 {
502 	CSG_Table_Record	*pClass	= m_pLUT->Get_Record_byIndex(iClass);
503 
504 	int		c	= Value.Cmp(pClass->asString(LUT_MIN));
505 
506 	if( c < 0 )
507 	{
508 		return( 1 );
509 	}
510 
511 	if( c > 0 && Value.Cmp(pClass->asString(LUT_MAX)) > 0 )
512 	{
513 		return( -1 );
514 	}
515 
516 	return( 0 );
517 }
518 
519 //---------------------------------------------------------
_LUT_Get_Class(const CSG_String & Value)520 int CWKSP_Layer_Classify::_LUT_Get_Class(const CSG_String &Value)
521 {
522 	int		a, b, i, c;
523 
524 	if( m_pLUT->Get_Record_Count() > 0 )
525 	{
526 		if( m_pLUT->Get_Index_Field(0) != LUT_MIN || m_pLUT->Get_Index_Order(0) != TABLE_INDEX_Ascending )
527 		{
528 			m_pLUT->Set_Index(LUT_MIN, TABLE_INDEX_Ascending);
529 		}
530 
531 		for(a=0, b=m_pLUT->Get_Record_Count()-1; a < b; )
532 		{
533 			i	= a + (b - a) / 2;
534 			c	= _LUT_Cmp_Class(Value, i);
535 
536 			if( c > 0 )
537 			{
538 				b	= b > i ? i : b - 1;
539 			}
540 			else if( c < 0 )
541 			{
542 				a	= a < i ? i : a + 1;
543 			}
544 			else
545 			{
546 				return( m_pLUT->Get_Record_byIndex(i)->Get_Index() );
547 			}
548 		}
549 
550 		if( _LUT_Cmp_Class(Value, a) == 0 )
551 		{
552 			return( m_pLUT->Get_Record_byIndex(a)->Get_Index() );
553 		}
554 
555 		if( a != b && _LUT_Cmp_Class(Value, b) == 0 )
556 		{
557 			return( m_pLUT->Get_Record_byIndex(b)->Get_Index() );
558 		}
559 	}
560 
561 	return( -1 );
562 }
563 
564 
565 ///////////////////////////////////////////////////////////
566 //														 //
567 //														 //
568 //														 //
569 ///////////////////////////////////////////////////////////
570 
571 //---------------------------------------------------------
Metric2EqualElements(void)572 void CWKSP_Layer_Classify::Metric2EqualElements(void)
573 {
574 	if( m_pLayer->Get_Type() == WKSP_ITEM_Grid && m_pColors->Get_Count() > 1 )
575 	{
576 		m_pLUT->Del_Records();
577 
578 		CSG_Grid	*pGrid	= ((CWKSP_Grid *)m_pLayer)->Get_Grid();
579 
580 		double	zA, zB, dClass	= (double)pGrid->Get_NCells() / (double)(m_pColors->Get_Count());
581 
582 		if( !pGrid->Set_Index() )
583 		{
584 			return;
585 		}
586 
587 		int		x, y;
588 
589 		pGrid->Get_Sorted(0, x, y, false, false);
590 		zA		= pGrid->asDouble(x, y);
591 
592 		for(int iClass=0; iClass<m_pColors->Get_Count()-1; iClass++)
593 		{
594 			pGrid->Get_Sorted((sLong)(dClass * (iClass + 1.0)), x, y, false, false);
595 			zB		= zA;
596 			zA		= pGrid->asDouble(x, y);
597 
598 			CSG_Table_Record	*pClass	= m_pLUT->Add_Record();
599 			pClass->Set_Value(LUT_COLOR      , m_pColors->Get_Color(iClass));
600 			pClass->Set_Value(LUT_TITLE      , CSG_String::Format(">=%f"     , zB    ));
601 			pClass->Set_Value(LUT_DESCRIPTION, CSG_String::Format("%f <-> %f", zB, zA));
602 			pClass->Set_Value(LUT_MIN        , zB);
603 			pClass->Set_Value(LUT_MAX        , zA);
604 		}
605 
606 		pGrid->Get_Sorted(pGrid->Get_NCells() - 1, x, y, false, false);
607 		zB		= zA;
608 		zA		= pGrid->asDouble(x, y);
609 
610 		CSG_Table_Record	*pClass	= m_pLUT->Add_Record();
611 		pClass->Set_Value(LUT_COLOR      , m_pColors->Get_Color(m_pColors->Get_Count() - 1));
612 		pClass->Set_Value(LUT_TITLE      , CSG_String::Format(">=%f"     , zB    ));
613 		pClass->Set_Value(LUT_DESCRIPTION, CSG_String::Format("%f <-> %f", zB, zA));
614 		pClass->Set_Value(LUT_MIN        , zB);
615 		pClass->Set_Value(LUT_MAX        , zA);
616 
617 		Set_Mode(CLASSIFY_LUT);
618 		m_pLayer->Update_Views();
619 	}
620 }
621 
622 
623 ///////////////////////////////////////////////////////////
624 //														 //
625 //						Histogram						 //
626 //														 //
627 ///////////////////////////////////////////////////////////
628 
629 //---------------------------------------------------------
Histogram_Update(void)630 bool CWKSP_Layer_Classify::Histogram_Update(void)
631 {
632 	m_Statistics.Create();
633 
634 	if( Get_Class_Count() < 1 )
635 	{
636 		m_Histogram.Destroy();
637 
638 		return( false );
639 	}
640 
641 	//-----------------------------------------------------
642 	STATUSBAR_Set_Text(_TL("Build Histogram..."));
643 
644 	m_Histogram.Create(Get_Class_Count(), 0, Get_Class_Count() - 1);
645 
646 	switch( m_pLayer->Get_Type() )
647 	{
648 	case WKSP_ITEM_Grid:
649 		_Histogram_Update(((CWKSP_Grid  *)m_pLayer)->Get_Grid ());
650 		break;
651 
652 	case WKSP_ITEM_Grids:
653 		if( m_Mode == CLASSIFY_OVERLAY )
654 		{
655 			_Histogram_Update(((CWKSP_Grids *)m_pLayer)->Get_Grids());
656 		}
657 		else
658 		{
659 			_Histogram_Update(((CWKSP_Grids *)m_pLayer)->Get_Grid ());
660 		}
661 		break;
662 
663 	case WKSP_ITEM_Shapes:
664 		_Histogram_Update(((CWKSP_Shapes *)m_pLayer)->Get_Shapes(),
665 			((CWKSP_Shapes *)m_pLayer)->Get_Field_Value (),
666 			((CWKSP_Shapes *)m_pLayer)->Get_Field_Normal(),
667 			((CWKSP_Shapes *)m_pLayer)->Get_Scale_Normal()
668 		);
669 		break;
670 
671 	case WKSP_ITEM_PointCloud:
672 		_Histogram_Update(((CWKSP_PointCloud *)m_pLayer)->Get_PointCloud(),
673 			((CWKSP_PointCloud *)m_pLayer)->Get_Field_Value()
674 		);
675 		break;
676 
677 	default: break;
678 	}
679 
680 	m_Histogram.Update();
681 
682 	PROCESS_Set_Okay();
683 
684 	//-----------------------------------------------------
685 	return( true );
686 }
687 
688 //---------------------------------------------------------
_Histogram_Update(CSG_Grid * pGrid)689 bool CWKSP_Layer_Classify::_Histogram_Update(CSG_Grid *pGrid)
690 {
691 	if( pGrid->Get_Max_Samples() > 0 && pGrid->Get_Max_Samples() < pGrid->Get_NCells() )
692 	{
693 		double	d	= (double)pGrid->Get_NCells() / (double)pGrid->Get_Max_Samples();
694 
695 		for(double i=0; i<(double)pGrid->Get_NCells() && PROGRESSBAR_Set_Position(i, (double)pGrid->Get_NCells()); i+=d)
696 		{
697 			if( !pGrid->is_NoData((sLong)i) )
698 			{
699 				m_Histogram	+= Get_Class(pGrid->asDouble((sLong)i));
700 			}
701 		}
702 
703 		if( m_Histogram.Update() && m_Histogram.Get_Element_Count() < pGrid->Get_Max_Samples() )	// any no-data cells ?
704 		{
705 			d	*= (double)m_Histogram.Get_Element_Count() / (double)pGrid->Get_Max_Samples();
706 		}
707 
708 		m_Histogram.Scale_Element_Count(d);
709 
710 		m_Statistics	= pGrid->Get_Statistics();
711 
712 		return( true );
713 	}
714 
715 	for(sLong i=0; i<pGrid->Get_NCells() && PROGRESSBAR_Set_Position((double)i, (double)pGrid->Get_NCells()); i++)
716 	{
717 		if( !pGrid->is_NoData(i) )
718 		{
719 			m_Histogram	+= Get_Class(pGrid->asDouble(i));
720 		}
721 	}
722 
723 	m_Statistics	= pGrid->Get_Statistics();
724 
725 	return( true );
726 }
727 
728 //---------------------------------------------------------
_Histogram_Update(CSG_Grids * pGrids)729 bool CWKSP_Layer_Classify::_Histogram_Update(CSG_Grids *pGrids)
730 {
731 	if( pGrids->Get_Max_Samples() > 0 && pGrids->Get_Max_Samples() < pGrids->Get_NCells() )
732 	{
733 		double	d	= (double)pGrids->Get_NCells() / (double)pGrids->Get_Max_Samples();
734 
735 		for(double i=0; i<(double)pGrids->Get_NCells() && PROGRESSBAR_Set_Position(i, (double)pGrids->Get_NCells()); i+=d)
736 		{
737 			if( !pGrids->is_NoData((sLong)i) )
738 			{
739 				m_Histogram	+= Get_Class(pGrids->asDouble((sLong)i));
740 			}
741 		}
742 
743 		if( m_Histogram.Update() && m_Histogram.Get_Element_Count() < pGrids->Get_Max_Samples() )	// any no-data cells ?
744 		{
745 			d	*= (double)m_Histogram.Get_Element_Count() / (double)pGrids->Get_Max_Samples();
746 		}
747 
748 		m_Histogram.Scale_Element_Count(d);
749 
750 		m_Statistics	= pGrids->Get_Statistics();
751 
752 		return( true );
753 	}
754 
755 	for(sLong i=0; i<pGrids->Get_NCells() && PROGRESSBAR_Set_Position((double)i, (double)pGrids->Get_NCells()); i++)
756 	{
757 		if( !pGrids->is_NoData(i) )
758 		{
759 			m_Histogram	+= Get_Class(pGrids->asDouble(i));
760 		}
761 	}
762 
763 	m_Statistics	= pGrids->Get_Statistics();
764 
765 	return( true );
766 }
767 
768 //---------------------------------------------------------
_Histogram_Update(CSG_Shapes * pShapes,int Attribute,int Normalize,double Scale)769 bool CWKSP_Layer_Classify::_Histogram_Update(CSG_Shapes *pShapes, int Attribute, int Normalize, double Scale)
770 {
771 	if( Attribute < 0 || Attribute >= pShapes->Get_Field_Count() )
772 	{
773 		return( false );
774 	}
775 
776 	if( pShapes->Get_Max_Samples() > 0 && pShapes->Get_Max_Samples() < pShapes->Get_Count() )
777 	{
778 		double	d	= (double)pShapes->Get_Count() / (double)pShapes->Get_Max_Samples();
779 
780 		for(double i=0; i<(double)pShapes->Get_Count() && PROGRESSBAR_Set_Position(i, (double)pShapes->Get_Count()); i+=d)
781 		{
782 			CSG_Shape	*pShape	= pShapes->Get_Shape((int)i);
783 
784 			if( m_Mode == CLASSIFY_LUT )
785 			{
786 				m_Histogram	+= SG_Data_Type_is_Numeric(m_pLUT->Get_Field_Type(LUT_MIN))
787 					? Get_Class(pShape->asDouble(Attribute))
788 					: Get_Class(pShape->asString(Attribute));
789 			}
790 			else if( !pShape->is_NoData(Attribute) )
791 			{
792 				double z = pShape->asDouble(Attribute);
793 
794 				if( Normalize < 0 )
795 				{
796 					m_Histogram += Get_Class(z); m_Statistics += z;
797 				}
798 				else if( !pShape->is_NoData(Normalize) && pShape->asDouble(Normalize) )
799 				{
800 					z *= Scale / pShape->asDouble(Normalize);
801 
802 					m_Histogram += Get_Class(z); m_Statistics += z;
803 				}
804 			}
805 		}
806 
807 		if( m_Histogram.Update() && m_Histogram.Get_Element_Count() < pShapes->Get_Max_Samples() )	// any no-data cells ?
808 		{
809 			d	*= (double)m_Histogram.Get_Element_Count() / (double)pShapes->Get_Max_Samples();
810 		}
811 
812 		m_Histogram.Scale_Element_Count(d);
813 
814 		return( true );
815 	}
816 
817 	for(int i=0; i<pShapes->Get_Count() && PROGRESSBAR_Set_Position(i, pShapes->Get_Count()); i++)
818 	{
819 		CSG_Shape	*pShape	= pShapes->Get_Shape(i);
820 
821 		if( m_Mode == CLASSIFY_LUT )
822 		{
823 			m_Histogram	+= SG_Data_Type_is_Numeric(m_pLUT->Get_Field_Type(LUT_MIN))
824 				? Get_Class(pShape->asDouble(Attribute))
825 				: Get_Class(pShape->asString(Attribute));
826 		}
827 		else if( !pShape->is_NoData(Attribute) )
828 		{
829 			double z = pShape->asDouble(Attribute);
830 
831 			if( Normalize < 0 )
832 			{
833 				m_Histogram += Get_Class(z); m_Statistics += z;
834 			}
835 			else if( !pShape->is_NoData(Normalize) && pShape->asDouble(Normalize) )
836 			{
837 				z *= Scale / pShape->asDouble(Normalize);
838 
839 				m_Histogram += Get_Class(z); m_Statistics += z;
840 			}
841 		}
842 	}
843 
844 	return( true );
845 }
846 
847 
848 ///////////////////////////////////////////////////////////
849 //														 //
850 //														 //
851 //														 //
852 ///////////////////////////////////////////////////////////
853 
854 //---------------------------------------------------------
855