MAIA bb96820c
Multiphysics at AIA
Loading...
Searching...
No Matches
kdtree.h
Go to the documentation of this file.
1// Copyright (C) 2024 The m-AIA AUTHORS
2//
3// This file is part of m-AIA (https://git.rwth-aachen.de/aia/m-AIA/m-AIA)
4//
5// SPDX-License-Identifier: LGPL-3.0-only
6
7#include "functions.h"
8#include "pointbox.h"
9
10#ifndef KDTREE_DEFINED
11#define KDTREE_DEFINED
12
20template <class T>
21inline void SWAP(T& a, T& b) {
22 T dum = a;
23 a = b;
24 b = dum;
25}
26
27template <MInt DIM>
28struct Boxnode : Box<DIM> {
31 Boxnode(Point<DIM> mylo, Point<DIM> myhi, MInt mymom, MInt myd1, MInt myd2, MInt myptlo, MInt mypthi)
32 : Box<DIM>(mylo, myhi), mom(mymom), dau1(myd1), dau2(myd2), ptlo(myptlo), pthi(mypthi) {}
33};
34template <MInt DIM>
35MInt selecti(const MInt k, MInt* indx, MInt n, MFloat* arr) {
36 MInt i, ia, ir, j, l, mid;
37 MFloat a;
38
39 l = 0;
40 ir = n - 1;
41 for(;;) {
42 if(ir <= l + 1) {
43 if(ir == l + 1 && arr[indx[ir]] < arr[indx[l]]) SWAP(indx[l], indx[ir]);
44 return indx[k];
45 } else {
46 mid = (l + ir) >> 1;
47 SWAP(indx[mid], indx[l + 1]);
48 if(arr[indx[l]] > arr[indx[ir]]) SWAP(indx[l], indx[ir]);
49 if(arr[indx[l + 1]] > arr[indx[ir]]) SWAP(indx[l + 1], indx[ir]);
50 if(arr[indx[l]] > arr[indx[l + 1]]) SWAP(indx[l], indx[l + 1]);
51 i = l + 1;
52 j = ir;
53 ia = indx[l + 1];
54 a = arr[ia];
55 for(;;) {
56 do
57 i++;
58 while(arr[indx[i]] < a);
59 do
60 j--;
61 while(arr[indx[j]] > a);
62 if(j < i) break;
63 SWAP(indx[i], indx[j]);
64 }
65 indx[l + 1] = indx[j];
66 indx[j] = ia;
67 if(j >= k) ir = j - 1;
68 if(j <= k) l = i;
69 }
70 }
71}
72template <MInt DIM>
73struct KDtree {
74 static const MFloat BIG;
76
77 std::vector<Point<DIM>> ptss;
80
81 std::vector<MInt> ptindx, rptindx;
82 // MInt ccellId;
83 KDtree(std::vector<Point<DIM>>& pts);
85 if(boxes != nullptr) delete[] boxes;
86 ptss.clear();
87 }
88 MFloat disti(MInt jpt, MInt kpt);
92 void nnearest(MInt jpt, MInt* nn, MFloat* dn, MInt n);
93 static void sift_down(MFloat* heap, MInt* ndx, MInt nn);
94 MInt locatenear(Point<DIM> pt, MFloat r, MInt* list, MInt nmax, MBool returnCellId = true);
95 MInt locatenearest(Point<DIM> pt, MFloat r, MInt* list, MFloat* dn, MInt nmax, MBool& overflow);
96};
97
98template <MInt DIM>
99const MFloat KDtree<DIM>::BIG(1.0e99);
100template <MInt DIM>
102 : ptss(pts), boxes(nullptr), npts(pts.size()), ptindx(npts), rptindx(npts) {
103 MInt ntmp, m, k, kk, j, nowtask, jbox, np, tmom, tdim, ptlo, pthi;
104 MInt* hp;
105 MFloat* cp;
106 MInt taskmom[50], taskdim[50];
107 if(npts == 0) return;
108 for(k = 0; k < npts; k++)
109 ptindx[k] = k;
110 m = 1;
111 for(ntmp = npts; ntmp; ntmp >>= 1) {
112 m <<= 1;
113 }
114 nboxes = 2 * npts - (m >> 1);
115 if(m < nboxes) nboxes = m;
116 nboxes--;
117 if(nboxes > 0) {
119 MFloat* coords = new MFloat[DIM * npts];
120 for(j = 0, kk = 0; j < DIM; j++, kk += npts) {
121 for(k = 0; k < npts; k++)
122 coords[kk + k] = pts[k].x[j];
123 }
124 Point<DIM> lo(-BIG, -BIG, -BIG), hi(BIG, BIG, BIG);
125 boxes[0] = Boxnode<DIM>(lo, hi, 0, 0, 0, 0, npts - 1);
126 jbox = 0;
127 taskmom[1] = 0;
128 taskdim[1] = 0;
129 nowtask = 1;
130 while(nowtask) {
131 tmom = taskmom[nowtask];
132 tdim = taskdim[nowtask--];
133 ptlo = boxes[tmom].ptlo;
134 pthi = boxes[tmom].pthi;
135 hp = &ptindx[ptlo];
136 cp = &coords[tdim * npts];
137 np = pthi - ptlo + 1;
138 kk = (np - 1) / 2;
139 (void)selecti<DIM>(kk, hp, np, cp);
140 hi = boxes[tmom].hi;
141 lo = boxes[tmom].lo;
142 hi.x[tdim] = lo.x[tdim] = coords[tdim * npts + hp[kk]];
143 if(jbox < nboxes - 1) boxes[++jbox] = Boxnode<DIM>(boxes[tmom].lo, hi, tmom, 0, 0, ptlo, ptlo + kk);
144 if(jbox < nboxes - 1) boxes[++jbox] = Boxnode<DIM>(lo, boxes[tmom].hi, tmom, 0, 0, ptlo + kk + 1, pthi);
145 if(tmom < nboxes) boxes[tmom].dau1 = jbox - 1;
146 if(tmom < nboxes) boxes[tmom].dau2 = jbox;
147 if(kk > 1) {
148 taskmom[++nowtask] = jbox - 1;
149 taskdim[nowtask] = (tdim + 1) % DIM;
150 }
151 if(np - kk > 3) {
152 taskmom[++nowtask] = jbox;
153 taskdim[nowtask] = (tdim + 1) % DIM;
154 }
155 }
156 for(j = 0; j < npts; j++)
157 rptindx[ptindx[j]] = j;
158 delete[] coords;
159 }
160}
161template <MInt DIM>
163 if(jpt == kpt)
164 return BIG;
165 else
166 return dist(ptss[jpt], ptss[kpt]);
167}
168template <MInt DIM>
170 MInt nb, d1, jdim;
171 nb = jdim = 0;
172 while(boxes[nb].dau1) {
173 d1 = boxes[nb].dau1;
174 if(pt.x[jdim] <= boxes[d1].hi.x[jdim])
175 nb = d1;
176 else
177 nb = boxes[nb].dau2;
178 // jdim = ++jdim % DIM;
179 ++jdim;
180 jdim %= DIM;
181 }
182 return nb;
183}
184template <MInt DIM>
186 MInt nb, d1, jh;
187 jh = rptindx[jpt];
188 nb = 0;
189 while(boxes[nb].dau1) {
190 d1 = boxes[nb].dau1;
191 if(jh <= boxes[d1].pthi)
192 nb = d1;
193 else
194 nb = boxes[nb].dau2;
195 }
196 return nb;
197}
198template <MInt DIM>
200 MInt i, k, ntask;
201 MInt nrst = 0;
202 MInt task[50];
203 MFloat dnrst = BIG, d;
204 k = locate(pt);
205 for(i = boxes[k].ptlo; i <= boxes[k].pthi; i++) {
206 d = dist(ptss[ptindx[i]], pt);
207 if(d < dnrst) {
208 nrst = ptindx[i];
209 dnrst = d;
210 }
211 }
212 task[1] = 0;
213 ntask = 1;
214 while(ntask) {
215 k = task[ntask--];
216 if(dist(boxes[k], pt) < dnrst) {
217 if(boxes[k].dau1) {
218 task[++ntask] = boxes[k].dau1;
219 task[++ntask] = boxes[k].dau2;
220 } else {
221 for(i = boxes[k].ptlo; i <= boxes[k].pthi; i++) {
222 d = dist(ptss[ptindx[i]], pt);
223 if(d < dnrst) {
224 nrst = ptindx[i];
225 dnrst = d;
226 }
227 }
228 }
229 }
230 }
231 dist1 = dist(ptss[nrst], pt); // gives the distance!
232 return ptss[nrst].cellId; // nrst;
233}
234template <MInt DIM>
235void KDtree<DIM>::nnearest(MInt jpt, MInt* nn, MFloat* dn, MInt n) {
236 MInt i, k, ntask, kp;
237 MInt task[50];
238 MFloat d;
239 ASSERT(!(n > npts - 1), "too many neighbors requested");
240 for(i = 0; i < n; i++)
241 nn[i] = -1;
242 for(i = 0; i < n; i++)
243 dn[i] = BIG;
244 if(npts == 0) {
245 return;
246 }
247 if(npts == 1) {
248 nn[0] = ptss[ptindx[0]].cellId;
249 dn[0] = disti(ptindx[0], jpt);
250 return;
251 } else if(npts == 2) {
252 MInt smaller = (disti(ptindx[0], jpt) < disti(ptindx[1], jpt)) ? 0 : 1;
253 MInt other = (smaller + 1) % 2;
254 nn[0] = ptss[ptindx[smaller]].cellId;
255 dn[0] = disti(ptindx[smaller], jpt);
256 if(n > 1) {
257 nn[1] = ptss[ptindx[other]].cellId;
258 dn[1] = disti(ptindx[other], jpt);
259 }
260 return;
261 }
262 kp = boxes[locate(jpt)].mom;
263 while(boxes[kp].pthi - boxes[kp].ptlo < n)
264 kp = boxes[kp].mom;
265 for(i = boxes[kp].ptlo; i <= boxes[kp].pthi; i++) {
266 if(jpt == ptindx[i]) continue;
267 d = disti(ptindx[i], jpt);
268 if(d < dn[0]) {
269 dn[0] = d;
270 nn[0] = ptindx[i];
271 if(n > 1) sift_down(dn, nn, n);
272 }
273 }
274 task[1] = 0;
275 ntask = 1;
276 while(ntask) {
277 k = task[ntask--];
278 if(k == kp) continue;
279 if(dist(boxes[k], ptss[jpt]) < dn[0]) {
280 if(boxes[k].dau1) {
281 task[++ntask] = boxes[k].dau1;
282 task[++ntask] = boxes[k].dau2;
283 } else {
284 for(i = boxes[k].ptlo; i <= boxes[k].pthi; i++) {
285 d = disti(ptindx[i], jpt);
286 if(d < dn[0]) {
287 dn[0] = d;
288 nn[0] = ptindx[i];
289 if(n > 1) sift_down(dn, nn, n);
290 }
291 }
292 }
293 }
294 }
295 for(i = 0; i < n; i++)
296 nn[i] = (nn[i] > -1) ? ptss[nn[i]].cellId : -1;
297 return;
298}
299template <MInt DIM>
300void KDtree<DIM>::sift_down(MFloat* heap, MInt* ndx, MInt nn) {
301 MInt n = nn - 1;
302 MInt j, jold, ia;
303 MFloat a;
304 a = heap[0];
305 ia = ndx[0];
306 jold = 0;
307 j = 1;
308 while(j <= n) {
309 if(j < n && heap[j] < heap[j + 1]) j++;
310 if(a >= heap[j]) break;
311 heap[jold] = heap[j];
312 ndx[jold] = ndx[j];
313 jold = j;
314 j = 2 * j + 1;
315 }
316 heap[jold] = a;
317 ndx[jold] = ia;
318}
319template <MInt DIM>
320MInt KDtree<DIM>::locatenear(Point<DIM> pt, MFloat r, MInt* list, MInt nmax, MBool returnCellId) {
321 MInt k, i, nb, nbold, nret, ntask, jdim, d1, d2;
322 MInt task[50];
323 nb = jdim = nret = 0;
324 ASSERT(!(r < 0.0), "radius must be nonnegative");
325 ASSERT(nmax > 0, "");
326 if(npts == 0) {
327 return 0;
328 } else if(npts == 1) {
329 if(dist(ptss[ptindx[0]], pt) < r && nmax > 0) list[nret++] = ptss[ptindx[0]].cellId;
330 } else if(npts == 2) {
331 if(dist(ptss[ptindx[0]], pt) < r && nmax > 0) list[nret++] = ptss[ptindx[0]].cellId;
332 if(dist(ptss[ptindx[1]], pt) < r && nmax > 1) list[nret++] = ptss[ptindx[1]].cellId;
333 } else {
334 while(boxes[nb].dau1) {
335 nbold = nb;
336 d1 = boxes[nb].dau1;
337 d2 = boxes[nb].dau2;
338 if(pt.x[jdim] + r <= boxes[d1].hi.x[jdim])
339 nb = d1;
340 else if(pt.x[jdim] - r >= boxes[d2].lo.x[jdim])
341 nb = d2;
342 // jdim = ++jdim % DIM;//undefined behavior
343 jdim = (jdim + 1) % DIM;
344 if(nb == nbold) break;
345 }
346 task[1] = nb;
347 ntask = 1;
348 while(ntask) {
349 k = task[ntask--];
350 if(dist(boxes[k], pt) > r) continue;
351 if(boxes[k].dau1) {
352 task[++ntask] = boxes[k].dau1;
353 task[++ntask] = boxes[k].dau2;
354 } else {
355 for(i = boxes[k].ptlo; i <= boxes[k].pthi; i++) {
356 if(dist(ptss[ptindx[i]], pt) <= r && nret < nmax) {
357 if(returnCellId) {
358 list[nret++] = ptss[ptindx[i]].cellId;
359 } else {
360 list[nret++] = ptindx[i];
361 }
362 }
363
364 if(nret == nmax) return nmax;
365 }
366 }
367 }
368 }
369 return nret;
370}
371template <MInt DIM>
373 MInt k, i, nb, nbold, nret, ntask, jdim, d1, d2;
374 MInt task[50];
375 nb = jdim = nret = 0;
376 overflow = false;
377 ASSERT(!(r < 0.0), "radius must be nonnegative");
378 ASSERT(nmax > 0, "");
379 if(npts == 0) {
380 return 0;
381 } else if(npts == 1) {
382 if(dist(ptss[ptindx[0]], pt) < r && nmax > 0) list[nret++] = ptss[ptindx[0]].cellId;
383 } else if(npts == 2) {
384 MInt smaller = (dist(ptss[ptindx[0]], pt) < dist(ptss[ptindx[1]], pt)) ? 0 : 1;
385 MInt other = (smaller + 1) % 2;
386 if(dist(ptss[ptindx[smaller]], pt) < r && nmax > 0) list[nret++] = ptss[ptindx[smaller]].cellId;
387 if(dist(ptss[ptindx[other]], pt) < r && nmax > 1) list[nret++] = ptss[ptindx[other]].cellId;
388 } else {
389 while(boxes[nb].dau1) {
390 nbold = nb;
391 d1 = boxes[nb].dau1;
392 d2 = boxes[nb].dau2;
393 if(pt.x[jdim] + r <= boxes[d1].hi.x[jdim])
394 nb = d1;
395 else if(pt.x[jdim] - r >= boxes[d2].lo.x[jdim])
396 nb = d2;
397 // jdim = ++jdim % DIM;//undefined behavior
398 jdim = (jdim + 1) % DIM;
399 if(nb == nbold) break;
400 }
401 task[1] = nb;
402 ntask = 1;
403 while(ntask) {
404 k = task[ntask--];
405 if(dist(boxes[k], pt) > r) continue;
406 if(boxes[k].dau1) {
407 task[++ntask] = boxes[k].dau1;
408 task[++ntask] = boxes[k].dau2;
409 } else {
410 for(i = boxes[k].ptlo; i <= boxes[k].pthi; i++) {
411 MFloat dst = dist(ptss[ptindx[i]], pt);
412 if(dst < r) {
413 if(nret == nmax) overflow = true;
414 MInt s = 0;
415 for(s = 0; s < nret; s++) {
416 if(dst < dn[s]) {
417 for(MInt t = std::min(nret, nmax - 1); t > s; t--) {
418 list[t] = list[t - 1];
419 dn[t] = dn[t - 1];
420 }
421 break;
422 }
423 }
424 if(s < nmax) {
425 list[s] = ptss[ptindx[i]].cellId;
426 dn[s] = dst;
427 }
428 if(nret < nmax) nret++;
429 }
430 }
431 }
432 }
433 }
434 return nret;
435}
436
437#endif
void SWAP(T &a, T &b)
Definition: kdtree.h:21
MInt selecti(const MInt k, MInt *indx, MInt n, MFloat *arr)
Definition: kdtree.h:35
int32_t MInt
Definition: maiatypes.h:62
double MFloat
Definition: maiatypes.h:52
int64_t MLong
Definition: maiatypes.h:64
bool MBool
Definition: maiatypes.h:58
MFloat dist(const Point< DIM > &p, const Point< DIM > &q)
Definition: pointbox.h:54
Definition: pointbox.h:48
Definition: kdtree.h:28
MInt mom
Definition: kdtree.h:29
MInt ptlo
Definition: kdtree.h:29
MInt dau2
Definition: kdtree.h:29
MInt pthi
Definition: kdtree.h:29
Boxnode()
Definition: kdtree.h:30
MInt dau1
Definition: kdtree.h:29
Boxnode(Point< DIM > mylo, Point< DIM > myhi, MInt mymom, MInt myd1, MInt myd2, MInt myptlo, MInt mypthi)
Definition: kdtree.h:31
Definition: kdtree.h:73
Boxnode< DIM > * boxes
Definition: kdtree.h:78
static void sift_down(MFloat *heap, MInt *ndx, MInt nn)
Definition: kdtree.h:300
MInt locate(MInt jpt)
Definition: kdtree.h:185
~KDtree()
Definition: kdtree.h:84
MInt nearest(Point< DIM > pt, MFloat &dist)
Definition: kdtree.h:199
MInt locatenear(Point< DIM > pt, MFloat r, MInt *list, MInt nmax, MBool returnCellId=true)
Definition: kdtree.h:320
std::vector< Point< DIM > > ptss
Definition: kdtree.h:77
MLong npts
Definition: kdtree.h:79
KDtree(std::vector< Point< DIM > > &pts)
Definition: kdtree.h:101
MInt locate(Point< DIM > pt)
Definition: kdtree.h:169
MLong nboxes
Definition: kdtree.h:75
MFloat disti(MInt jpt, MInt kpt)
Definition: kdtree.h:162
MInt locatenearest(Point< DIM > pt, MFloat r, MInt *list, MFloat *dn, MInt nmax, MBool &overflow)
Definition: kdtree.h:372
std::vector< MInt > ptindx
Definition: kdtree.h:81
static const MFloat BIG
Definition: kdtree.h:74
void nnearest(MInt jpt, MInt *nn, MFloat *dn, MInt n)
Definition: kdtree.h:235
std::vector< MInt > rptindx
Definition: kdtree.h:81
Definition: pointbox.h:20
MFloat x[DIM]
Definition: pointbox.h:21
Definition: contexttypes.h:19