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