SAGA API Version 9.14
Loading...
Searching...
No Matches
map_symbology.cpp
Go to the documentation of this file.
1
3// //
4// SAGA //
5// //
6// System for Automated Geoscientific Analyses //
7// //
8// Application Programming Interface //
9// //
10// Library: SAGA_API //
11// //
12//-------------------------------------------------------//
13// //
14// map_symbology.cpp //
15// //
16// Copyright (C) 2026 by //
17// Olaf Conrad //
18// //
19//-------------------------------------------------------//
20// //
21// This file is part of 'SAGA - System for Automated //
22// Geoscientific Analyses'. SAGA is free software; you //
23// can redistribute it and/or modify it under the terms //
24// of the GNU General Public License as published by the //
25// Free Software Foundation, either version 2 of the //
26// License, or (at your option) any later version. //
27// //
28// SAGA is distributed in the hope that it will be //
29// useful, but WITHOUT ANY WARRANTY; without even the //
30// implied warranty of MERCHANTABILITY or FITNESS FOR A //
31// PARTICULAR PURPOSE. See the GNU General Public //
32// License for more details. //
33// //
34// You should have received a copy of the GNU General //
35// Public License along with this program; if not, see //
36// <http://www.gnu.org/licenses/>. //
37// //
38//-------------------------------------------------------//
39// //
40// e-mail: oconrad@saga-gis.org //
41// //
42// contact: Olaf Conrad //
43// Institute of Geography //
44// University of Hamburg //
45// Germany //
46// //
48
49//---------------------------------------------------------
50#include "map_symbology.h"
51
52#include "map_layer.h"
53
54
56// //
57// //
58// //
60
61//---------------------------------------------------------
76
77//---------------------------------------------------------
80
81
83// //
85
86//---------------------------------------------------------
88{
89 m_pLUT = &m_pLayer->Get_LUT(); m_pColors = &m_pLayer->Get_Colors();
90
91 if( m_pLUT )
92 {
94 }
95
96 if( m_pLayer->Get_Object() )
97 {
98 switch( m_pLayer->Get_ObjectType() )
99 {
101 m_Stretch.Set_Histogram(m_pLayer->Get_Object()->asGrid());
102 break;
103
106 {
107 m_Stretch.Set_Histogram(m_pLayer->Get_Object()->asGrids());
108 }
109 else
110 {
111 m_Stretch.Set_Histogram(m_pLayer->Get_Object()->asGrid ());
112 }
113 break;
114
115 #define HISTOGRAM_UPDATE(pLayer) m_Stretch.Set_Histogram((pLayer)->Get_Object()->asTable(true), (pLayer)->Get_Field_Value(), (pLayer)->Get_Field_Normal(), (pLayer)->Get_Scale_Normal())
116
120
121 #undef HISTOGRAM_UPDATE
122
123 default: break;
124 }
125 }
126
127 return( true );
128}
129
130
132// //
134
135//---------------------------------------------------------
137{
138 switch( m_Mode )
139 {
141 if( iClass >= 0 && iClass < m_pLUT->Get_Count() )
142 {
143 return( m_pLUT->Get_Record(iClass)->asDouble(CSG_Map_Symbology::LUT_MIN) );
144 }
145 break;
146
150 if( m_Stretch.Get_Range() > 0. )
151 {
152 return( m_Stretch.from_Relative(iClass / (double)Get_Class_Count()) );
153 }
154 break;
155
156 default: break;
157 }
158
159 return( m_Stretch.Get_Minimum() );
160}
161
163{
164 switch( m_Mode )
165 {
167 if( iClass >= 0 && iClass < m_pLUT->Get_Count() )
168 {
169 return( m_pLUT->Get_Record(iClass)->asDouble(CSG_Map_Symbology::LUT_MAX) );
170 }
171 break;
172
176 if( m_Stretch.Get_Range() > 0. )
177 {
178 return( m_Stretch.from_Relative((1. + iClass) / (double)Get_Class_Count()) );
179 }
180 break;
181
182 default: break;
183 }
184
185 return( m_Stretch.Get_Maximum() );
186}
187
189{
190 switch( m_Mode )
191 {
193 if( iClass >= 0 && iClass < m_pLUT->Get_Count() )
194 {
195 return( 0.5 * (m_pLUT->Get_Record(iClass)->asDouble(CSG_Map_Symbology::LUT_MIN) + m_pLUT->Get_Record(iClass)->asDouble(CSG_Map_Symbology::LUT_MAX)) );
196 }
197 break;
198
202 if( m_Stretch.Get_Range() > 0. )
203 {
204 return( m_Stretch.from_Relative((0.5 + iClass) / (double)Get_Class_Count()) );
205 }
206 break;
207
208 default: break;
209 }
210
211 return( m_Stretch.Get_Minimum() + 0.5 * m_Stretch.Get_Range() );
212}
213
214//---------------------------------------------------------
216{
217 CSG_String s;
218
219 switch( m_Mode )
220 {
222 if( iClass >= 0 && iClass < m_pLUT->Get_Count() )
223 {
224 s.Printf(SG_T("%s"), m_pLUT->Get_Record(iClass)->asString(CSG_Map_Symbology::LUT_TITLE));
225 }
226 break;
227
231 s = SG_Get_String(Get_Class_Value_Minimum(iClass), -2) + SG_T(" < ")
233 break;
234
235 default: break;
236 }
237
238 return( s.c_str() );
239}
240
241//---------------------------------------------------------
243{
244 return( Get_Class_Name(Get_Class(Value)) );
245}
246
247wxString CSG_Map_Symbology::Get_Class_Name_byValue(const wxString &Value)
248{
252 );
253}
254
255
257// //
259
260//---------------------------------------------------------
262{
263 m_Mode = Mode;
264
265 return( true );
266}
267
268//---------------------------------------------------------
270{
271 m_NoData_Color = Color;
272
273 return( true );
274}
275
276//---------------------------------------------------------
278{
279 m_Single_Color = Color;
280
281 return( true );
282}
283
284
286// //
288
289//---------------------------------------------------------
291{
292 if( Count > 0 && Count != m_Count )
293 {
294 m_Count = Count;
295
296 return( Histogram_Update() );
297 }
298
299 return( false );
300}
301
302//---------------------------------------------------------
304{
305 CSG_Colors Colors(Get_Class_Count());
306
307 for(int i=0; i<Get_Class_Count(); i++)
308 {
309 Colors[i] = Get_Class_Color(i);
310 }
311
312 return( Colors );
313}
314
315
317// //
319
320//---------------------------------------------------------
321inline int CSG_Map_Symbology::_LUT_Cmp_Class(double Value, int iClass) const
322{
323 CSG_Table_Record *pClass = m_pLUT->Get_Record_byIndex(iClass);
324
325 double min = pClass->asDouble(CSG_Map_Symbology::LUT_MIN);
326
327 if( Value == min ) { return( 0 ); }
328 if( Value < min ) { return( 1 ); }
329
330 double max = pClass->asDouble(CSG_Map_Symbology::LUT_MAX);
331
332 if( max < min ) { return( -1 ); }
333 if( Value < max ) { return( 0 ); }
334
335 return( iClass == m_pLUT->Get_Count() - 1 && Value == max ? 0 : -1 );
336}
337
338//---------------------------------------------------------
340{
341 if( m_pLUT->Get_Count() > 0 )
342 {
343 if( m_pLUT->Get_Index_Field(0) != CSG_Map_Symbology::LUT_MIN || m_pLUT->Get_Index_Order(0) != TABLE_INDEX_Ascending )
344 {
346 }
347
348 int a = 0, b = m_pLUT->Get_Count() - 1;
349
350 while( a < b )
351 {
352 int i = a + (b - a) / 2; int c = _LUT_Cmp_Class(Value, i);
353
354 if( c > 0 )
355 {
356 b = b > i ? i : b - 1;
357 }
358 else if( c < 0 )
359 {
360 a = a < i ? i : a + 1;
361 }
362 else
363 {
364 return( m_pLUT->Get_Record_byIndex(i)->Get_Index() );
365 }
366 }
367
368 if( a != b && _LUT_Cmp_Class(Value, a) == 0 )
369 {
370 return( m_pLUT->Get_Record_byIndex(a)->Get_Index() );
371 }
372
373 if( _LUT_Cmp_Class(Value, b) == 0 )
374 {
375 return( m_pLUT->Get_Record_byIndex(b)->Get_Index() );
376 }
377 }
378
379 return( -1 );
380}
381
382//---------------------------------------------------------
383inline int CSG_Map_Symbology::_LUT_Cmp_Class(const CSG_String &Value, int iClass) const
384{
385 CSG_Table_Record *pClass = m_pLUT->Get_Record_byIndex(iClass);
386
387 int c = Value.Cmp(pClass->asString(CSG_Map_Symbology::LUT_MIN));
388
389 if( c < 0 )
390 {
391 return( 1 );
392 }
393
394 if( c > 0 && Value.Cmp(pClass->asString(CSG_Map_Symbology::LUT_MAX)) > 0 )
395 {
396 return( -1 );
397 }
398
399 return( 0 );
400}
401
402//---------------------------------------------------------
404{
405 if( m_pLUT->Get_Count() > 0 )
406 {
407 if( m_pLUT->Get_Index_Field(0) != CSG_Map_Symbology::LUT_MIN || m_pLUT->Get_Index_Order(0) != TABLE_INDEX_Ascending )
408 {
410 }
411
412 int a = 0, b = m_pLUT->Get_Count() - 1;
413
414 while( a < b )
415 {
416 int i = a + (b - a) / 2; int c = _LUT_Cmp_Class(Value, i);
417
418 if( c > 0 )
419 {
420 b = b > i ? i : b - 1;
421 }
422 else if( c < 0 )
423 {
424 a = a < i ? i : a + 1;
425 }
426 else
427 {
428 return( m_pLUT->Get_Record_byIndex(i)->Get_Index() );
429 }
430 }
431
432 if( a != b && _LUT_Cmp_Class(Value, a) == 0 )
433 {
434 return( m_pLUT->Get_Record_byIndex(a)->Get_Index() );
435 }
436
437 if( _LUT_Cmp_Class(Value, b) == 0 )
438 {
439 return( m_pLUT->Get_Record_byIndex(b)->Get_Index() );
440 }
441 }
442
443 return( -1 );
444}
445
446
448// //
450
451//---------------------------------------------------------
453{
454 m_Statistics.Create();
455
456 if( Get_Class_Count() < 1 )
457 {
458 m_Histogram.Destroy();
459
460 return( false );
461 }
462
463 //-----------------------------------------------------
464 SG_UI_Process_Set_Text(_TL("Build Histogram..."));
465
466 m_Histogram.Create(Get_Class_Count(), 0., Get_Class_Count() - 1.);
467
468 switch( m_pLayer->Get_Object()->Get_ObjectType() )
469 {
471 _Histogram_Update(m_pLayer->Get_Object()->asGrid());
472 break;
473
476 {
477 _Histogram_Update(m_pLayer->Get_Object()->asGrids());
478 }
479 else
480 {
481 _Histogram_Update(m_pLayer->Get_Object()->asGrid ());
482 }
483 break;
484
485 #define HISTOGRAM_UPDATE(pLayer) _Histogram_Update((pLayer)->Get_Object()->asTable(true), (pLayer)->Get_Field_Value (), (pLayer)->Get_Field_Normal(), (pLayer)->Get_Scale_Normal())
486
490
491 #undef HISTOGRAM_UPDATE
492
493 default: break;
494 }
495
496 m_Histogram.Update();
497
499
500 //-----------------------------------------------------
501 return( true );
502}
503
504//---------------------------------------------------------
506{
507 #define isNoData(i) (pObject->asGrid() ? pObject->asGrid()->is_NoData((sLong)i) : pObject->asGrids()->is_NoData((sLong)i))
508 #define asDouble(i) (pObject->asGrid() ? pObject->asGrid()-> asDouble((sLong)i) : pObject->asGrids()-> asDouble((sLong)i))
509
510 sLong nCells = pObject->asGrid() ? pObject->asGrid()->Get_NCells() : pObject->asGrids()->Get_NCells();
511
512 if( pObject->Get_Max_Samples() > 0 && pObject->Get_Max_Samples() < nCells )
513 {
514 double d = (double)nCells / (double)pObject->Get_Max_Samples();
515
516 for(double i=0; i<(double)nCells && SG_UI_Process_Set_Progress(i, (double)nCells); i+=d)
517 {
518 if( !isNoData(i) )
519 {
521 }
522 }
523
524 if( m_Histogram.Update() && m_Histogram.Get_Element_Count() < (size_t)pObject->Get_Max_Samples() ) // any no-data cells ?
525 {
526 d *= (double)m_Histogram.Get_Element_Count() / (double)pObject->Get_Max_Samples();
527 }
528
529 m_Histogram.Scale_Element_Count(d);
530
531 m_Statistics = pObject->asGrid() ? pObject->asGrid()->Get_Statistics() : pObject->asGrids()->Get_Statistics();
532
533 return( true );
534 }
535
536 for(sLong i=0; i<nCells && SG_UI_Process_Set_Progress((double)i, (double)nCells); i++)
537 {
538 if( !isNoData(i) )
539 {
541 }
542 }
543
544 m_Statistics = pObject->asGrid() ? pObject->asGrid()->Get_Statistics() : pObject->asGrids()->Get_Statistics();
545
546 #undef isNoData
547 #undef asDouble
548
549 return( true );
550}
551
552//---------------------------------------------------------
553bool CSG_Map_Symbology::_Histogram_Update(CSG_Table *pTable, int Field, int Normalize, double Scale)
554{
555 if( !pTable || Field < 0 || Field >= pTable->Get_Field_Count() )
556 {
557 return( false );
558 }
559
560 //-----------------------------------------------------
561 if( pTable->Get_Max_Samples() > 0 && pTable->Get_Max_Samples() < pTable->Get_Count() )
562 {
563 double d = (double)pTable->Get_Count() / (double)pTable->Get_Max_Samples();
564
566 {
567 CSG_String Value;
568
569 for(double i=0; i<(double)pTable->Get_Count() && SG_UI_Process_Set_Progress(i, (double)pTable->Get_Count()); i+=d)
570 {
571 if( pTable->Get_Value((sLong)i, Field, Value) )
572 {
573 m_Histogram += Get_Class(Value);
574 }
575 }
576 }
577 else
578 {
579 double Value, Dividend;
580
581 for(double i=0; i<(double)pTable->Get_Count() && SG_UI_Process_Set_Progress(i, (double)pTable->Get_Count()); i+=d)
582 {
583 if( pTable->Get_Value((sLong)i, Field, Value) )
584 {
585 if( Normalize < 0 )
586 {
587 m_Histogram += Get_Class(Value); m_Statistics += Value;
588 }
589 else if( pTable->Get_Value((sLong)i, Normalize, Dividend) && Dividend != 0. )
590 {
591 Value *= Scale / Dividend;
592
593 m_Histogram += Get_Class(Value); m_Statistics += Value;
594 }
595 }
596 }
597 }
598
599 if( m_Histogram.Update() && m_Histogram.Get_Element_Count() < (size_t)pTable->Get_Max_Samples() ) // any no-data cells ?
600 {
601 d *= (double)m_Histogram.Get_Element_Count() / (double)pTable->Get_Max_Samples();
602 }
603
604 m_Histogram.Scale_Element_Count(d);
605
606 return( true );
607 }
608
609 //-----------------------------------------------------
611 {
612 CSG_String Value;
613
614 for(sLong i=0; i<pTable->Get_Count() && SG_UI_Process_Set_Progress(i, pTable->Get_Count()); i++)
615 {
616 if( pTable->Get_Value((sLong)i, Field, Value) )
617 {
618 m_Histogram += Get_Class(Value);
619 }
620 }
621 }
622 else
623 {
624 double Value, Dividend;
625
626 for(sLong i=0; i<pTable->Get_Count() && SG_UI_Process_Set_Progress(i, pTable->Get_Count()); i++)
627 {
628 if( pTable->Get_Value((sLong)i, Field, Value) )
629 {
630 if( Normalize < 0 )
631 {
632 m_Histogram += Get_Class(Value); m_Statistics += Value;
633 }
634 else if( pTable->Get_Value((sLong)i, Normalize, Dividend) && Dividend != 0. )
635 {
636 Value *= Scale / Dividend;
637
638 m_Histogram += Get_Class(Value); m_Statistics += Value;
639 }
640 }
641 }
642 }
643
644 return( true );
645}
646
647
649// //
650// //
651// //
653
654//---------------------------------------------------------
void SG_UI_Process_Set_Text(const CSG_String &Text)
bool SG_UI_Process_Set_Ready(void)
bool SG_UI_Process_Set_Progress(int Position, int Range)
long SG_Color_Get_Random(void)
bool SG_Data_Type_is_Numeric(TSG_Data_Type Type)
Definition api_core.cpp:199
#define SG_COLOR_GREY_LIGHT
Definition api_core.h:1356
signed long long sLong
Definition api_core.h:158
#define SG_T(s)
Definition api_core.h:537
#define _TL(s)
Definition api_core.h:1619
SAGA_API_DLL_EXPORT CSG_String SG_Get_String(double Value, int Precision=-99)
sLong Get_Max_Samples(void) const
Definition dataobject.h:266
class CSG_Grids * asGrids(bool bPolymorph=false) const
class CSG_Grid * asGrid(bool bPolymorph=false) const
const CSG_Simple_Statistics & Get_Statistics(void)
Definition grid.cpp:1099
sLong Get_NCells(void) const
Definition grid.h:565
const CSG_Simple_Statistics & Get_Statistics(void)
Definition grids.cpp:1544
sLong Get_NCells(void) const
Definition grids.h:191
CSG_Colors * m_pColors
int Get_Class(double Value)
bool _Histogram_Update(CSG_Data_Object *pObject)
int _LUT_Cmp_Class(double Value, int Class) const
CSG_Simple_Statistics m_Statistics
CSG_Map_Symbology(class CSG_Map_Layer *pLayer)
bool Histogram_Update(void)
int _LUT_Get_Class(double Value) const
CSG_Histogram m_Histogram
CSG_Colors Get_Class_Colors(void) const
bool Set_Mode(int Mode)
bool Set_Class_Count(int Count)
double Get_Class_Value_Center(int Class)
int Get_Class_Count(void) const
bool Get_Class_Color(int Class, int &Color) const
virtual ~CSG_Map_Symbology(void)
double Get_Class_Value_Minimum(int Class)
class CSG_Map_Layer * m_pLayer
bool Set_Single_Color(int Color)
wxString Get_Class_Name(int Class)
wxString Get_Class_Name_byValue(double Value)
double Get_Class_Value_Maximum(int Class)
bool Set_NoData_Color(int Color)
int Cmp(const CSG_String &String) const
const SG_Char * c_str(void) const
int Printf(const char *Format,...)
double asDouble(int Field) const
const SG_Char * asString(int Field, int Decimals=-99) const
sLong Get_Count(void) const
Definition table.h:410
virtual bool Get_Value(sLong Index, int Field, CSG_String &Value) const
Definition table.cpp:1159
int Get_Field_Count(void) const
Definition table.h:371
@ SG_DATAOBJECT_TYPE_PointCloud
Definition dataobject.h:123
@ SG_DATAOBJECT_TYPE_Grids
Definition dataobject.h:119
@ SG_DATAOBJECT_TYPE_TIN
Definition dataobject.h:122
@ SG_DATAOBJECT_TYPE_Shapes
Definition dataobject.h:121
@ SG_DATAOBJECT_TYPE_Grid
Definition dataobject.h:118
#define isNoData(i)
#define asDouble(i)
#define HISTOGRAM_UPDATE(pLayer)
@ TABLE_INDEX_Ascending
Definition table.h:105