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