1 
2 ///////////////////////////////////////////////////////////
3 //                                                       //
4 //                         SAGA                          //
5 //                                                       //
6 //      System for Automated Geoscientific Analyses      //
7 //                                                       //
8 //           Application Programming Interface           //
9 //                                                       //
10 //                  Library: SAGA_API                    //
11 //                                                       //
12 //-------------------------------------------------------//
13 //                                                       //
14 //                     quadtree.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'.                              //
22 //                                                       //
23 // This library is free software; you can redistribute   //
24 // it and/or modify it under the terms of the GNU Lesser //
25 // General Public License as published by the Free       //
26 // Software Foundation, either version 2.1 of the        //
27 // License, or (at your option) any later version.       //
28 //                                                       //
29 // This library is distributed in the hope that it will  //
30 // be useful, but WITHOUT ANY WARRANTY; without even the //
31 // implied warranty of MERCHANTABILITY or FITNESS FOR A  //
32 // PARTICULAR PURPOSE. See the GNU Lesser General Public //
33 // License for more details.                             //
34 //                                                       //
35 // You should have received a copy of the GNU Lesser     //
36 // General Public License along with this program; if    //
37 // not, see <http://www.gnu.org/licenses/>.              //
38 //                                                       //
39 //-------------------------------------------------------//
40 //                                                       //
41 //    e-mail:     oconrad@saga-gis.org                   //
42 //                                                       //
43 //    contact:    Olaf Conrad                            //
44 //                Institute of Geography                 //
45 //                University of Hamburg                  //
46 //                Germany                                //
47 //                                                       //
48 ///////////////////////////////////////////////////////////
49 
50 //---------------------------------------------------------
51 #include "shapes.h"
52 
53 
54 ///////////////////////////////////////////////////////////
55 //														 //
56 //														 //
57 //														 //
58 ///////////////////////////////////////////////////////////
59 
60 //---------------------------------------------------------
CSG_PRQuadTree_Node(const CSG_Rect & Extent,int Quadrant)61 CSG_PRQuadTree_Node::CSG_PRQuadTree_Node(const CSG_Rect &Extent, int Quadrant)
62 	: CSG_PRQuadTree_Item(Extent, Quadrant)
63 {
64 	m_pChildren[0] = m_pChildren[1] = m_pChildren[2] = m_pChildren[3] = NULL;
65 }
66 
67 //---------------------------------------------------------
CSG_PRQuadTree_Node(CSG_PRQuadTree_Leaf * pLeaf)68 CSG_PRQuadTree_Node::CSG_PRQuadTree_Node(CSG_PRQuadTree_Leaf *pLeaf)
69 	: CSG_PRQuadTree_Item(pLeaf->m_Extent)
70 {
71 	m_pChildren[0] = m_pChildren[1] = m_pChildren[2] = m_pChildren[3] = NULL;
72 
73 	int	Quadrant	=  Get_Quadrant(pLeaf->Get_Point());
74 
75 	pLeaf->Set_Extent(m_Extent, Quadrant);
76 
77 	m_pChildren[Quadrant] = pLeaf;
78 }
79 
80 //---------------------------------------------------------
~CSG_PRQuadTree_Node(void)81 CSG_PRQuadTree_Node::~CSG_PRQuadTree_Node(void)
82 {
83 	for(int i=0; i<4; i++)
84 	{
85 		if( m_pChildren[i] )
86 		{
87 			if( m_pChildren[i]->is_Leaf() )
88 			{
89 				delete((CSG_PRQuadTree_Leaf *)m_pChildren[i]);
90 			}
91 			else
92 			{
93 				delete((CSG_PRQuadTree_Node *)m_pChildren[i]);
94 			}
95 		}
96 	}
97 }
98 
99 //---------------------------------------------------------
Get_Child(double x,double y)100 CSG_PRQuadTree_Item * CSG_PRQuadTree_Node::Get_Child(double x, double y)
101 {
102 	for(int i=0; i<4; i++)
103 	{
104 		if( m_pChildren[i] && m_pChildren[i]->Contains(x, y) )
105 		{
106 			return( m_pChildren[i]->is_Node() ? m_pChildren[i]->asNode()->Get_Child(x, y) : m_pChildren[i] );
107 		}
108 	}
109 
110 	return( this );
111 }
112 
113 //---------------------------------------------------------
Add_Point(double x,double y,double z)114 bool CSG_PRQuadTree_Node::Add_Point(double x, double y, double z)
115 {
116 	if( !Contains(x, y) )
117 	{
118 		return( false );
119 	}
120 
121 	if( has_Statistics() )
122 	{
123 		Get_X()->Add_Value(x);
124 		Get_Y()->Add_Value(y);
125 		Get_Z()->Add_Value(z);
126 	}
127 
128 	int	Quadrant	= Get_Quadrant(x, y);
129 
130 	//-----------------------------------------------------
131 	if( m_pChildren[Quadrant] == NULL )
132 	{
133 		m_pChildren[Quadrant]	= new CSG_PRQuadTree_Leaf(m_Extent, Quadrant, x, y, z);
134 
135 		return( true );
136 	}
137 
138 	//-----------------------------------------------------
139 	if( m_pChildren[Quadrant]->is_Leaf() )
140 	{
141 		CSG_PRQuadTree_Leaf	*pLeaf	= m_pChildren[Quadrant]->asLeaf();
142 
143 		if( x != pLeaf->Get_X() || y != pLeaf->Get_Y() )
144 		{
145 			if( has_Statistics() )
146 			{
147 				m_pChildren[Quadrant]	= new CSG_PRQuadTree_Node_Statistics(pLeaf);
148 			}
149 			else
150 			{
151 				m_pChildren[Quadrant]	= new CSG_PRQuadTree_Node(pLeaf);
152 			}
153 
154 			((CSG_PRQuadTree_Node *)m_pChildren[Quadrant])->Add_Point(x, y, z);
155 		}
156 		else // if( x == pLeaf->Get_X() || y == pLeaf->Get_Y() ) // duplicate !!
157 		{
158 			if( !pLeaf->has_Statistics() )
159 			{
160 				m_pChildren[Quadrant]	= new CSG_PRQuadTree_Leaf_List(pLeaf->m_Extent, -1, x, y, pLeaf->m_z);
161 
162 				delete(pLeaf);
163 			}
164 
165 			((CSG_PRQuadTree_Leaf_List *)m_pChildren[Quadrant])->Add_Value(z);
166 		}
167 
168 		return( true );
169 	}
170 
171 	//-----------------------------------------------------
172 	return( ((CSG_PRQuadTree_Node *)m_pChildren[Quadrant])->Add_Point(x, y, z) );	//	if( m_pChildren[i]->is_Node() )
173 }
174 
175 
176 ///////////////////////////////////////////////////////////
177 //														 //
178 //														 //
179 //														 //
180 ///////////////////////////////////////////////////////////
181 
182 //---------------------------------------------------------
CSG_PRQuadTree(void)183 CSG_PRQuadTree::CSG_PRQuadTree(void)
184 {
185 	m_pRoot		= NULL;
186 	m_nPoints	= 0;
187 	m_bPolar	= false;
188 }
189 
190 //---------------------------------------------------------
CSG_PRQuadTree(const TSG_Rect & Extent,bool bStatistics)191 CSG_PRQuadTree::CSG_PRQuadTree(const TSG_Rect &Extent, bool bStatistics)
192 {
193 	m_pRoot		= NULL;
194 	m_nPoints	= 0;
195 	m_bPolar	= false;
196 
197 	Create(Extent, bStatistics);
198 }
199 
200 //---------------------------------------------------------
CSG_PRQuadTree(CSG_Shapes * pShapes,int Attribute,bool bStatistics)201 CSG_PRQuadTree::CSG_PRQuadTree(CSG_Shapes *pShapes, int Attribute, bool bStatistics)
202 {
203 	m_pRoot		= NULL;
204 	m_nPoints	= 0;
205 	m_bPolar	= false;
206 
207 	Create(pShapes, Attribute, bStatistics);
208 }
209 
210 //---------------------------------------------------------
~CSG_PRQuadTree(void)211 CSG_PRQuadTree::~CSG_PRQuadTree(void)
212 {
213 	Destroy();
214 }
215 
216 //---------------------------------------------------------
Create(const CSG_Rect & Extent,bool bStatistics)217 bool CSG_PRQuadTree::Create(const CSG_Rect &Extent, bool bStatistics)
218 {
219 	Destroy();
220 
221 	if( Extent.Get_XRange() > 0.0 && Extent.Get_YRange() > 0.0 )
222 	{
223 		double	Size	= (0.5 + 0.01) * (Extent.Get_XRange() > Extent.Get_YRange() ? Extent.Get_XRange() : Extent.Get_YRange());
224 
225 		CSG_Rect	r(
226 			Extent.Get_XCenter() - Size, Extent.Get_YCenter() - Size,
227 			Extent.Get_XCenter() + Size, Extent.Get_YCenter() + Size
228 		);
229 
230 		if( bStatistics )
231 		{
232 			m_pRoot	= new CSG_PRQuadTree_Node_Statistics(r);
233 		}
234 		else
235 		{
236 			m_pRoot	= new CSG_PRQuadTree_Node(r);
237 		}
238 
239 		return( true );
240 	}
241 
242 	return( false );
243 }
244 
245 //---------------------------------------------------------
Create(CSG_Shapes * pShapes,int Attribute,bool bStatistics)246 bool CSG_PRQuadTree::Create(CSG_Shapes *pShapes, int Attribute, bool bStatistics)
247 {
248 	Destroy();
249 
250 	if( pShapes && pShapes->is_Valid() && Create(pShapes->Get_Extent(), bStatistics) )
251 	{
252 		for(int iShape=0; iShape<pShapes->Get_Count() && SG_UI_Process_Set_Progress(iShape, pShapes->Get_Count()); iShape++)
253 		{
254 			CSG_Shape	*pShape	= pShapes->Get_Shape(iShape);
255 
256 			if( Attribute < 0 || !pShape->is_NoData(Attribute) )
257 			{
258 				double	z	= Attribute < 0 ? iShape : pShape->asDouble(Attribute);
259 
260 				for(int iPart=0; iPart<pShape->Get_Part_Count(); iPart++)
261 				{
262 					for(int iPoint=0; iPoint<pShape->Get_Point_Count(iPart); iPoint++)
263 					{
264 						Add_Point(pShape->Get_Point(iPoint, iPart), z);
265 					}
266 				}
267 			}
268 		}
269 
270 		return( Get_Point_Count() > 0 );
271 	}
272 
273 	return( false );
274 }
275 
276 //---------------------------------------------------------
Destroy(void)277 void CSG_PRQuadTree::Destroy(void)
278 {
279 	if( m_pRoot )
280 	{
281 		delete(m_pRoot);
282 
283 		m_pRoot	= NULL;
284 	}
285 
286 	m_nPoints	= 0;
287 
288 	m_Selection.Destroy();
289 }
290 
291 
292 ///////////////////////////////////////////////////////////
293 //														 //
294 ///////////////////////////////////////////////////////////
295 
296 //---------------------------------------------------------
Add_Point(double x,double y,double z)297 bool CSG_PRQuadTree::Add_Point(double x, double y, double z)
298 {
299 	if( _Check_Root(x, y) && m_pRoot->Add_Point(x, y, z) )
300 	{
301 		m_nPoints++;
302 
303 		return( true );
304 	}
305 
306 	return( false );
307 }
308 
309 //---------------------------------------------------------
Add_Point(const TSG_Point & p,double z)310 bool CSG_PRQuadTree::Add_Point(const TSG_Point &p, double z)
311 {
312 	return( Add_Point(p.x, p.y, z) );
313 }
314 
315 
316 ///////////////////////////////////////////////////////////
317 //														 //
318 ///////////////////////////////////////////////////////////
319 
320 //---------------------------------------------------------
_Check_Root(double x,double y)321 bool CSG_PRQuadTree::_Check_Root(double x, double y)
322 {
323 	if( !m_pRoot )
324 	{
325 		return( false );
326 	}
327 
328 	if( m_pRoot->Get_Extent().Contains(x, y) )
329 	{
330 		return( true );
331 	}
332 
333 	//-----------------------------------------------------
334 	int	Quadrant	= y < m_pRoot->Get_yMin()	// bottom / top ?
335 		? (x < m_pRoot->Get_xMin() ? 0 : 3) 	// bottom: left / right ?
336 		: (x < m_pRoot->Get_xMin() ? 1 : 2);	// top   : left / right ?
337 
338 	TSG_Rect	Extent	= m_pRoot->Get_Extent();
339 
340 	switch( Quadrant )
341 	{
342 	case 0: Extent.xMin -= m_pRoot->Get_Size(); Extent.yMin -= m_pRoot->Get_Size(); break; // bottom left
343 	case 1: Extent.xMin -= m_pRoot->Get_Size(); Extent.yMax += m_pRoot->Get_Size(); break; // top left
344 	case 2: Extent.xMax += m_pRoot->Get_Size(); Extent.yMin -= m_pRoot->Get_Size(); break; // bottom right
345 	case 3: Extent.xMax += m_pRoot->Get_Size(); Extent.yMax += m_pRoot->Get_Size(); break; // top right
346 	}
347 
348 	CSG_PRQuadTree_Node	*pRoot;
349 
350 	if( m_pRoot->has_Statistics() )
351 	{
352 		CSG_PRQuadTree_Node_Statistics	*pNode	= new CSG_PRQuadTree_Node_Statistics(Extent);
353 
354 		pNode->m_x	= ((CSG_PRQuadTree_Node_Statistics *)m_pRoot)->m_x;
355 		pNode->m_y	= ((CSG_PRQuadTree_Node_Statistics *)m_pRoot)->m_y;
356 		pNode->m_z	= ((CSG_PRQuadTree_Node_Statistics *)m_pRoot)->m_z;
357 
358 		pRoot	= pNode;
359 	}
360 	else
361 	{
362 		pRoot	= new CSG_PRQuadTree_Node(Extent);
363 	}
364 
365 	pRoot->m_pChildren[Quadrant]	= m_pRoot;
366 
367 	m_pRoot	= pRoot;
368 
369 	return( _Check_Root(x, y) );
370 }
371 
372 
373 ///////////////////////////////////////////////////////////
374 //														 //
375 ///////////////////////////////////////////////////////////
376 
377 //---------------------------------------------------------
_Quadrant_Contains(double x,double y,int iQuadrant,const TSG_Point & p) const378 inline bool CSG_PRQuadTree::_Quadrant_Contains(double x, double y, int iQuadrant, const TSG_Point &p) const
379 {
380 	switch( iQuadrant )
381 	{
382 	case 0:	return( x <  p.x && y <  p.y );	// lower left
383 	case 1:	return( x <  p.x && y >= p.y );	// upper left
384 	case 2:	return( x >= p.x && y >= p.y );	// upper right
385 	case 3:	return( x >= p.x && y <  p.y );	// lower right
386 	}
387 
388 	return( true );
389 }
390 
391 //---------------------------------------------------------
_Radius_Contains(double x,double y,double r,const TSG_Point & p) const392 inline bool CSG_PRQuadTree::_Radius_Contains(double x, double y, double r, const TSG_Point &p)	const
393 {
394 	double	dx, dy;
395 
396 	if( fabs(dx = x - p.x) <= r && fabs(dy = y - p.y) <= r )
397 	{
398 		return( dx*dx + dy*dy < r*r );
399 	}
400 
401 	return( false );
402 }
403 
404 //---------------------------------------------------------
_Radius_Contains(double x,double y,double r,int iQuadrant,const TSG_Point & p) const405 inline bool CSG_PRQuadTree::_Radius_Contains(double x, double y, double r, int iQuadrant, const TSG_Point &p)	const
406 {
407 	return( _Quadrant_Contains(x, y, iQuadrant, p) && _Radius_Contains(x, y, r, p) );
408 }
409 
410 //---------------------------------------------------------
_Quadrant_Intersects(double x,double y,int iQuadrant,CSG_PRQuadTree_Item * pItem) const411 inline bool CSG_PRQuadTree::_Quadrant_Intersects(double x, double y, int iQuadrant, CSG_PRQuadTree_Item *pItem)	const
412 {
413 	switch( iQuadrant )
414 	{
415 	case 0:	return( x <  pItem->Get_xMax() && y <  pItem->Get_yMax() );	// lower left
416 	case 1:	return( x <  pItem->Get_xMax() && y >= pItem->Get_yMin() );	// upper left
417 	case 2:	return( x >= pItem->Get_xMin() && y >= pItem->Get_yMin() );	// upper right
418 	case 3:	return( x >= pItem->Get_xMin() && y <  pItem->Get_yMax() );	// lower right
419 	}
420 
421 	return( true );
422 }
423 
424 //---------------------------------------------------------
_Radius_Intersects(double x,double y,double r,CSG_PRQuadTree_Item * pItem) const425 inline bool CSG_PRQuadTree::_Radius_Intersects(double x, double y, double r, CSG_PRQuadTree_Item *pItem)	const
426 {
427 	if( r <= 0.0 )
428 	{
429 		return( true );
430 	}
431 
432 	if(	pItem->Get_xMax() < x - r || pItem->Get_xMin() > x + r
433 	||	pItem->Get_yMax() < y - r || pItem->Get_yMin() > y + r )
434 	{
435 		return( false );
436 	}
437 
438 	if( (pItem->Get_xMin() <= x && x <= pItem->Get_xMax())
439 	||	(pItem->Get_yMin() <= y && y <= pItem->Get_yMax()) )
440 	{
441 		return( true );
442 	}
443 
444 	TSG_Point	p;
445 
446 	if( pItem->Get_xMax() < x )
447 	{
448 		p.x	= pItem->Get_xMax();
449 		p.y	= pItem->Get_yMax() < y ? pItem->Get_yMax() : pItem->Get_yMin();
450 	}
451 	else // if( pItem->Get_xMin() >= x )
452 	{
453 		p.x	= pItem->Get_xMin();
454 		p.y	= pItem->Get_yMax() < y ? pItem->Get_yMax() : pItem->Get_yMin();
455 	}
456 
457 	return( _Radius_Contains(x, y, r, p) );
458 }
459 
460 //---------------------------------------------------------
_Radius_Intersects(double x,double y,double r,int iQuadrant,CSG_PRQuadTree_Item * pItem) const461 inline bool CSG_PRQuadTree::_Radius_Intersects(double x, double y, double r, int iQuadrant, CSG_PRQuadTree_Item *pItem)	const
462 {
463 	return( _Quadrant_Intersects(x, y, iQuadrant, pItem) && _Radius_Intersects(x, y, r, pItem) );
464 }
465 
466 
467 ///////////////////////////////////////////////////////////
468 //														 //
469 ///////////////////////////////////////////////////////////
470 
471 //---------------------------------------------------------
Get_Nearest_Leaf(const TSG_Point & p,double & Distance) const472 CSG_PRQuadTree_Leaf * CSG_PRQuadTree::Get_Nearest_Leaf(const TSG_Point &p, double &Distance)	const
473 {
474 	return( Get_Nearest_Leaf(p.x, p.y, Distance) );
475 }
476 
Get_Nearest_Leaf(double x,double y,double & Distance) const477 CSG_PRQuadTree_Leaf * CSG_PRQuadTree::Get_Nearest_Leaf(double x, double y, double &Distance)	const
478 {
479 	return( _Get_Nearest_Point(m_pRoot, x, y, Distance = -1) );
480 }
481 
482 //---------------------------------------------------------
Get_Nearest_Point(const TSG_Point & p,TSG_Point & Point,double & Value,double & Distance) const483 bool CSG_PRQuadTree::Get_Nearest_Point(const TSG_Point &p, TSG_Point &Point, double &Value, double &Distance)	const
484 {
485 	return( Get_Nearest_Point(p.x, p.y, Point, Value, Distance) );
486 }
487 
Get_Nearest_Point(double x,double y,TSG_Point & Point,double & Value,double & Distance) const488 bool CSG_PRQuadTree::Get_Nearest_Point(double x, double y, TSG_Point &Point, double &Value, double &Distance)	const
489 {
490 	CSG_PRQuadTree_Leaf	*pLeaf	= _Get_Nearest_Point(m_pRoot, x, y, Distance = -1);
491 
492 	if( pLeaf )
493 	{
494 		Point.x		= pLeaf->Get_X();
495 		Point.y		= pLeaf->Get_Y();
496 		Value		= pLeaf->Get_Z();
497 
498 		return( true );
499 	}
500 
501 	return( false );
502 }
503 
504 //---------------------------------------------------------
_Get_Nearest_Point(CSG_PRQuadTree_Item * pItem,double x,double y,double & Distance) const505 CSG_PRQuadTree_Leaf	* CSG_PRQuadTree::_Get_Nearest_Point(CSG_PRQuadTree_Item *pItem, double x, double y, double &Distance)	const
506 {
507 	CSG_PRQuadTree_Leaf	*pLeaf, *pNearest	= NULL;
508 
509 	if( pItem )
510 	{
511 		if( pItem->is_Leaf() )
512 		{
513 			pLeaf	= (CSG_PRQuadTree_Leaf *)pItem;
514 
515 			double	d	= SG_Get_Distance(x, y, pLeaf->Get_X(), pLeaf->Get_Y(), m_bPolar);
516 
517 			if( Distance < 0.0 || Distance > d )
518 			{
519 				Distance	= d;
520 				pNearest	= pLeaf;
521 			}
522 		}
523 		else // if( pItem->is_Node() )
524 		{
525 			int	i;
526 
527 			if( pItem->Contains(x, y) )
528 			{
529 				for(i=0; i<4; i++)
530 				{
531 					CSG_PRQuadTree_Item	*pChild	= ((CSG_PRQuadTree_Node *)pItem)->Get_Child(i);
532 
533 					if( pChild && pChild->Contains(x, y) && (pLeaf = _Get_Nearest_Point(pChild, x, y, Distance)) != NULL )
534 					{
535 						pNearest	= pLeaf;
536 					}
537 				}
538 			}
539 
540 			for(i=0; i<4; i++)
541 			{
542 				CSG_PRQuadTree_Item	*pChild	= ((CSG_PRQuadTree_Node *)pItem)->Get_Child(i);
543 
544 				if( pChild && pChild->Contains(x, y) == false && (Distance < 0.0
545 				    || (  Distance > (x < pChild->Get_xCenter() ? pChild->Get_xMin() - x : x - pChild->Get_xMax())
546 				       && Distance > (y < pChild->Get_yCenter() ? pChild->Get_yMin() - y : y - pChild->Get_yMax()) ))
547 				&&  (pLeaf = _Get_Nearest_Point(pChild, x, y, Distance)) != NULL )
548 				{
549 					pNearest	= pLeaf;
550 				}
551 			}
552 		}
553 	}
554 
555 	return( pNearest );
556 }
557 
558 
559 ///////////////////////////////////////////////////////////
560 //														 //
561 ///////////////////////////////////////////////////////////
562 
563 //---------------------------------------------------------
_Get_Selected(const CSG_Array & Selection,size_t i) const564 inline CSG_PRQuadTree::TLeaf * CSG_PRQuadTree::_Get_Selected(const CSG_Array &Selection, size_t i)	const
565 {
566 	return( (TLeaf *)Selection.Get_Entry(i) );
567 }
568 
569 //---------------------------------------------------------
_Add_Selected(CSG_Array & Selection,CSG_PRQuadTree_Leaf * pLeaf,double Distance) const570 inline bool CSG_PRQuadTree::_Add_Selected(CSG_Array &Selection, CSG_PRQuadTree_Leaf *pLeaf, double Distance)	const
571 {
572 	if( Selection.Inc_Array() )
573 	{
574 		TLeaf	*pL		= (TLeaf *)Selection.Get_Entry(Selection.Get_Size() - 1);
575 
576 		pL->pLeaf		= pLeaf;
577 		pL->Distance	= Distance;
578 
579 		return( true );
580 	}
581 
582 	return( false );
583 }
584 
585 //---------------------------------------------------------
_Set_Selected(CSG_Array & Selection,size_t i,CSG_PRQuadTree_Leaf * pLeaf,double Distance) const586 inline bool CSG_PRQuadTree::_Set_Selected(CSG_Array &Selection, size_t i, CSG_PRQuadTree_Leaf *pLeaf, double Distance)	const
587 {
588 	TLeaf	*pL		= (TLeaf *)Selection.Get_Entry(i);
589 
590 	if( pL )
591 	{
592 		pL->pLeaf		= pLeaf;
593 		pL->Distance	= Distance;
594 
595 		return( true );
596 	}
597 
598 	return( false );
599 }
600 
601 
602 ///////////////////////////////////////////////////////////
603 //														 //
604 ///////////////////////////////////////////////////////////
605 
606 //---------------------------------------------------------
Select_Nearest_Points(const TSG_Point & p,size_t maxPoints,double Radius,int iQuadrant)607 size_t CSG_PRQuadTree::Select_Nearest_Points(const TSG_Point &p, size_t maxPoints, double Radius, int iQuadrant)
608 {
609 	return( Select_Nearest_Points(p.x, p.y, maxPoints, Radius, iQuadrant) );
610 }
611 
612 //---------------------------------------------------------
Select_Nearest_Points(double x,double y,size_t maxPoints,double Radius,int iQuadrant)613 size_t CSG_PRQuadTree::Select_Nearest_Points(double x, double y, size_t maxPoints, double Radius, int iQuadrant)
614 {
615 	return( _Select_Nearest_Points(m_Selection, x, y, maxPoints, Radius, iQuadrant) );
616 }
617 
618 //---------------------------------------------------------
_Select_Nearest_Points(CSG_Array & Selection,double x,double y,size_t maxPoints,double Radius,int iQuadrant) const619 size_t CSG_PRQuadTree::_Select_Nearest_Points(CSG_Array &Selection, double x, double y, size_t maxPoints, double Radius, int iQuadrant)	const
620 {
621 	if( Selection.Get_Value_Size() != sizeof(TLeaf) )
622 	{
623 		Selection.Create(sizeof(TLeaf), 0, SG_ARRAY_GROWTH_3);
624 	}
625 	else
626 	{
627 		Selection.Set_Array(0, false);
628 	}
629 
630 	if( m_pRoot )
631 	{
632 		double	Distance;
633 
634 		if( maxPoints < 1 )
635 		{
636 			maxPoints	= m_nPoints;
637 		}
638 
639 		if( iQuadrant != 4 )
640 		{
641 			_Select_Nearest_Points(Selection, m_pRoot, x, y, Distance = 0.0, Radius, maxPoints, iQuadrant);
642 		}
643 		else // if( iQuadrant == 4 )	// quadrant-wise search
644 		{
645 			for(iQuadrant=0; iQuadrant<4; iQuadrant++)
646 			{
647 				_Select_Nearest_Points(Selection, m_pRoot, x, y, Distance = 0.0, Radius, maxPoints, iQuadrant);
648 			}
649 		}
650 	}
651 
652 	return( Selection.Get_Size() );
653 }
654 
655 //---------------------------------------------------------
_Select_Nearest_Points(CSG_Array & Selection,CSG_PRQuadTree_Item * pItem,double x,double y,double & Distance,double Radius,size_t maxPoints,int iQuadrant) const656 void CSG_PRQuadTree::_Select_Nearest_Points(CSG_Array &Selection, CSG_PRQuadTree_Item *pItem, double x, double y, double &Distance, double Radius, size_t maxPoints, int iQuadrant)	const
657 {
658 	//-----------------------------------------------------
659 	if( pItem->is_Leaf() )
660 	{
661 		CSG_PRQuadTree_Leaf	*pLeaf	= (CSG_PRQuadTree_Leaf *)pItem;
662 
663 		if( _Quadrant_Contains(x, y, iQuadrant, pLeaf->Get_Point()) == false )
664 		{
665 			return;
666 		}
667 
668 		double	d	= SG_Get_Distance(x, y, pLeaf->Get_X(), pLeaf->Get_Y(), m_bPolar);
669 
670 		if( Radius > 0.0 && Radius < d )
671 		{
672 			return;
673 		}
674 
675 		//-------------------------------------------------
676 		if( Selection.Get_Size() < maxPoints )
677 		{
678 			if( Distance < d )
679 			{
680 				Distance	= d;
681 			}
682 
683 			_Add_Selected(Selection, pLeaf, d);
684 		}
685 		else if( d < Distance )
686 		{
687 			size_t	i;
688 
689 			for(i=0; i<Selection.Get_Size(); i++)
690 			{
691 				if( Distance <= _Get_Selected(Selection, i)->Distance )
692 				{
693 					_Set_Selected(Selection, i, pLeaf, d);
694 
695 					break;
696 				}
697 			}
698 
699 			for(i=0, Distance=d; i<maxPoints; i++)
700 			{
701 				if( Distance < _Get_Selected(Selection, i)->Distance )
702 				{
703 					Distance	= _Get_Selected(Selection, i)->Distance;
704 				}
705 			}
706 		}
707 	}
708 
709 	//-----------------------------------------------------
710 	else // if( pItem->is_Node() )
711 	{
712 		int	i;
713 
714 		CSG_PRQuadTree_Item	*pChild;
715 
716 		for(i=0; i<4; i++)
717 		{
718 			if( (pChild = ((CSG_PRQuadTree_Node *)pItem)->Get_Child(i)) != NULL && pChild->Contains(x, y) == true )
719 			{
720 				_Select_Nearest_Points(Selection, pChild, x, y, Distance, Radius, maxPoints, iQuadrant);
721 			}
722 		}
723 
724 		for(i=0; i<4; i++)
725 		{
726 			if( (pChild = ((CSG_PRQuadTree_Node *)pItem)->Get_Child(i)) != NULL && pChild->Contains(x, y) == false )
727 			{
728 				if( _Radius_Intersects(x, y, Radius, iQuadrant, pChild) )
729 				{
730 					if( Get_Selected_Count() < maxPoints
731 					||	(	Distance > (x < pChild->Get_xCenter() ? pChild->Get_xMin() - x : x - pChild->Get_xMax())
732 						&&	Distance > (y < pChild->Get_yCenter() ? pChild->Get_yMin() - y : y - pChild->Get_yMax())	) )
733 					{
734 						_Select_Nearest_Points(Selection, pChild, x, y, Distance, Radius, maxPoints, iQuadrant);
735 					}
736 				}
737 			}
738 		}
739 	}
740 }
741 
742 
743 ///////////////////////////////////////////////////////////
744 //														 //
745 ///////////////////////////////////////////////////////////
746 
747 //---------------------------------------------------------
Get_Nearest_Points(CSG_Points_Z & Points,const TSG_Point & p,size_t maxPoints,double Radius,int iQuadrant) const748 size_t CSG_PRQuadTree::Get_Nearest_Points(CSG_Points_Z &Points, const TSG_Point &p, size_t maxPoints, double Radius, int iQuadrant)	const
749 {
750 	return( Get_Nearest_Points(Points, p.x, p.y, maxPoints, Radius, iQuadrant) );
751 }
752 
753 //---------------------------------------------------------
Get_Nearest_Points(CSG_Points_Z & Points,double x,double y,size_t maxPoints,double Radius,int iQuadrant) const754 size_t CSG_PRQuadTree::Get_Nearest_Points(CSG_Points_Z &Points, double x, double y, size_t maxPoints, double Radius, int iQuadrant)	const
755 {
756 	CSG_Array	Selection;
757 
758 	_Select_Nearest_Points(Selection, x, y, maxPoints, Radius, iQuadrant);
759 
760 	Points.Clear();
761 
762 	for(size_t i=0; i<Selection.Get_Size(); i++)
763 	{
764 		CSG_PRQuadTree_Leaf	*pLeaf	= _Get_Selected(Selection, i)->pLeaf;
765 
766 		Points.Add(pLeaf->Get_X(), pLeaf->Get_Y(), pLeaf->Get_Z());
767 	}
768 
769 	return( Points.Get_Count() );
770 }
771 
772 
773 ///////////////////////////////////////////////////////////
774 //														 //
775 //														 //
776 //														 //
777 ///////////////////////////////////////////////////////////
778 
779 //---------------------------------------------------------
780 #include "parameters.h"
781 
782 //---------------------------------------------------------
CSG_Parameters_PointSearch(void)783 CSG_Parameters_PointSearch::CSG_Parameters_PointSearch(void)
784 {
785 	m_pParameters	= NULL;
786 
787 	m_minPoints		= 1;
788 	m_maxPoints		= 0;
789 	m_Radius		= 0.;
790 }
791 
792 //---------------------------------------------------------
Create(CSG_Parameters * pParameters,const CSG_String & Parent,size_t minPoints)793 bool CSG_Parameters_PointSearch::Create(CSG_Parameters *pParameters, const CSG_String &Parent, size_t minPoints)
794 {
795 	if( pParameters == NULL || m_pParameters != NULL )
796 	{
797 		return( false );
798 	}
799 
800 	m_pParameters	= pParameters;
801 
802 	if( !Parent.is_Empty() && !(*m_pParameters)(Parent) )
803 	{
804 		m_pParameters->Add_Node("", Parent, _TL("Search Options"), _TL(""));
805 	}
806 
807 	//-----------------------------------------------------
808 	m_pParameters->Add_Choice(Parent,
809 		"SEARCH_RANGE"		, _TL("Search Range"),
810 		_TL(""),
811 		CSG_String::Format("%s|%s",
812 			_TL("local"),
813 			_TL("global")
814 		), 1
815 	);
816 
817 	m_pParameters->Add_Double("SEARCH_RANGE",
818 		"SEARCH_RADIUS"		, _TL("Maximum Search Distance"),
819 		_TL("local maximum search distance given in map units"),
820 		1000., 0., true
821 	);
822 
823 	m_pParameters->Add_Choice(Parent,
824 		"SEARCH_POINTS_ALL"	, _TL("Number of Points"),
825 		_TL(""),
826 		CSG_String::Format("%s|%s",
827 			_TL("maximum number of nearest points"),
828 			_TL("all points within search distance")
829 		), 1
830 	);
831 
832 	if( minPoints > 0 )
833 	{
834 		m_pParameters->Add_Int("SEARCH_POINTS_ALL",
835 			"SEARCH_POINTS_MIN"	, _TL("Minimum"),
836 			_TL("minimum number of points to use"),
837 			(int)minPoints, 1, true
838 		);
839 	}
840 
841 	m_pParameters->Add_Int("SEARCH_POINTS_ALL",
842 		"SEARCH_POINTS_MAX"	, _TL("Maximum"),
843 		_TL("maximum number of nearest points"),
844 		20, 1, true
845 	);
846 
847 	return( true );
848 }
849 
850 
851 ///////////////////////////////////////////////////////////
852 //														 //
853 ///////////////////////////////////////////////////////////
854 
855 //---------------------------------------------------------
On_Parameter_Changed(CSG_Parameters * pParameters,CSG_Parameter * pParameter)856 bool CSG_Parameters_PointSearch::On_Parameter_Changed(CSG_Parameters *pParameters, CSG_Parameter *pParameter)
857 {
858 	if( !m_pParameters || !pParameters || m_pParameters->Get_Identifier().Cmp(pParameters->Get_Identifier()) || !pParameter || !pParameter->asShapes() )
859 	{
860 		return( false );
861 	}
862 
863 	pParameters->Set_Parameter("SEARCH_RADIUS", SG_Get_Rounded_To_SignificantFigures(
864 		5 * sqrt(pParameter->asShapes()->Get_Extent().Get_Area() / pParameter->asShapes()->Get_Count()), 1
865 	));
866 
867 	return( true );
868 }
869 
870 //---------------------------------------------------------
On_Parameters_Enable(CSG_Parameters * pParameters,CSG_Parameter * pParameter)871 bool CSG_Parameters_PointSearch::On_Parameters_Enable(CSG_Parameters *pParameters, CSG_Parameter *pParameter)
872 {
873 	if( !m_pParameters || !pParameters || m_pParameters->Get_Identifier().Cmp(pParameters->Get_Identifier()) || !pParameter )
874 	{
875 		return( false );
876 	}
877 
878 	if(	pParameter->Cmp_Identifier("SEARCH_RANGE") )
879 	{
880 		pParameters->Set_Enabled("SEARCH_RADIUS"    , pParameter->asInt() == 0);	// local
881 		pParameters->Set_Enabled("SEARCH_POINTS_MIN", pParameter->asInt() == 0);	// when global, no minimum number of points
882 	}
883 
884 	if(	pParameter->Cmp_Identifier("SEARCH_POINTS_ALL") )
885 	{
886 		pParameters->Set_Enabled("SEARCH_POINTS_MAX", pParameter->asInt() == 0);	// maximum number of points
887 		pParameters->Set_Enabled("SEARCH_DIRECTION" , pParameter->asInt() == 0);	// maximum number of points per quadrant
888 	}
889 
890 	return( true );
891 }
892 
893 
894 ///////////////////////////////////////////////////////////
895 //														 //
896 ///////////////////////////////////////////////////////////
897 
898 //---------------------------------------------------------
Update(void)899 bool CSG_Parameters_PointSearch::Update(void)
900 {
901 	if( m_pParameters )
902 	{
903 		m_minPoints	= (*m_pParameters)("SEARCH_POINTS_MIN")
904 					? (*m_pParameters)("SEARCH_POINTS_MIN")->asInt   () : 0;
905 		m_maxPoints	= (*m_pParameters)("SEARCH_POINTS_ALL")->asInt   () == 0
906 					? (*m_pParameters)("SEARCH_POINTS_MAX")->asInt   () : 0;
907 		m_Radius	= (*m_pParameters)("SEARCH_RANGE"     )->asInt   () == 0
908 					? (*m_pParameters)("SEARCH_RADIUS"    )->asDouble() : 0.;
909 
910 		return( true );
911 	}
912 
913 	return( false );
914 }
915 
916 //---------------------------------------------------------
Do_Use_All(bool bUpdate)917 bool CSG_Parameters_PointSearch::Do_Use_All(bool bUpdate)
918 {
919 	if( bUpdate )
920 	{
921 		Update();
922 	}
923 
924 	return( m_maxPoints == 0 && m_Radius <= 0. );
925 }
926 
927 
928 ///////////////////////////////////////////////////////////
929 //														 //
930 //														 //
931 //														 //
932 ///////////////////////////////////////////////////////////
933 
934 //---------------------------------------------------------
CSG_Parameters_Search_Points(void)935 CSG_Parameters_Search_Points::CSG_Parameters_Search_Points(void)
936 {
937 	Finalize();
938 }
939 
940 //---------------------------------------------------------
Create(CSG_Parameters * pParameters,CSG_Parameter * pParent,int minPoints)941 bool CSG_Parameters_Search_Points::Create(CSG_Parameters *pParameters, CSG_Parameter *pParent, int minPoints)
942 {
943 	return( pParent ? Create(pParameters, pParent->Get_Identifier(), minPoints) : Create(pParameters, "", minPoints) );
944 }
945 
946 //---------------------------------------------------------
Create(CSG_Parameters * pParameters,const CSG_String & Parent,int minPoints)947 bool CSG_Parameters_Search_Points::Create(CSG_Parameters *pParameters, const CSG_String &Parent, int minPoints)
948 {
949 	if( !CSG_Parameters_PointSearch::Create(pParameters, Parent, minPoints) )
950 	{
951 		return( false );
952 	}
953 
954 	m_pParameters->Add_Choice("SEARCH_POINTS_ALL",
955 		"SEARCH_DIRECTION"	, _TL("Direction"),
956 		_TL(""),
957 		CSG_String::Format("%s|%s",
958 			_TL("all directions"),
959 			_TL("quadrants")
960 		)
961 	);
962 
963 	return( true );
964 }
965 
966 
967 ///////////////////////////////////////////////////////////
968 //														 //
969 ///////////////////////////////////////////////////////////
970 
971 //---------------------------------------------------------
Update(void)972 bool CSG_Parameters_Search_Points::Update(void)
973 {
974 	if( m_pParameters )
975 	{
976 		m_Quadrant	= (*m_pParameters)("SEARCH_DIRECTION" )->asInt() == 0 ? -1 : 4;
977 
978 		return( CSG_Parameters_PointSearch::Update() );
979 	}
980 
981 	return( false );
982 }
983 
984 
985 ///////////////////////////////////////////////////////////
986 //														 //
987 ///////////////////////////////////////////////////////////
988 
989 //---------------------------------------------------------
Initialize(CSG_Shapes * pPoints,int zField)990 bool CSG_Parameters_Search_Points::Initialize(CSG_Shapes *pPoints, int zField)
991 {
992 	Finalize();
993 
994 	if( !m_pParameters || !pPoints || pPoints->Get_Count() < 1 )
995 	{
996 		return( false );
997 	}
998 
999 	if( Do_Use_All(true) )
1000 	{
1001 		m_pPoints	= pPoints;
1002 		m_zField	= zField;
1003 
1004 		return( true );
1005 	}
1006 
1007 	return( m_Search.Create(pPoints, zField) );
1008 }
1009 
1010 //---------------------------------------------------------
Finalize(void)1011 bool CSG_Parameters_Search_Points::Finalize(void)
1012 {
1013 	m_pPoints	= NULL;
1014 	m_zField	= -1;
1015 
1016 	m_Radius	= 0.0;
1017 	m_minPoints	= m_maxPoints = 0;
1018 	m_nPoints	= 0;
1019 	m_Quadrant	= -1;
1020 
1021 	m_Search.Destroy();
1022 
1023 	return( true );
1024 }
1025 
1026 
1027 ///////////////////////////////////////////////////////////
1028 //														 //
1029 ///////////////////////////////////////////////////////////
1030 
1031 //---------------------------------------------------------
Set_Location(double x,double y)1032 int CSG_Parameters_Search_Points::Set_Location(double x, double y)
1033 {
1034 	if( Do_Use_All() )	// without search engine
1035 	{
1036 		m_nPoints	= m_pPoints->Get_Count();
1037 	}
1038 	else				// using search engine
1039 	{
1040 		m_nPoints	= (int)m_Search.Select_Nearest_Points(x, y, m_maxPoints, m_Radius, m_Quadrant);
1041 	}
1042 
1043 	return( m_nPoints );
1044 }
1045 
1046 //---------------------------------------------------------
Set_Location(const TSG_Point & p)1047 int CSG_Parameters_Search_Points::Set_Location(const TSG_Point &p)
1048 {
1049 	return( Set_Location(p.x, p.y) );
1050 }
1051 
1052 
1053 ///////////////////////////////////////////////////////////
1054 //														 //
1055 ///////////////////////////////////////////////////////////
1056 
1057 //---------------------------------------------------------
Get_Point(int Index,double & x,double & y,double & z)1058 bool CSG_Parameters_Search_Points::Get_Point(int Index, double &x, double &y, double &z)
1059 {
1060 	if( m_pPoints )	// without search engine
1061 	{
1062 		CSG_Shape	*pPoint	= m_pPoints->Get_Shape(Index);
1063 
1064 		if( !pPoint || pPoint->is_NoData(m_zField) )
1065 		{
1066 			return( false );
1067 		}
1068 
1069 		x	= pPoint->Get_Point(0).x;
1070 		y	= pPoint->Get_Point(0).y;
1071 		z	= m_zField < 0 ? Index : pPoint->asDouble(m_zField);
1072 	}
1073 	else			// using search engine
1074 	{
1075 		if( !m_Search.Get_Selected_Point(Index, x, y, z) )
1076 		{
1077 			return( false );
1078 		}
1079 	}
1080 
1081 	return( true );
1082 }
1083 
1084 
1085 ///////////////////////////////////////////////////////////
1086 //														 //
1087 ///////////////////////////////////////////////////////////
1088 
1089 //---------------------------------------------------------
Get_Points(double x,double y,CSG_Points_Z & Points)1090 bool CSG_Parameters_Search_Points::Get_Points(double x, double y, CSG_Points_Z &Points)
1091 {
1092 	return( Get_Points(CSG_Point(x, y), Points) );
1093 }
1094 
1095 //---------------------------------------------------------
Get_Points(const TSG_Point & p,CSG_Points_Z & Points)1096 bool CSG_Parameters_Search_Points::Get_Points(const TSG_Point &p, CSG_Points_Z &Points)
1097 {
1098 	return( m_Search.Get_Nearest_Points(Points, p, m_maxPoints, m_Radius, m_Quadrant) >= (size_t)m_minPoints );
1099 }
1100 
1101 
1102 ///////////////////////////////////////////////////////////
1103 //														 //
1104 //														 //
1105 //														 //
1106 ///////////////////////////////////////////////////////////
1107 
1108 //---------------------------------------------------------
1109