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_PointCloud.cpp //
15 // //
16 // Copyright (C) 2009 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 Hamburg //
42 // Germany //
43 // //
44 // e-mail: oconrad@saga-gis.org //
45 // //
46 ///////////////////////////////////////////////////////////
47
48 //---------------------------------------------------------
49 #include "res_commands.h"
50 #include "res_dialogs.h"
51
52 #include "helper.h"
53
54 #include "active.h"
55 #include "active_attributes.h"
56
57 #include "wksp_map_control.h"
58
59 #include "wksp_layer_classify.h"
60
61 #include "wksp_data_manager.h"
62
63 #include "wksp_pointcloud.h"
64 #include "wksp_table.h"
65 #include "view_table.h"
66 #include "view_scatterplot.h"
67
68
69 ///////////////////////////////////////////////////////////
70 // //
71 // //
72 // //
73 ///////////////////////////////////////////////////////////
74
75 //---------------------------------------------------------
CWKSP_PointCloud(CSG_PointCloud * pPointCloud)76 CWKSP_PointCloud::CWKSP_PointCloud(CSG_PointCloud *pPointCloud)
77 : CWKSP_Layer(pPointCloud)
78 {
79 m_pTable = new CWKSP_Table(pPointCloud);
80
81 m_Edit_Attributes.Destroy();
82 m_Edit_Attributes.Add_Field(_TL("Name" ), SG_DATATYPE_String);
83 m_Edit_Attributes.Add_Field(_TL("Value"), SG_DATATYPE_String);
84
85 //-----------------------------------------------------
86 On_Create_Parameters();
87
88 DataObject_Changed();
89
90 m_Parameters("COLORS_TYPE" )->Set_Value(CLASSIFY_GRADUATED);
91 m_Parameters("METRIC_ATTRIB")->Set_Value(2);
92
93 On_Parameter_Changed(&m_Parameters, m_Parameters("METRIC_ATTRIB"), PARAMETER_CHECK_ALL);
94
95 Parameters_Changed();
96 }
97
98 //---------------------------------------------------------
~CWKSP_PointCloud(void)99 CWKSP_PointCloud::~CWKSP_PointCloud(void)
100 {
101 delete(m_pTable);
102 }
103
104
105 ///////////////////////////////////////////////////////////
106 // //
107 ///////////////////////////////////////////////////////////
108
109 //---------------------------------------------------------
Get_Description(void)110 wxString CWKSP_PointCloud::Get_Description(void)
111 {
112 wxString s;
113
114 //-----------------------------------------------------
115 s += wxString::Format("<h4>%s</h4>", _TL("Point Cloud"));
116
117 s += "<table border=\"0\">";
118
119 DESC_ADD_STR(_TL("Name" ), m_pObject->Get_Name());
120 DESC_ADD_STR(_TL("Description" ), m_pObject->Get_Description());
121 DESC_ADD_STR(_TL("File" ), SG_File_Exists(m_pObject->Get_File_Name()) ? m_pObject->Get_File_Name() : _TL("memory"));
122 DESC_ADD_STR(_TL("Modified" ), m_pObject->is_Modified() ? _TL("yes") : _TL("no"));
123 DESC_ADD_STR(_TL("Projection" ), m_pObject->Get_Projection().Get_Description().c_str());
124 DESC_ADD_FLT(_TL("West" ), Get_PointCloud()->Get_Extent().Get_XMin());
125 DESC_ADD_FLT(_TL("East" ), Get_PointCloud()->Get_Extent().Get_XMax());
126 DESC_ADD_FLT(_TL("West-East" ), Get_PointCloud()->Get_Extent().Get_XRange());
127 DESC_ADD_FLT(_TL("South" ), Get_PointCloud()->Get_Extent().Get_YMin());
128 DESC_ADD_FLT(_TL("North" ), Get_PointCloud()->Get_Extent().Get_YMax());
129 DESC_ADD_FLT(_TL("South-North" ), Get_PointCloud()->Get_Extent().Get_YRange());
130 DESC_ADD_INT(_TL("Number of Points"), Get_PointCloud()->Get_Count());
131 DESC_ADD_SIZET(_TL("Selected" ), Get_PointCloud()->Get_Selection_Count());
132
133 s += "</table>";
134
135 s += Get_TableInfo_asHTML(Get_PointCloud());
136
137 //-----------------------------------------------------
138 // s += wxString::Format("<hr><b>%s</b><font size=\"-1\">", _TL("Data History"));
139 // s += Get_PointCloud()->Get_History().Get_HTML();
140 // s += wxString::Format("</font");
141
142 //-----------------------------------------------------
143 return( s );
144 }
145
146 //---------------------------------------------------------
Get_Menu(void)147 wxMenu * CWKSP_PointCloud::Get_Menu(void)
148 {
149 wxMenu *pMenu = new wxMenu(m_pObject->Get_Name());
150
151 CMD_Menu_Add_Item(pMenu, false, ID_CMD_WKSP_ITEM_CLOSE);
152 CMD_Menu_Add_Item(pMenu, false, ID_CMD_POINTCLOUD_SHOW);
153
154 pMenu->AppendSeparator();
155 CMD_Menu_Add_Item(pMenu, false, ID_CMD_DATA_SAVE);
156 CMD_Menu_Add_Item(pMenu, false, ID_CMD_DATA_SAVEAS);
157
158 if( m_pObject->is_File_Native() && m_pObject->is_Modified() )
159 CMD_Menu_Add_Item(pMenu, false, ID_CMD_DATA_RELOAD);
160
161 if( m_pObject->is_File_Native() )
162 CMD_Menu_Add_Item(pMenu, false, ID_CMD_DATA_DEL_FILES);
163
164 pMenu->AppendSeparator();
165 CMD_Menu_Add_Item(pMenu, false, ID_CMD_DATA_PROJECTION);
166
167 if( m_pObject->Get_MetaData().Get_Children_Count() > 0 )
168 CMD_Menu_Add_Item(pMenu, false, ID_CMD_DATA_METADATA);
169
170 pMenu->AppendSeparator();
171 CMD_Menu_Add_Item(pMenu, true, ID_CMD_SHAPES_HISTOGRAM);
172
173 pMenu->AppendSeparator();
174 CMD_Menu_Add_Item(pMenu, false, ID_CMD_SHAPES_SET_LUT);
175 CMD_Menu_Add_Item(pMenu, false, ID_CMD_WKSP_ITEM_SETTINGS_COPY);
176
177 pMenu->AppendSeparator();
178
179 //-----------------------------------------------------
180 wxMenu *pSubMenu = new wxMenu(_TL("Classification"));
181
182 CMD_Menu_Add_Item(pSubMenu , false, ID_CMD_POINTCLOUD_RANGE_MINMAX);
183 CMD_Menu_Add_Item(pSubMenu , false, ID_CMD_POINTCLOUD_RANGE_STDDEV150);
184 CMD_Menu_Add_Item(pSubMenu , false, ID_CMD_POINTCLOUD_RANGE_STDDEV200);
185
186 pMenu->Append(ID_CMD_WKSP_FIRST, _TL("Classification"), pSubMenu);
187
188 //-----------------------------------------------------
189 wxMenu *pTable = new wxMenu(_TL("Table"));
190
191 CMD_Menu_Add_Item(pTable, true, ID_CMD_TABLE_SHOW);
192 // CMD_Menu_Add_Item(pTable, true, ID_CMD_TABLE_DIAGRAM);
193 // CMD_Menu_Add_Item(pTable, false, ID_CMD_TABLE_SCATTERPLOT);
194
195 pMenu->Append(ID_CMD_WKSP_FIRST, _TL("Attributes"), pTable);
196
197 return( pMenu );
198 }
199
200
201 ///////////////////////////////////////////////////////////
202 // //
203 ///////////////////////////////////////////////////////////
204
205 //---------------------------------------------------------
On_Command(int Cmd_ID)206 bool CWKSP_PointCloud::On_Command(int Cmd_ID)
207 {
208 switch( Cmd_ID )
209 {
210 default:
211 return( CWKSP_Layer::On_Command(Cmd_ID) );
212
213 case ID_CMD_POINTCLOUD_LAST:
214 break;
215
216 case ID_CMD_SHAPES_SET_LUT:
217 _LUT_Create();
218 break;
219
220 case ID_CMD_POINTCLOUD_RANGE_MINMAX:
221 Set_Color_Range(
222 Get_PointCloud()->Get_Minimum(m_fValue),
223 Get_PointCloud()->Get_Maximum(m_fValue)
224 );
225 break;
226
227 case ID_CMD_POINTCLOUD_RANGE_STDDEV150:
228 Set_Color_Range(
229 Get_PointCloud()->Get_Mean(m_fValue) - 1.5 * Get_PointCloud()->Get_StdDev(m_fValue),
230 Get_PointCloud()->Get_Mean(m_fValue) + 1.5 * Get_PointCloud()->Get_StdDev(m_fValue)
231 );
232 break;
233
234 case ID_CMD_POINTCLOUD_RANGE_STDDEV200:
235 Set_Color_Range(
236 Get_PointCloud()->Get_Mean(m_fValue) - 2. * Get_PointCloud()->Get_StdDev(m_fValue),
237 Get_PointCloud()->Get_Mean(m_fValue) + 2. * Get_PointCloud()->Get_StdDev(m_fValue)
238 );
239 break;
240
241 case ID_CMD_SHAPES_EDIT_SEL_CLEAR:
242 Get_PointCloud()->Select();
243 Update_Views();
244 break;
245
246 case ID_CMD_SHAPES_EDIT_SEL_INVERT:
247 Get_PointCloud()->Inv_Selection();
248 Update_Views();
249 break;
250
251 case ID_CMD_SHAPES_EDIT_DEL_SHAPE:
252 if( Get_PointCloud()->Get_Selection_Count() > 0 && DLG_Message_Confirm(_TL("Delete selected point(s)."), _TL("Edit Point Cloud")) )
253 {
254 Get_PointCloud()->Del_Selection();
255
256 Update_Views();
257 }
258 break;
259
260 case ID_CMD_TABLE_SHOW:
261 m_pTable->Toggle_View();
262 break;
263
264 case ID_CMD_TABLE_DIAGRAM:
265 m_pTable->Toggle_Diagram();
266 break;
267
268 case ID_CMD_SHAPES_HISTOGRAM:
269 Histogram_Toggle();
270 break;
271 }
272
273 return( true );
274 }
275
276 //---------------------------------------------------------
On_Command_UI(wxUpdateUIEvent & event)277 bool CWKSP_PointCloud::On_Command_UI(wxUpdateUIEvent &event)
278 {
279 switch( event.GetId() )
280 {
281 default:
282 return( CWKSP_Layer::On_Command_UI(event) );
283
284 case ID_CMD_POINTCLOUD_LAST:
285 break;
286
287 case ID_CMD_TABLE_SHOW:
288 event.Check(m_pTable->Get_View() != NULL);
289 break;
290
291 case ID_CMD_TABLE_DIAGRAM:
292 event.Check(m_pTable->Get_Diagram() != NULL);
293 break;
294 }
295
296 return( true );
297 }
298
299
300 ///////////////////////////////////////////////////////////
301 // //
302 ///////////////////////////////////////////////////////////
303
304 //---------------------------------------------------------
On_Create_Parameters(void)305 void CWKSP_PointCloud::On_Create_Parameters(void)
306 {
307 CWKSP_Layer::On_Create_Parameters();
308
309 //-----------------------------------------------------
310 m_Parameters.Add_Int("NODE_DISPLAY",
311 "DISPLAY_SIZE" , _TL("Point Size"),
312 _TL(""),
313 0, 0, true
314 );
315
316 m_Parameters.Add_Choice("NODE_DISPLAY",
317 "DISPLAY_VALUE_AGGREGATE", _TL("Value Aggregation"),
318 _TL(""),
319 CSG_String::Format("%s|%s|%s|%s",
320 _TL("first value"),
321 _TL("last value" ),
322 _TL("lowest z" ),
323 _TL("highest z" )
324 ), 3
325 );
326
327 //-----------------------------------------------------
328 m_Parameters.Add_Node("NODE_COLORS", "NODE_RGB", _TL("RGB"), _TL(""));
329
330 m_Parameters.Add_Choice("NODE_RGB",
331 "RGB_ATTRIB" , _TL("Attribute"),
332 _TL(""),
333 _TL("<default>")
334 );
335
336 //-----------------------------------------------------
337 // Memory...
338
339 m_Parameters.Add_Double("NODE_GENERAL",
340 "MAX_SAMPLES" , _TL("Maximum Samples"),
341 _TL("Maximum number of samples used to build statistics and histograms expressed as percent of the total number of cells."),
342 100. * m_pObject->Get_Max_Samples() / (double)Get_PointCloud()->Get_Count(), 0., true, 100., true
343 );
344 }
345
346
347 ///////////////////////////////////////////////////////////
348 // //
349 ///////////////////////////////////////////////////////////
350
351 //---------------------------------------------------------
On_DataObject_Changed(void)352 void CWKSP_PointCloud::On_DataObject_Changed(void)
353 {
354 {
355 if( m_fValue >= Get_PointCloud()->Get_Field_Count() )
356 {
357 m_fValue = Get_PointCloud()->Get_Field_Count() - 1;
358 }
359
360 double m = Get_PointCloud()->Get_Mean (m_fValue);
361 double s = Get_PointCloud()->Get_StdDev(m_fValue) * 2.;
362
363 m_Parameters("METRIC_ZRANGE")->asRange()->Set_Range(m - s, m + s);
364 }
365
366 _AttributeList_Set(m_Parameters("LUT_ATTRIB" ), false);
367 _AttributeList_Set(m_Parameters("METRIC_ATTRIB"), false);
368 _AttributeList_Set(m_Parameters("RGB_ATTRIB" ), false);
369
370 //-----------------------------------------------------
371 m_Parameters.Set_Parameter("MAX_SAMPLES", 100. * m_pObject->Get_Max_Samples() / (double)Get_PointCloud()->Get_Count());
372
373 //-----------------------------------------------------
374 CWKSP_Layer::On_DataObject_Changed();
375
376 m_pTable->DataObject_Changed();
377 }
378
379 //---------------------------------------------------------
On_Parameters_Changed(void)380 void CWKSP_PointCloud::On_Parameters_Changed(void)
381 {
382 CWKSP_Layer::On_Parameters_Changed();
383
384 //-----------------------------------------------------
385 switch( m_Parameters("COLORS_TYPE")->asInt() )
386 {
387 default: m_fValue = -1 ; break; // CLASSIFY_SINGLE
388 case 1: m_fValue = m_Parameters("LUT_ATTRIB" )->asInt(); break; // CLASSIFY_LUT
389 case 2: m_fValue = m_Parameters("METRIC_ATTRIB")->asInt(); break; // CLASSIFY_DISCRETE
390 case 3: m_fValue = m_Parameters("METRIC_ATTRIB")->asInt(); break; // CLASSIFY_GRADUATED
391 case 4: m_fValue = m_Parameters("RGB_ATTRIB" )->asInt(); break; // CLASSIFY_RGB
392 }
393
394 if( m_fValue < 0 || m_fValue >= Get_PointCloud()->Get_Field_Count() )
395 {
396 m_fValue = -1;
397
398 m_pClassify->Set_Mode(CLASSIFY_SINGLE);
399 }
400 else if( m_Parameters("COLORS_TYPE")->asInt() == CLASSIFY_OVERLAY )
401 {
402 m_pClassify->Set_Mode(CLASSIFY_RGB);
403 }
404
405 m_pObject->Set_Max_Samples(Get_PointCloud()->Get_Count() * (m_Parameters("MAX_SAMPLES")->asDouble() / 100.) );
406
407 //-----------------------------------------------------
408 long DefColor = m_Parameters("SINGLE_COLOR")->asColor();
409 m_Color_Pen = wxColour(SG_GET_R(DefColor), SG_GET_G(DefColor), SG_GET_B(DefColor));
410
411 m_PointSize = m_Parameters("DISPLAY_SIZE")->asInt();
412 }
413
414 //---------------------------------------------------------
On_Update_Views(void)415 void CWKSP_PointCloud::On_Update_Views(void)
416 {
417 m_pTable->Update_Views();
418 }
419
420
421 ///////////////////////////////////////////////////////////
422 // //
423 ///////////////////////////////////////////////////////////
424
425 //---------------------------------------------------------
On_Parameter_Changed(CSG_Parameters * pParameters,CSG_Parameter * pParameter,int Flags)426 int CWKSP_PointCloud::On_Parameter_Changed(CSG_Parameters *pParameters, CSG_Parameter *pParameter, int Flags)
427 {
428 //-----------------------------------------------------
429 if( Flags & PARAMETER_CHECK_VALUES )
430 {
431 if( pParameter->Cmp_Identifier("METRIC_ATTRIB") )
432 {
433 int zField = pParameter->asInt();
434
435 double m = Get_PointCloud()->Get_Mean (zField);
436 double s = Get_PointCloud()->Get_StdDev(zField) * 2.;
437 double min = m - s; if( min < Get_PointCloud()->Get_Minimum(zField) ) min = Get_PointCloud()->Get_Minimum(zField);
438 double max = m + s; if( max > Get_PointCloud()->Get_Maximum(zField) ) max = Get_PointCloud()->Get_Maximum(zField);
439
440 pParameters->Get_Parameter("METRIC_ZRANGE")->asRange()->Set_Range(min, max);
441 }
442 }
443
444 //-----------------------------------------------------
445 if( Flags & PARAMETER_CHECK_ENABLE )
446 {
447 if( pParameter->Cmp_Identifier("COLORS_TYPE") )
448 {
449 int Value = pParameter->asInt();
450
451 pParameters->Set_Enabled("NODE_SINGLE" , Value == CLASSIFY_SINGLE);
452 pParameters->Set_Enabled("NODE_LUT" , Value == CLASSIFY_LUT);
453 pParameters->Set_Enabled("NODE_METRIC" , Value == CLASSIFY_DISCRETE || Value == CLASSIFY_GRADUATED);
454 pParameters->Set_Enabled("NODE_RGB" , Value == 4);
455
456 return( 1 );
457 }
458 }
459
460 //-----------------------------------------------------
461 return( CWKSP_Layer::On_Parameter_Changed(pParameters, pParameter, Flags) );
462 }
463
464
465 ///////////////////////////////////////////////////////////
466 // //
467 ///////////////////////////////////////////////////////////
468
469 //---------------------------------------------------------
Get_Name_Attribute(void)470 wxString CWKSP_PointCloud::Get_Name_Attribute(void)
471 {
472 return( m_fValue < 0 || m_pClassify->Get_Mode() == CLASSIFY_SINGLE ? SG_T("") : Get_PointCloud()->Get_Field_Name(m_fValue) );
473 }
474
475 //---------------------------------------------------------
_AttributeList_Set(CSG_Parameter * pFields,bool bAddNoField)476 void CWKSP_PointCloud::_AttributeList_Set(CSG_Parameter *pFields, bool bAddNoField)
477 {
478 if( pFields && pFields->Get_Type() == PARAMETER_TYPE_Choice )
479 {
480 CSG_String s;
481
482 for(int i=0; i<Get_PointCloud()->Get_Field_Count(); i++)
483 {
484 s += Get_PointCloud()->Get_Field_Name(i); s += "|";
485 }
486
487 if( bAddNoField )
488 {
489 s += _TL("<none>");
490
491 pFields->asChoice()->Set_Items(s);
492
493 pFields->Set_Value(Get_PointCloud()->Get_Field_Count());
494 }
495 else
496 {
497 pFields->asChoice()->Set_Items(s);
498 }
499 }
500 }
501
502
503 ///////////////////////////////////////////////////////////
504 // //
505 ///////////////////////////////////////////////////////////
506
507 //---------------------------------------------------------
_LUT_Create(void)508 void CWKSP_PointCloud::_LUT_Create(void)
509 {
510 //-----------------------------------------------------
511 if( Get_PointCloud()->Get_Field_Count() <= 0 || Get_PointCloud()->Get_Count() < 1 )
512 {
513 DLG_Message_Show(_TL("Function failed because no attributes are available"), _TL("Classify"));
514
515 return;
516 }
517
518 //-----------------------------------------------------
519 static CSG_Parameters Parameters;
520
521 if( Parameters.Get_Count() == 0 )
522 {
523 Parameters.Create(_TL("Classify"));
524 Parameters.Add_Choice("", "FIELD" , _TL("Attribute" ), _TL(""), "");
525 Parameters.Add_Colors("", "COLOR" , _TL("Colors" ), _TL(""))->asColors()->Set_Count(11);
526 Parameters.Add_Choice("", "METHOD", _TL("Classification"), _TL(""),
527 CSG_String::Format("%s|%s|%s|%s",
528 _TL("unique values"),
529 _TL("equal intervals"),
530 _TL("quantiles"),
531 _TL("natural breaks")
532 ), 0
533 );
534 }
535
536 {
537 CSG_String Fields;
538
539 for(int i=0; i<Get_PointCloud()->Get_Field_Count(); i++)
540 {
541 Fields += CSG_String(Get_PointCloud()->Get_Field_Name(i)) + "|";
542 }
543
544 Parameters("FIELD")->asChoice()->Set_Items(Fields);
545 }
546
547 if( !DLG_Parameters(&Parameters) )
548 {
549 return;
550 }
551
552 //-----------------------------------------------------
553 DataObject_Changed();
554
555 int Field = Parameters("FIELD")->asInt();
556
557 CSG_Colors Colors(*Parameters("COLOR")->asColors());
558
559 CSG_Table Classes(m_Parameters("LUT")->asTable());
560
561 switch( SG_Data_Type_is_Numeric(Get_PointCloud()->Get_Field_Type(Field)) ? Parameters("METHOD")->asInt() : 0 )
562 {
563 //-----------------------------------------------------
564 case 0: // unique values
565 {
566 TSG_Data_Type Type = SG_Data_Type_is_Numeric(Get_PointCloud()->Get_Field_Type(Field))
567 ? SG_DATATYPE_Double : SG_DATATYPE_String;
568
569 Classes.Set_Field_Type(LUT_MIN, Type);
570 Classes.Set_Field_Type(LUT_MAX, Type);
571
572 CSG_Unique_String_Statistics s;
573
574 #define MAX_CLASSES 1024
575
576 for(int iShape=0; iShape<Get_PointCloud()->Get_Count() && s.Get_Count()<MAX_CLASSES; iShape++)
577 {
578 s += Get_PointCloud()->Get_Record(iShape)->asString(Field);
579 }
580
581 Colors.Set_Count(s.Get_Count());
582
583 for(int iClass=0; iClass<s.Get_Count(); iClass++)
584 {
585 CSG_String Value = s.Get_Value(iClass);
586
587 CSG_Table_Record *pClass = Classes.Add_Record();
588
589 pClass->Set_Value(0, Colors[iClass]); // Color
590 pClass->Set_Value(1, Value ); // Name
591 pClass->Set_Value(2, Value ); // Description
592 pClass->Set_Value(3, Value ); // Minimum
593 pClass->Set_Value(4, Value ); // Maximum
594 }
595 }
596 break;
597
598 //-----------------------------------------------------
599 case 1: // equal intervals
600 {
601 double Minimum, Maximum, Interval;
602
603 Interval = Get_PointCloud()->Get_Range (Field) / (double)Colors.Get_Count();
604 Minimum = Get_PointCloud()->Get_Minimum(Field);
605
606 Classes.Set_Field_Type(LUT_MIN, SG_DATATYPE_Double);
607 Classes.Set_Field_Type(LUT_MAX, SG_DATATYPE_Double);
608
609 for(int iClass=0; iClass<Colors.Get_Count(); iClass++, Minimum+=Interval)
610 {
611 Maximum = iClass < Colors.Get_Count() - 1 ? Minimum + Interval : Get_PointCloud()->Get_Maximum(Field) + 1.;
612
613 CSG_String Name = SG_Get_String(Minimum, -2)
614 + " - " + SG_Get_String(Maximum, -2);
615
616 CSG_Table_Record *pClass = Classes.Add_Record();
617
618 pClass->Set_Value(0, Colors[iClass]); // Color
619 pClass->Set_Value(1, Name ); // Name
620 pClass->Set_Value(2, Name ); // Description
621 pClass->Set_Value(3, Minimum ); // Minimum
622 pClass->Set_Value(4, Maximum ); // Maximum
623 }
624 }
625 break;
626
627 //-----------------------------------------------------
628 case 2: // quantiles
629 {
630 TSG_Table_Index_Order old_Order = Get_PointCloud()->Get_Index_Order(0);
631 int old_Field = Get_PointCloud()->Get_Index_Field(0);
632
633 Get_PointCloud()->Set_Index(Field, TABLE_INDEX_Ascending);
634
635 Classes.Set_Field_Type(LUT_MIN, SG_DATATYPE_Double);
636 Classes.Set_Field_Type(LUT_MAX, SG_DATATYPE_Double);
637
638 if( Get_PointCloud()->Get_Count() < Colors.Get_Count() )
639 {
640 Colors.Set_Count(Get_PointCloud()->Get_Count());
641 }
642
643 double Minimum, Maximum, Count, iRecord;
644
645 Maximum = Get_PointCloud()->Get_Minimum(Field);
646 iRecord = Count = Get_PointCloud()->Get_Count() / (double)Colors.Get_Count();
647
648 for(int iClass=0; iClass<Colors.Get_Count(); iClass++, iRecord+=Count)
649 {
650 Minimum = Maximum;
651 Maximum = iRecord < Get_PointCloud()->Get_Count() ? Get_PointCloud()->Get_Record_byIndex((int)iRecord)->asDouble(Field) : Get_PointCloud()->Get_Maximum(Field) + 1.;
652
653 CSG_String Name = SG_Get_String(Minimum, -2)
654 + " - " + SG_Get_String(Maximum, -2);
655
656 CSG_Table_Record *pClass = Classes.Add_Record();
657
658 pClass->Set_Value(0, Colors[iClass]); // Color
659 pClass->Set_Value(1, Name ); // Name
660 pClass->Set_Value(2, Name ); // Description
661 pClass->Set_Value(3, Minimum ); // Minimum
662 pClass->Set_Value(4, Maximum ); // Maximum
663 }
664
665 Get_PointCloud()->Set_Index(old_Field, old_Order);
666 }
667 break;
668
669 //-----------------------------------------------------
670 case 3: // natural breaks
671 {
672 CSG_Natural_Breaks Breaks(Get_PointCloud(), Field, Colors.Get_Count(), Get_PointCloud()->Get_Count() > 4096 ? 256 : 0);
673
674 if( Breaks.Get_Count() <= Colors.Get_Count() ) return;
675
676 Classes.Set_Field_Type(LUT_MIN, SG_DATATYPE_Double);
677 Classes.Set_Field_Type(LUT_MAX, SG_DATATYPE_Double);
678
679 for(int iClass=0; iClass<Colors.Get_Count(); iClass++)
680 {
681 CSG_Table_Record *pClass = Classes.Add_Record();
682
683 double Minimum = Breaks[iClass ];
684 double Maximum = Breaks[iClass + 1];
685
686 CSG_String Name = SG_Get_String(Minimum, -2)
687 + " - " + SG_Get_String(Maximum, -2);
688
689 pClass->Set_Value(0, Colors[iClass]); // Color
690 pClass->Set_Value(1, Name ); // Name
691 pClass->Set_Value(2, Name ); // Description
692 pClass->Set_Value(3, Minimum ); // Minimum
693 pClass->Set_Value(4, Maximum ); // Maximum
694 }
695 }
696 break;
697 }
698
699 //-----------------------------------------------------
700 if( Classes.Get_Count() > 0 )
701 {
702 m_Parameters("LUT")->asTable()->Assign(&Classes);
703
704 m_Parameters("COLORS_TYPE")->Set_Value(CLASSIFY_LUT); // Lookup Table
705 m_Parameters("LUT_ATTRIB" )->Set_Value(Field);
706
707 Parameters_Changed();
708 }
709 }
710
711
712 ///////////////////////////////////////////////////////////
713 // //
714 ///////////////////////////////////////////////////////////
715
716 //---------------------------------------------------------
Get_Value(CSG_Point ptWorld,double Epsilon)717 wxString CWKSP_PointCloud::Get_Value(CSG_Point ptWorld, double Epsilon)
718 {
719 CSG_Shape *pShape;
720
721 if( (pShape = Get_PointCloud()->Get_Shape(ptWorld, Epsilon)) != NULL )
722 {
723 if( m_fValue >= 0 )
724 {
725 switch( m_pClassify->Get_Mode() )
726 {
727 case CLASSIFY_LUT:
728 return( m_pClassify->Get_Class_Name_byValue(pShape->asDouble(m_fValue)) );
729
730 case CLASSIFY_DISCRETE: default:
731 return( pShape->asString(m_fValue) );
732
733 case CLASSIFY_RGB:
734 double Value = pShape->asDouble(m_fValue);
735 return( wxString::Format("R%03d G%03d B%03d", SG_GET_R((int)Value), SG_GET_G((int)Value), SG_GET_B((int)Value)) );
736 }
737 }
738 else
739 {
740 return( wxString::Format("%s: %d", _TL("Index"), pShape->Get_Index() + 1) );
741 }
742 }
743
744 return( _TL("") );
745 }
746
747
748 ///////////////////////////////////////////////////////////
749 // //
750 ///////////////////////////////////////////////////////////
751
752 //---------------------------------------------------------
Get_Value_Minimum(void)753 double CWKSP_PointCloud::Get_Value_Minimum(void) { return( m_fValue < 0 ? 0. : Get_PointCloud()->Get_Minimum(m_fValue) ); }
Get_Value_Maximum(void)754 double CWKSP_PointCloud::Get_Value_Maximum(void) { return( m_fValue < 0 ? 0. : Get_PointCloud()->Get_Maximum(m_fValue) ); }
Get_Value_Range(void)755 double CWKSP_PointCloud::Get_Value_Range (void) { return( m_fValue < 0 ? 0. : Get_PointCloud()->Get_Range (m_fValue) ); }
Get_Value_Mean(void)756 double CWKSP_PointCloud::Get_Value_Mean (void) { return( m_fValue < 0 ? 0. : Get_PointCloud()->Get_Mean (m_fValue) ); }
Get_Value_StdDev(void)757 double CWKSP_PointCloud::Get_Value_StdDev (void) { return( m_fValue < 0 ? 0. : Get_PointCloud()->Get_StdDev (m_fValue) ); }
758
759
760 ///////////////////////////////////////////////////////////
761 // //
762 ///////////////////////////////////////////////////////////
763
764 //---------------------------------------------------------
asImage(CSG_Grid * pImage)765 bool CWKSP_PointCloud::asImage(CSG_Grid *pImage)
766 {
767 return( false );
768 }
769
770
771 ///////////////////////////////////////////////////////////
772 // //
773 ///////////////////////////////////////////////////////////
774
775 //---------------------------------------------------------
Edit_Get_Menu(void)776 wxMenu * CWKSP_PointCloud::Edit_Get_Menu(void)
777 {
778 wxMenu *pMenu = new wxMenu;
779
780 CMD_Menu_Add_Item(pMenu, false, ID_CMD_SHAPES_EDIT_DEL_SHAPE);
781 CMD_Menu_Add_Item(pMenu, false, ID_CMD_SHAPES_EDIT_SEL_CLEAR);
782 CMD_Menu_Add_Item(pMenu, false, ID_CMD_SHAPES_EDIT_SEL_INVERT);
783
784 return( pMenu );
785 }
786
787 //---------------------------------------------------------
Edit_Get_Extent(void)788 TSG_Rect CWKSP_PointCloud::Edit_Get_Extent(void)
789 {
790 if( Get_PointCloud()->Get_Selection_Count() > 0 )
791 {
792 return( Get_PointCloud()->Get_Selection_Extent().m_rect );
793 }
794
795 return( Get_PointCloud()->Get_Extent() );
796 }
797
798 //---------------------------------------------------------
Edit_On_Mouse_Up(CSG_Point Point,double ClientToWorld,int Key)799 bool CWKSP_PointCloud::Edit_On_Mouse_Up(CSG_Point Point, double ClientToWorld, int Key)
800 {
801 if( Key & TOOL_INTERACTIVE_KEY_RIGHT )
802 {
803 return( false );
804 }
805 else
806 {
807 CSG_Rect rWorld(m_Edit_Mouse_Down, Point);
808
809 if( rWorld.Get_XRange() == 0. && rWorld.Get_YRange() == 0. )
810 {
811 rWorld.Inflate(2. * ClientToWorld, false);
812 }
813
814 g_pActive->Update_Attributes();
815
816 Get_PointCloud()->Select(rWorld, (Key & TOOL_INTERACTIVE_KEY_CTRL) != 0);
817
818 //-----------------------------------------------------
819 m_Edit_Attributes.Del_Records();
820 m_Edit_Index = 0;
821
822 CSG_Table_Record *pRecord = Get_PointCloud()->Get_Selection();
823
824 if( pRecord != NULL )
825 {
826 for(int i=0; i<Get_PointCloud()->Get_Field_Count(); i++)
827 {
828 CSG_Table_Record *pAttribute = m_Edit_Attributes.Add_Record();
829 pAttribute->Set_Value(0, pRecord->Get_Table()->Get_Field_Name(i));
830 pAttribute->Set_Value(1, pRecord->asString(i));
831 }
832 }
833
834 //-----------------------------------------------------
835 g_pActive->Update_Attributes();
836
837 if( m_pTable->Get_View() )
838 {
839 m_pTable->Get_View()->Update_Selection();
840 }
841
842 Update_Views(false);
843 }
844
845 return( true );
846 }
847
848 //---------------------------------------------------------
Edit_Set_Index(int Index)849 bool CWKSP_PointCloud::Edit_Set_Index(int Index)
850 {
851 m_Edit_Attributes.Del_Records();
852
853 if( Index > (int)Get_PointCloud()->Get_Selection_Count() )
854 {
855 Index = Get_PointCloud()->Get_Selection_Count();
856 }
857
858 CSG_Table_Record *pSelection = Get_PointCloud()->Get_Selection(Index);
859
860 if( pSelection )
861 {
862 m_Edit_Index = Index;
863
864 for(int i=0; i<Get_PointCloud()->Get_Field_Count(); i++)
865 {
866 CSG_Table_Record *pRecord = m_Edit_Attributes.Add_Record();
867
868 pRecord->Set_Value(0, pSelection->Get_Table()->Get_Field_Name(i));
869 pRecord->Set_Value(1, pSelection->asString(i));
870 }
871 }
872 else
873 {
874 m_Edit_Index = 0;
875 }
876
877 return( true );
878 }
879
880 //---------------------------------------------------------
Edit_Set_Attributes(void)881 bool CWKSP_PointCloud::Edit_Set_Attributes(void)
882 {
883 CSG_Table_Record *pSelection = Get_PointCloud()->Get_Selection(m_Edit_Index);
884
885 if( pSelection )
886 {
887 for(int i=0; i<m_Edit_Attributes.Get_Record_Count(); i++)
888 {
889 pSelection->Set_Value(i, m_Edit_Attributes.Get_Record(i)->asString(1));
890 }
891
892 Update_Views(false);
893
894 return( true );
895 }
896
897 return( false );
898 }
899
900
901 ///////////////////////////////////////////////////////////
902 // //
903 ///////////////////////////////////////////////////////////
904
905 //---------------------------------------------------------
On_Draw(CWKSP_Map_DC & dc_Map,int Flags)906 void CWKSP_PointCloud::On_Draw(CWKSP_Map_DC &dc_Map, int Flags)
907 {
908 if( Get_Extent().Intersects(dc_Map.m_rWorld) && dc_Map.IMG_Draw_Begin(m_Parameters("DISPLAY_TRANSPARENCY")->asDouble() / 100.) )
909 {
910 if( (Flags & LAYER_DRAW_FLAG_THUMBNAIL) == 0 )
911 {
912 _Draw_Points (dc_Map);
913 }
914 else
915 {
916 _Draw_Thumbnail(dc_Map);
917 }
918
919 dc_Map.IMG_Draw_End();
920 }
921 }
922
923
924 ///////////////////////////////////////////////////////////
925 // //
926 ///////////////////////////////////////////////////////////
927
928 //---------------------------------------------------------
_Draw_Point(CWKSP_Map_DC & dc_Map,int x,int y,double z,int Color)929 inline void CWKSP_PointCloud::_Draw_Point(CWKSP_Map_DC &dc_Map, int x, int y, double z, int Color)
930 {
931 if( m_Aggregation == 1 ) // last value
932 {
933 dc_Map.IMG_Set_Pixel(x, y, Color);
934 }
935 else if( m_Z.is_InGrid(x, y) )
936 {
937 switch( m_Aggregation )
938 {
939 case 0: // first value
940 if( m_N.asInt(x, y) == 0 )
941 {
942 dc_Map.IMG_Set_Pixel(x, y, Color);
943 }
944 break;
945
946 case 2: // lowest z
947 if( m_N.asInt(x, y) == 0 || z < m_Z.asDouble(x, y) )
948 {
949 dc_Map.IMG_Set_Pixel(x, y, Color);
950 m_Z.Set_Value(x, y, z);
951 }
952 break;
953
954 case 3: // highest z
955 if( m_N.asInt(x, y) == 0 || z > m_Z.asDouble(x, y) )
956 {
957 dc_Map.IMG_Set_Pixel(x, y, Color);
958 m_Z.Set_Value(x, y, z);
959 }
960 break;
961 }
962
963 m_N.Add_Value(x, y, 1);
964 }
965 }
966
967 //---------------------------------------------------------
_Draw_Point(CWKSP_Map_DC & dc_Map,int x,int y,double z,int Color,int Radius)968 void CWKSP_PointCloud::_Draw_Point(CWKSP_Map_DC &dc_Map, int x, int y, double z, int Color, int Radius)
969 {
970 _Draw_Point(dc_Map, x, y, z, Color);
971
972 for(int iy=1; iy<=Radius; iy++)
973 {
974 for(int ix=0; ix<=Radius; ix++)
975 {
976 if( ix*ix + iy*iy <= Radius*Radius )
977 {
978 _Draw_Point(dc_Map, x + ix, y + iy, z, Color);
979 _Draw_Point(dc_Map, x + iy, y - ix, z, Color);
980 _Draw_Point(dc_Map, x - ix, y - iy, z, Color);
981 _Draw_Point(dc_Map, x - iy, y + ix, z, Color);
982 }
983 }
984 }
985 }
986
987 //---------------------------------------------------------
_Draw_Points(CWKSP_Map_DC & dc_Map)988 void CWKSP_PointCloud::_Draw_Points(CWKSP_Map_DC &dc_Map)
989 {
990 m_Aggregation = m_Parameters("DISPLAY_VALUE_AGGREGATE")->asInt();
991
992 if( m_Aggregation != 1 )
993 {
994 m_Z.Create(SG_DATATYPE_Double, dc_Map.m_rDC.GetWidth(), dc_Map.m_rDC.GetHeight());
995 m_N.Create(SG_DATATYPE_Int , dc_Map.m_rDC.GetWidth(), dc_Map.m_rDC.GetHeight());
996 }
997
998 //-----------------------------------------------------
999 CSG_PointCloud *pPoints = Get_PointCloud();
1000
1001 int Selection = pPoints->Get_Selection_Count() > 0 ? (int)pPoints->Get_Selection_Index(m_Edit_Index) : -1;
1002
1003 for(int i=0; i<pPoints->Get_Count(); i++)
1004 {
1005 pPoints->Set_Cursor(i);
1006
1007 if( !pPoints->is_NoData(m_fValue) )
1008 {
1009 TSG_Point_Z Point = pPoints->Get_Point();
1010
1011 if( dc_Map.m_rWorld.Contains(Point.x, Point.y) )
1012 {
1013 int x = (int)dc_Map.xWorld2DC(Point.x);
1014 int y = (int)dc_Map.yWorld2DC(Point.y);
1015
1016 if( Selection >= 0 && pPoints->is_Selected(i) )
1017 {
1018 int Size = Selection == i ? 2 + m_PointSize : m_PointSize;
1019
1020 _Draw_Point(dc_Map, x, y, Point.z, SG_COLOR_YELLOW, Size );
1021 _Draw_Point(dc_Map, x, y, Point.z, SG_COLOR_RED , Size + 2);
1022 }
1023 else
1024 {
1025 int Color;
1026
1027 m_pClassify->Get_Class_Color_byValue(pPoints->Get_Value(m_fValue), Color);
1028
1029 _Draw_Point(dc_Map, x, y, Point.z, Color, m_PointSize);
1030 }
1031 }
1032 }
1033 }
1034 }
1035
1036 //---------------------------------------------------------
_Draw_Thumbnail(CWKSP_Map_DC & dc_Map)1037 void CWKSP_PointCloud::_Draw_Thumbnail(CWKSP_Map_DC &dc_Map)
1038 {
1039 CSG_PointCloud *pPoints = Get_PointCloud();
1040
1041 int n = 1 + (int)(pPoints->Get_Count() / (2 * dc_Map.m_rDC.GetWidth() * dc_Map.m_rDC.GetHeight()));
1042
1043 for(int i=0; i<pPoints->Get_Count(); i+=n)
1044 {
1045 pPoints->Set_Cursor(i);
1046
1047 if( !pPoints->is_NoData(m_fValue) )
1048 {
1049 TSG_Point_Z Point = pPoints->Get_Point();
1050
1051 int x = (int)dc_Map.xWorld2DC(Point.x);
1052 int y = (int)dc_Map.yWorld2DC(Point.y);
1053
1054 int Color;
1055
1056 m_pClassify->Get_Class_Color_byValue(pPoints->Get_Value(m_fValue), Color);
1057
1058 dc_Map.IMG_Set_Pixel(x, y, Color);
1059 }
1060 }
1061 }
1062
1063
1064 ///////////////////////////////////////////////////////////
1065 // //
1066 // //
1067 // //
1068 ///////////////////////////////////////////////////////////
1069
1070 //---------------------------------------------------------
1071