VM2D 1.14
Vortex methods for 2D flows simulation
Loading...
Searching...
No Matches
cpuNeighborTree.h
Go to the documentation of this file.
1/*--------------------------------*- VM2D -*-----------------*---------------*\
2| ## ## ## ## #### ##### | | Version 1.14 |
3| ## ## ### ### ## ## ## ## | VM2D: Vortex Method | 2026/03/06 |
4| ## ## ## # ## ## ## ## | for 2D Flow Simulation *----------------*
5| #### ## ## ## ## ## | Open Source Code |
6| ## ## ## ###### ##### | https://www.github.com/vortexmethods/VM2D |
7| |
8| Copyright (C) 2017-2026 I. Marchevsky, K. Sokol, E. Ryatina, A. Kolganova |
9*-----------------------------------------------------------------------------*
10| File name: cpuNeighborTree.h |
11| Info: Source code of VM2D |
12| |
13| This file is part of VM2D. |
14| VM2D is free software: you can redistribute it and/or modify it |
15| under the terms of the GNU General Public License as published by |
16| the Free Software Foundation, either version 3 of the License, or |
17| (at your option) any later version. |
18| |
19| VM2D is distributed in the hope that it will be useful, but WITHOUT |
20| ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or |
21| FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License |
22| for more details. |
23| |
24| You should have received a copy of the GNU General Public License |
25| along with VM2D. If not, see <http://www.gnu.org/licenses/>. |
26\*---------------------------------------------------------------------------*/
27
40
41#ifndef CPUNEIGHBORTREE_H
42#define CPUNEIGHBORTREE_H
43
44#include <algorithm>
45#include <cstdint>
46#include <limits>
47#include <vector>
48
49#include "Point2D.h"
50
51namespace VM2D
52{
54 struct NbBox
55 {
56 double minx, miny, maxx, maxy;
57
58 void SetEmpty()
59 {
60 minx = miny = std::numeric_limits<double>::infinity();
61 maxx = maxy = -std::numeric_limits<double>::infinity();
62 }
63
64 void Add(const Point2D& p)
65 {
66 minx = std::min(minx, p[0]); maxx = std::max(maxx, p[0]);
67 miny = std::min(miny, p[1]); maxy = std::max(maxy, p[1]);
68 }
69
70 void Add(const NbBox& b)
71 {
72 minx = std::min(minx, b.minx); maxx = std::max(maxx, b.maxx);
73 miny = std::min(miny, b.miny); maxy = std::max(maxy, b.maxy);
74 }
75
76 bool IsEmpty() const { return minx > maxx; }
77
79 double Dist2(const NbBox& b) const
80 {
81 if (IsEmpty() || b.IsEmpty())
82 return std::numeric_limits<double>::infinity();
83 const double dx = std::max(0.0, std::max(minx - b.maxx, b.minx - maxx));
84 const double dy = std::max(0.0, std::max(miny - b.maxy, b.miny - maxy));
85 return dx * dx + dy * dy;
86 }
87
89 double Dist2(const Point2D& p) const
90 {
91 if (IsEmpty())
92 return std::numeric_limits<double>::infinity();
93 const double dx = std::max(0.0, std::max(minx - p[0], p[0] - maxx));
94 const double dy = std::max(0.0, std::max(miny - p[1], p[1] - maxy));
95 return dx * dx + dy * dy;
96 }
97 };
98
99
101 {
102 public:
103 static const int leafSize = 32;
104
105 int n = 0;
106 int nLeaves = 0;
107 int firstLeaf = 1;
108
109 std::vector<int> idx;
110 std::vector<Point2D> pos;
111 std::vector<NbBox> box;
112
113 int LeafBegin(int leaf) const { return leaf * leafSize; }
114 int LeafEnd(int leaf) const { return std::min(n, (leaf + 1) * leafSize); }
115 const NbBox& LeafBox(int leaf) const { return box[firstLeaf + leaf]; }
116
118 template<typename F>
119 void Build(int n_, F getPos)
120 {
121 n = n_;
122 idx.resize(n);
123 pos.resize(n);
124
125 NbBox all;
126 all.SetEmpty();
127 for (int i = 0; i < n; ++i)
128 all.Add(getPos(i));
129
130 std::vector<uint64_t> keys(n), tmp(n);
131 const double scale = std::max(all.maxx - all.minx, all.maxy - all.miny);
132 const double iscale = (scale > 0.0) ? (65535.0 / scale) : 0.0;
133
134#pragma omp parallel for
135 for (int i = 0; i < n; ++i)
136 {
137 const Point2D& p = getPos(i);
138 const uint32_t ix = (uint32_t)((p[0] - all.minx) * iscale);
139 const uint32_t iy = (uint32_t)((p[1] - all.miny) * iscale);
140 keys[i] = ((uint64_t)((Spread(ix) << 1) | Spread(iy)) << 32) | (uint32_t)i;
141 }
142
143 //поразрядная сортировка по старшим 32 битам (мортоновский код)
144 for (int shift = 32; shift < 64; shift += 8)
145 {
146 size_t cnt[257] = { 0 };
147 for (int i = 0; i < n; ++i)
148 ++cnt[((keys[i] >> shift) & 0xFF) + 1];
149 for (int b = 0; b < 256; ++b)
150 cnt[b + 1] += cnt[b];
151 for (int i = 0; i < n; ++i)
152 tmp[cnt[(keys[i] >> shift) & 0xFF]++] = keys[i];
153 keys.swap(tmp);
154 }
155
156 for (int i = 0; i < n; ++i)
157 {
158 idx[i] = (int)(keys[i] & 0xFFFFFFFFu);
159 pos[i] = getPos(idx[i]);
160 }
161
162 nLeaves = (n + leafSize - 1) / leafSize;
163 firstLeaf = 1;
164 while (firstLeaf < std::max(nLeaves, 1))
165 firstLeaf <<= 1;
166
167 box.resize(2 * firstLeaf);
168#pragma omp parallel for
169 for (int l = 0; l < firstLeaf; ++l)
170 {
171 NbBox& b = box[firstLeaf + l];
172 b.SetEmpty();
173 if (l < nLeaves)
174 for (int k = LeafBegin(l); k < LeafEnd(l); ++k)
175 b.Add(pos[k]);
176 }
177 for (int k = firstLeaf - 1; k >= 1; --k)
178 {
179 box[k] = box[2 * k];
180 box[k].Add(box[2 * k + 1]);
181 }
182 }
183
185 void CollectLeaves(const NbBox& q, double R, std::vector<int>& leaves) const
186 {
187 leaves.clear();
188 if (nLeaves == 0)
189 return;
190 const double R2 = R * R;
191 int stack[64];
192 int top = 0;
193 stack[top++] = 1;
194 while (top > 0)
195 {
196 const int k = stack[--top];
197 if (box[k].Dist2(q) >= R2)
198 continue;
199 if (k >= firstLeaf)
200 leaves.push_back(k - firstLeaf);
201 else
202 {
203 stack[top++] = 2 * k + 1;
204 stack[top++] = 2 * k;
205 }
206 }
207 }
208
209 private:
210 static uint32_t Spread(uint32_t v)
211 {
212 v &= 0x0000FFFF;
213 v = (v | (v << 8)) & 0x00FF00FF;
214 v = (v | (v << 4)) & 0x0F0F0F0F;
215 v = (v | (v << 2)) & 0x33333333;
216 v = (v | (v << 1)) & 0x55555555;
217 return v;
218 }
219 };
220
221}//namespace VM2D
222
223#endif
Заголовочный файл с описанием класса Point2D.
std::vector< int > idx
исходные номера точек в порядке сортировки
int firstLeaf
номер первого листа в неявном бинарном дереве (степень двойки)
std::vector< NbBox > box
прямоугольники узлов: корень 1, потомки узла k — 2k и 2k+1
int LeafBegin(int leaf) const
int LeafEnd(int leaf) const
void Build(int n_, F getPos)
Построение дерева; getPos(i) возвращает координаты i-й точки
void CollectLeaves(const NbBox &q, double R, std::vector< int > &leaves) const
Список листьев, прямоугольники которых находятся на расстоянии меньше R от прямоугольника q.
static const int leafSize
static uint32_t Spread(uint32_t v)
const NbBox & LeafBox(int leaf) const
std::vector< Point2D > pos
координаты точек в порядке сортировки
Габаритный прямоугольник
double Dist2(const Point2D &p) const
Квадрат расстояния до точки
void Add(const Point2D &p)
bool IsEmpty() const
double Dist2(const NbBox &b) const
Квадрат расстояния до другого прямоугольника (для пустого — бесконечность).
void Add(const NbBox &b)