├── .github
└── workflows
│ ├── build-linux.yml
│ └── build-windows.yml
├── CMakeLists.txt
├── LICENSE
├── README.md
├── demo
├── CMakeLists.txt
└── main.cpp
├── extern
└── libmorton
│ ├── LICENSE
│ ├── README.md
│ └── libmorton
│ └── include
│ ├── morton.h
│ ├── morton2D.h
│ ├── morton2D_LUTs.h
│ ├── morton3D.h
│ ├── morton3D_LUTs.h
│ ├── morton_BMI.h
│ ├── morton_LUT_generators.h
│ └── morton_common.h
├── include
├── CompactNSearch
├── CompactNSearch.h
├── Config.h
├── DataStructures.h
└── PointSet.h
└── src
└── CompactNSearch.cpp
/.github/workflows/build-linux.yml:
--------------------------------------------------------------------------------
1 | name: build-linux
2 |
3 | on: [push]
4 |
5 | jobs:
6 | build-ubuntu:
7 |
8 | runs-on: ubuntu-latest
9 |
10 | steps:
11 | - uses: actions/checkout@v1
12 | - name: configure
13 | run: mkdir build-release && cd build-release && cmake -DCMAKE_BUILD_TYPE=Release ..
14 | - name: build
15 | run: cmake --build build-release
16 |
17 |
--------------------------------------------------------------------------------
/.github/workflows/build-windows.yml:
--------------------------------------------------------------------------------
1 | name: build-windows
2 |
3 | on: [push]
4 |
5 | jobs:
6 | build-windows:
7 |
8 | runs-on: ${{ matrix.os }}
9 | strategy:
10 | matrix:
11 | os: [windows-latest]
12 |
13 | steps:
14 | - uses: actions/checkout@v1
15 | - name: configure
16 | run: mkdir build-release;cd build-release;cmake ..
17 | shell: pwsh
18 | - name: build
19 | run: cmake --build build-release --config Release
20 |
21 |
22 |
--------------------------------------------------------------------------------
/CMakeLists.txt:
--------------------------------------------------------------------------------
1 | cmake_minimum_required(VERSION 3.2)
2 |
3 | project(CompactNSearch)
4 |
5 | # Visual studio solution directories.
6 | set_property(GLOBAL PROPERTY USE_FOLDERS on)
7 |
8 | set(CMAKE_CXX_STANDARD 11)
9 | set(CMAKE_CXX_STANDARD_REQUIRED ON)
10 |
11 | if (UNIX)
12 | find_package(OpenMP)
13 | if (OPENMP_FOUND)
14 | if (CMAKE_VERSION VERSION_GREATER "3.8")
15 | link_libraries(OpenMP::OpenMP_CXX)
16 | else()
17 | set (CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} ${OpenMP_CXX_FLAGS}")
18 | endif()
19 | endif(OPENMP_FOUND)
20 | endif (UNIX)
21 |
22 | OPTION(BUILD_AS_SHARED_LIBS "Build all the libraries as shared" OFF)
23 | if (BUILD_AS_SHARED_LIBS)
24 | if(WIN32)
25 | add_definitions(-DCMAKE_WINDOWS_EXPORT_ALL_SYMBOLS)
26 | set(CMAKE_WINDOWS_EXPORT_ALL_SYMBOLS YES CACHE BOOL "Export all symbols")
27 | endif(WIN32)
28 | endif (BUILD_AS_SHARED_LIBS)
29 |
30 | SET(CMAKE_DEBUG_POSTFIX "_d")
31 |
32 | set (HEADER_FILES
33 | include/Config.h
34 | include/CompactNSearch.h
35 | include/PointSet.h
36 | include/DataStructures.h)
37 |
38 | if (BUILD_AS_SHARED_LIBS)
39 | add_library(CompactNSearch SHARED
40 | ${HEADER_FILES}
41 | src/CompactNSearch.cpp
42 | )
43 | else()
44 | add_library(CompactNSearch
45 | ${HEADER_FILES}
46 | src/CompactNSearch.cpp
47 | )
48 | endif ()
49 |
50 | target_include_directories(CompactNSearch PUBLIC include)
51 |
52 | if (APPLE AND CMAKE_CXX_COMPILER_ID MATCHES "Clang")
53 | find_package(oneDPL REQUIRED)
54 | target_link_libraries(CompactNSearch PUBLIC oneDPL)
55 | endif()
56 |
57 | install(FILES "include/CompactNSearch" ${HEADER_FILES}
58 | DESTINATION include/)
59 |
60 | install(TARGETS CompactNSearch
61 | RUNTIME DESTINATION bin
62 | LIBRARY DESTINATION lib
63 | ARCHIVE DESTINATION lib)
64 |
65 | OPTION(USE_DOUBLE_PRECISION "Use double precision" ON)
66 | if (USE_DOUBLE_PRECISION)
67 | add_definitions( -DUSE_DOUBLE)
68 | endif (USE_DOUBLE_PRECISION)
69 |
70 | option(BUILD_DEMO "Build example of how to use this library."
71 | ON)
72 | if(BUILD_DEMO)
73 | add_subdirectory(demo)
74 | endif(BUILD_DEMO)
75 |
76 |
--------------------------------------------------------------------------------
/LICENSE:
--------------------------------------------------------------------------------
1 | The MIT License (MIT)
2 |
3 | Copyright (c) 2016-present, CompactNSearch contributors
4 |
5 | Permission is hereby granted, free of charge, to any person obtaining a copy
6 | of this software and associated documentation files (the "Software"), to deal
7 | in the Software without restriction, including without limitation the rights
8 | to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
9 | copies of the Software, and to permit persons to whom the Software is
10 | furnished to do so, subject to the following conditions:
11 |
12 | The above copyright notice and this permission notice shall be included in all
13 | copies or substantial portions of the Software.
14 |
15 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
16 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
17 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
18 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
19 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
20 | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
21 | SOFTWARE.
22 |
23 |
--------------------------------------------------------------------------------
/README.md:
--------------------------------------------------------------------------------
1 | # CompactNSearch
2 |
3 |

4 |
5 | **CompactNSearch** is a C++ library for **parallel** computation of neighboring points in a **fixed radius** in a **three-dimensional point cloud**. The implemented algorithm is a variant of the *Compact Hashing* approach proposed by Ihmsen et al. [IABT11]. The neighborhood information can be efficiently updated when the points spatially move. Moreover, the library offers the possibility to reorder the points (and other array-stored per point information) according to a space-filling Z curve to improve the cache efficiency in later queries or accesses.
6 |
7 | The library was used to generate all results of the SPH-based fluid simulations presented by Bender and Koschier in [BK15, BK16].
8 |
9 | **Author**: Dan Koschier, **License**: MIT
10 |
11 | ## Libraries using CompactNSearch
12 | * [PBD] - A C++ library for physically-based simulation of rigid bodies, deformables, cloth and fluids using Position-Based Dynamics
13 | * [SPlisHSPlasH] - A C++ library for the physically-based simulation of fluids using Smoothed Particle Hydrodynamics (cf. video) (Coming soon)
14 |
15 | [](https://www.youtube.com/watch?v=POnmzzhc5E0)
16 |
17 | ## Build Instructions
18 |
19 | This project is based on [CMake](https://cmake.org/). Simply generate project, Makefiles, etc. using [CMake](https://cmake.org/) and compile the project with the compiler of your choice. The code was tested with the following configurations:
20 | - Windows 10 64-bit, CMake 3.7, Visual Studio 2015
21 | - Debian 8 64-bit, CMake 3.7, GCC 4.9.2.
22 |
23 | ## Usage
24 | A data structure to perform a neighborhood search can be created by calling the constructor given a fixed search radius ```r```.
25 | ```c++
26 | CompactNSearch::NeighborhoodSearch nsearch(r);
27 | ```
28 | An arbitrary number of point clouds can then be added to the data structure using the method ```add_point_set```. The library expects the point positions to be contiguously stored in an array-like structure. The method will return a unique id associated with the initialized point set.
29 | ```c++
30 | // ... Fill array with 3 * n real numbers representing three-dimensional point positions.
31 | std::vector> point_set_1;
32 | std::vector> point_set_2;
33 |
34 | unsigned int point_set_1_id = nsearch.add_point_set(point_set_1.front().data(), positions.size());
35 | unsigned int point_set_2_id = nsearch.add_point_set(point_set_2.front().data(), positions.size());
36 | ```
37 | In order to generate the neighborhood information simply execute the following command
38 | ```c++
39 | nsearch.find_neighbors();
40 | ```
41 | Finally, the neighborhood information can be accessed as follows
42 | ```c++
43 | CompactNSearch::PointSet const& ps_1 = nsearch.point_set(point_set_1_id);
44 | for (int i = 0; i < ps_1.n_points(); ++i)
45 | {
46 | // Get point set 1 neighbors of point set 1.
47 | for (size_t j = 0; j < ps_1.n_neighbors(point_set_1_id, i); ++j)
48 | {
49 | // Return the point id of the jth neighbor of the ith particle in the point_set_1.
50 | const unsigned int pid = ps_1.neighbor(point_set_1_id, i, j);
51 | }
52 |
53 | // Get point set 2 neighbors of point set 1.
54 | for (size_t j = 0; j < ps_1.n_neighbors(point_set_2_id, i); ++j)
55 | {
56 | // Return the point id of the jth neighbor of the ith particle in the point_set_1.
57 | const unsigned int pid = ps_1.neighbor(point_set_2_id, i, j);
58 | }
59 | }
60 | ```
61 |
62 | Besides the basic functionality the library offers to compute a rule for reordering the points according to a space-filling Z curve. The reordering will improve the performance of future neighborhood queries and accesses. The rule can be computed via
63 | ```c++
64 | nsearch.z_sort();
65 | ```
66 | Please note that the actual reordering must be invoked by the user by
67 | ```c++
68 | ps_1.sort_field(positions.data());
69 | ```
70 | Assuming that there is additional information stored per-point (e.g. velocity, color, mass etc.) the information **must** also be reorded using the same method to maintain consistency. Subsequently, the ```find_neighbors``` function has to be invoked again to update the neighborhood information.
71 |
72 | Another self-explaining (benchmark) [demo](demo/main.cpp) is contained in the project.
73 |
74 | ## Activation Table
75 |
76 | When maintaining multiple it is sometimes desired that only certain point sets can find points from other point sets. Therefore an activation table is implemented where the user can specify whether a point set i searches points in another point set j. When nothing else is specified all point sets will search points in all other point sets. The activation table can be modified with e.g.
77 | ```c++
78 | // Point set 2 will not look for neighbors within its own points
79 | nsearch.set_active(point_set_2_id, point_set_2_id, false)
80 | ```
81 |
82 | ## References
83 |
84 | * [IABT11] M. Ihmsen, N. Akinci, M. Becker and M. Teschner, 2011. "A Parallel SPH Implementation on Multi-Core CPUs", Computer Graphics Forum 30, 1, 99-112.
85 | * [BK15] J. Bender and D. Koschier 2015. "Divergence-Free Smoothed Particle Hydrodynamics", ACM SIGGRAPH / Eurographics Symposium on Computer Animation, 1-9
86 | * [BK17] J. Bender and D. Koschier, 2017. "Divergence-Free SPH for Incompressible and Viscous Fluids", IEEE Transactions on Visualization and Computer Graphics.
87 |
88 | [PBD]:
89 | [SPlisHSPlasH]:
90 |
--------------------------------------------------------------------------------
/demo/CMakeLists.txt:
--------------------------------------------------------------------------------
1 |
2 |
3 | add_definitions(-D_USE_MATH_DEFINES)
4 |
5 | include_directories("../include")
6 |
7 | add_executable(Demo
8 | main.cpp
9 | )
10 |
11 | target_link_libraries(Demo CompactNSearch)
12 |
--------------------------------------------------------------------------------
/demo/main.cpp:
--------------------------------------------------------------------------------
1 |
2 | #include
3 |
4 | #include
5 | #include
6 | #include
7 | #include
8 | #include
9 | #include
10 | #include
11 |
12 | #include
13 |
14 | using namespace CompactNSearch;
15 |
16 | std::vector> positions;
17 |
18 | std::size_t const N = 30;
19 | //std::size_t const N = 5;
20 | Real const r_omega = static_cast(0.15);
21 | Real const r_omega2 = r_omega * r_omega;
22 | Real const radius = static_cast(2.0) * (static_cast(2.0) * r_omega / static_cast(N-1));
23 |
24 | std::size_t const N_enright_steps = 50;
25 |
26 | Real
27 | compute_average_number_of_neighbors(NeighborhoodSearch const& nsearch)
28 | {
29 | unsigned long res = 0;
30 | auto const& d = nsearch.point_set(0);
31 | for (int i = 0; i < d.n_points(); ++i)
32 | {
33 | res += static_cast(d.n_neighbors(0, i));
34 | }
35 | return static_cast(res) / static_cast(d.n_points());
36 | }
37 |
38 | Real
39 | compute_average_distance(NeighborhoodSearch const& nsearch)
40 | {
41 | unsigned long long res = 0;
42 | auto const& d = nsearch.point_set(0);
43 | unsigned long long count = 0;
44 | for (int i = 0; i < d.n_points(); ++i)
45 | {
46 | std::size_t nn = d.n_neighbors(0, i);
47 | for (int j = 0; j < nn; ++j)
48 | {
49 | unsigned int k = d.neighbor(0, i, j);
50 | res += std::abs(i - static_cast(k));
51 | count++;
52 | }
53 | }
54 | return static_cast(res) / static_cast(count);
55 | }
56 |
57 | std::vector>
58 | brute_force_search(std::size_t n_positions)
59 | {
60 | std::vector> brute_force_neighbors(n_positions);
61 | for (int i = 0; i < n_positions; ++i)
62 | {
63 | std::vector& neighbors = brute_force_neighbors[i];
64 | for (int j = 0; j < n_positions; ++j)
65 | {
66 | if (i == j)
67 | continue;
68 | std::array const& xa = positions[i];
69 | std::array const& xb = positions[j];
70 | Real l2 =
71 | (xa[0] - xb[0])*(xa[0] - xb[0]) +
72 | (xa[1] - xb[1])*(xa[1] - xb[1]) +
73 | (xa[2] - xb[2])*(xa[2] - xb[2]);
74 | if (l2 <= radius * radius)
75 | {
76 | neighbors.push_back(j);
77 | }
78 | }
79 | }
80 | return std::move(brute_force_neighbors);
81 | }
82 |
83 | void
84 | compare_with_bruteforce_search(NeighborhoodSearch const& nsearch)
85 | {
86 | PointSet const& d0 = nsearch.point_set(0);
87 | auto brute_force_neighbors = brute_force_search(d0.n_points());
88 | for (int i = 0; i < d0.n_points(); ++i)
89 | {
90 | auto const& bfn = brute_force_neighbors[i];
91 | if (bfn.size() != d0.n_neighbors(0, i))
92 | {
93 | std::cerr << "ERROR: Not the same number of neighbors." << std::endl;
94 | }
95 | for (int j = 0; j < d0.n_neighbors(0, i); ++j)
96 | {
97 | if (std::find(bfn.begin(), bfn.end(), d0.neighbor(0, i, j)) == bfn.end())
98 | {
99 | std::cerr << "ERROR: Neighbor not found in brute force list." << std::endl;
100 | }
101 | }
102 | }
103 | }
104 |
105 | void
106 | compare_single_query_with_bruteforce_search(NeighborhoodSearch& nsearch)
107 | {
108 | std::vector> neighbors;
109 | PointSet const& d0 = nsearch.point_set(0);
110 | auto brute_force_neighbors = brute_force_search(d0.n_points());
111 | for (int i = 0; i < d0.n_points(); ++i)
112 | {
113 | auto const& bfn = brute_force_neighbors[i];
114 | neighbors.clear();
115 | nsearch.find_neighbors(0, i, neighbors);
116 | if (bfn.size() != neighbors[0].size())
117 | {
118 | std::cerr << "ERROR: Not the same number of neighbors." << std::endl;
119 | }
120 | for (int j = 0; j < neighbors.size(); ++j)
121 | {
122 | if (std::find(bfn.begin(), bfn.end(), neighbors[0][j]) == bfn.end())
123 | {
124 | std::cerr << "ERROR: Neighbor not found in brute force list." << std::endl;
125 | }
126 | }
127 | }
128 | }
129 |
130 |
131 | std::array
132 | enright_velocity_field(std::array const& x)
133 | {
134 | Real sin_pi_x_2 = std::sin(static_cast(M_PI) * x[0]);
135 | Real sin_pi_y_2 = std::sin(static_cast(M_PI) * x[1]);
136 | Real sin_pi_z_2 = std::sin(static_cast(M_PI) * x[2]);
137 | sin_pi_x_2 *= sin_pi_x_2;
138 | sin_pi_y_2 *= sin_pi_y_2;
139 | sin_pi_z_2 *= sin_pi_z_2;
140 |
141 | Real sin_2_pi_x = static_cast(std::sin(static_cast(2.0 * M_PI) * x[0]));
142 | Real sin_2_pi_y = static_cast(std::sin(static_cast(2.0 * M_PI) * x[1]));
143 | Real sin_2_pi_z = static_cast(std::sin(static_cast(2.0 * M_PI) * x[2]));
144 | return {{
145 | static_cast(2.0) * sin_pi_x_2 * sin_2_pi_y * sin_2_pi_z,
146 | -sin_2_pi_x * sin_pi_y_2 * sin_2_pi_z,
147 | -sin_2_pi_x * sin_2_pi_y * sin_pi_z_2}};
148 |
149 | }
150 |
151 | void
152 | advect()
153 | {
154 | #ifdef _MSC_VER
155 | concurrency::parallel_for_each(
156 | #elif defined(__APPLE__) && defined(__clang__)
157 | std::for_each(oneapi::dpl::execution::par,
158 | #else
159 | __gnu_parallel::for_each(
160 | #endif
161 | positions.begin(), positions.end(), [&](std::array& x)
162 | {
163 | std::array v = enright_velocity_field(x);
164 | x[0] += static_cast(0.005) * v[0];
165 | x[1] += static_cast(0.005) * v[1];
166 | x[2] += static_cast(0.005) * v[1];
167 | }
168 | );
169 | }
170 |
171 | int main(int argc, char* argv[])
172 | {
173 | Real min_x = std::numeric_limits::max();
174 | Real max_x = std::numeric_limits::min();
175 | positions.reserve(N * N * N);
176 | for (unsigned int i = 0; i < N; ++i)
177 | {
178 | for (unsigned int j = 0; j < N; ++j)
179 | {
180 | for (unsigned int k = 0; k < N; ++k)
181 | {
182 | std::array x = {{
183 | r_omega * (static_cast(2.0) * static_cast(i) / static_cast(N-1)-static_cast(1.0)),
184 | r_omega * (static_cast(2.0) * static_cast(j) / static_cast(N-1)-static_cast(1.0)),
185 | r_omega * (static_cast(2.0) * static_cast(k) / static_cast(N-1)-static_cast(1.0))}};
186 |
187 | Real l2 = x[0] * x[0] + x[1] * x[1] + x[2] * x[2];
188 | if (l2 < r_omega2)
189 | {
190 | x[0] += static_cast(0.35);
191 | x[1] += static_cast(0.35);
192 | x[2] += static_cast(0.35);
193 | positions.push_back(x);
194 | if (min_x > x[0])
195 | {
196 | min_x = x[0];
197 | }
198 | if (max_x < x[0])
199 | {
200 | max_x = x[0];
201 | }
202 | }
203 | }
204 | }
205 | }
206 | std::random_shuffle(positions.begin(), positions.end());
207 |
208 | NeighborhoodSearch nsearch(radius, true);
209 | nsearch.add_point_set(positions.front().data(), positions.size(), true, true);
210 | nsearch.add_point_set(positions.front().data(), positions.size(), true, true);
211 | nsearch.find_neighbors();
212 |
213 | nsearch.update_point_sets();
214 | std::vector> neighbors2;
215 | nsearch.find_neighbors(0, 1, neighbors2);
216 | std::vector> neighbors3;
217 | nsearch.find_neighbors(1, 2, neighbors3);
218 |
219 | std::cout << "#Points = " << positions.size() << std::endl;
220 | std::cout << "Search radius = " << radius << std::endl;
221 | std::cout << "Min x = " << min_x << std::endl;
222 | std::cout << "Max x = " << max_x << std::endl;
223 | std::cout << "Average number of neighbors = " << compute_average_number_of_neighbors(nsearch) << std::endl;
224 | std::cout << "Average index distance prior to z-sort = " << compute_average_distance(nsearch) << std::endl;
225 |
226 | nsearch.z_sort();
227 | for (auto i = 0u; i < nsearch.n_point_sets(); ++i)
228 | {
229 | auto const& d = nsearch.point_set(i);
230 | d.sort_field(positions.data());
231 |
232 | }
233 | nsearch.find_neighbors();
234 |
235 | //compare_single_query_with_bruteforce_search(nsearch);
236 | //compare_with_bruteforce_search(nsearch);
237 |
238 | std::cout << "Average index distance after z-sort = " << compute_average_distance(nsearch) << std::endl;
239 |
240 | std::cout << "Moving points:" << std::endl;
241 | for (int i = 0; i < N_enright_steps; ++i)
242 | {
243 | std::cout << "Enright step " << i << ". ";
244 | advect();
245 | auto t0 = std::chrono::high_resolution_clock::now();
246 | nsearch.find_neighbors();
247 | std::cout << "Neighborhood search took " << std::chrono::duration_cast(std::chrono::high_resolution_clock::now() - t0).count() << "ms" << std::endl;
248 | //compare_with_bruteforce_search(nsearch);
249 | //compare_single_query_with_bruteforce_search(nsearch);
250 | }
251 |
252 | return 0;
253 | }
254 |
--------------------------------------------------------------------------------
/extern/libmorton/LICENSE:
--------------------------------------------------------------------------------
1 | MIT License
2 |
3 | Copyright (c) 2016 Jeroen Baert
4 |
5 | Permission is hereby granted, free of charge, to any person obtaining a copy
6 | of this software and associated documentation files (the "Software"), to deal
7 | in the Software without restriction, including without limitation the rights
8 | to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
9 | copies of the Software, and to permit persons to whom the Software is
10 | furnished to do so, subject to the following conditions:
11 |
12 | The above copyright notice and this permission notice shall be included in all
13 | copies or substantial portions of the Software.
14 |
15 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
16 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
17 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
18 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
19 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
20 | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
21 | SOFTWARE.
22 |
--------------------------------------------------------------------------------
/extern/libmorton/README.md:
--------------------------------------------------------------------------------
1 | # Libmorton
2 |
3 | * Libmorton is a **C++ header-only library** with methods to efficiently encode/decode between 64, 32 and 16-bit morton codes and coordinates, in 2D and 3D. *Morton order* is also known as *Z-order* or *[the Z-order curve](https://en.wikipedia.org/wiki/Z-order_curve)*.
4 | * Libmorton is a **lightweight and portable** library - in its most basic form it only depends on standard C++ headers. Architecture-specific optimizations are implemented incrementally.
5 | * This library is under active development. SHIT MIGHT BREAK.
6 | * More info and some benchmarks in these blogposts:
7 | * http://www.forceflow.be/2016/01/18/libmorton-a-library-for-morton-order-encoding-decoding/
8 | * http://www.forceflow.be/2013/10/07/morton-encodingdecoding-through-bit-interleaving-implementations/
9 |
10 | ## Usage
11 | Just include *libmorton/morton.h*. This will always have functions that point to the most efficient way to encode/decode Morton codes. If you want to test out alternative (and possibly slower) methods, you can find them in *libmorton/morton2D.h* and *libmorton/morton3D.h*.
12 |
13 |
14 | // ENCODING 2D / 3D morton codes, of length 32 and 64 bits
15 | inline uint_fast32_t morton2D_32_encode(const uint_fast16_t x, const uint_fast16_t y);
16 | inline uint_fast64_t morton2D_64_encode(const uint_fast32_t x, const uint_fast32_t y);
17 | inline uint_fast32_t morton3D_32_encode(const uint_fast16_t x, const uint_fast16_t y, const uint_fast16_t z);
18 | inline uint_fast64_t morton3D_64_encode(const uint_fast32_t x, const uint_fast32_t y, const uint_fast32_t z);
19 | // DECODING 2D / 3D morton codes, of length 32 and 64 bits
20 | inline void morton2D_32_decode(const uint_fast32_t morton, uint_fast16_t& x, uint_fast16_t& y);
21 | inline void morton2D_64_decode(const uint_fast64_t morton, uint_fast32_t& x, uint_fast32_t& y);
22 | inline void morton3D_32_decode(const uint_fast32_t morton, uint_fast16_t& x, uint_fast16_t& y, uint_fast16_t& z);
23 | inline void morton3D_64_decode(const uint_fast64_t morton, uint_fast32_t& x, uint_fast32_t& y, uint_fast32_t& z);
24 |
25 |
26 | ## Testing
27 | The *test* folder contains tools I use to test correctness and performance of the libmorton implementation. This section is under heavy re-writing, but might contain some useful code for advanced usage.
28 |
29 | ## TODO
30 | * Write better test suites
31 | * Implement BMI2 instruction set detection and optimization for newer Intel CPU's
32 | * More testing
33 |
--------------------------------------------------------------------------------
/extern/libmorton/libmorton/include/morton.h:
--------------------------------------------------------------------------------
1 | #pragma once
2 |
3 | // This file will always contain pointers to the fastest Morton encoding/decoding implementation
4 | // IF you just want to use the fastest method to encode/decode morton codes, include this
5 |
6 | #include "morton2D.h"
7 | #include "morton3D.h"
8 |
9 | //// ENCODE
10 | //inline uint_fast32_t morton2D_32_encode(const uint_fast16_t x, const uint_fast16_t y);
11 | //inline uint_fast64_t morton2D_64_encode(const uint_fast32_t x, const uint_fast32_t y);
12 | //inline uint_fast32_t morton3D_32_encode(const uint_fast16_t x, const uint_fast16_t y, const uint_fast16_t z);
13 | //inline uint_fast64_t morton3D_64_encode(const uint_fast32_t x, const uint_fast32_t y, const uint_fast32_t z);
14 | //
15 | //// DECODE
16 | //inline void morton2D_32_decode(const uint_fast32_t morton, uint_fast16_t& x, uint_fast16_t& y);
17 | //inline void morton2D_64_decode(const uint_fast64_t morton, uint_fast32_t& x, uint_fast32_t& y);
18 | //inline void morton3D_32_decode(const uint_fast32_t morton, uint_fast16_t& x, uint_fast16_t& y, uint_fast16_t& z);
19 | //inline void morton3D_64_decode(const uint_fast64_t morton, uint_fast32_t& x, uint_fast32_t& y, uint_fast32_t& z);
20 |
21 | // Functions under this are stubs which will always point to fastest implementation at the moment
22 | //-----------------------------------------------------------------------------------------------
23 |
24 | #define morton2D_32_encode m2D_e_sLUT
25 | #define morton2D_64_encode m2D_e_sLUT
26 | #define morton2D_32_decode m2D_d_sLUT
27 | #define morton2D_64_decode m2D_d_sLUT
28 |
29 | #define morton3D_32_encode m3D_e_sLUT
30 | #define morton3D_64_encode m3D_e_sLUT
31 | #define morton3D_32_decode m3D_d_sLUT
32 | #define morton3D_64_decode m3D_d_sLUT
--------------------------------------------------------------------------------
/extern/libmorton/libmorton/include/morton2D.h:
--------------------------------------------------------------------------------
1 | #pragma once
2 |
3 | // Libmorton - Methods to encode/decode 64-bit morton codes from/to 32-bit (x,y) coordinates
4 | // Warning: morton.h will always point to the functions that use the fastest available method.
5 |
6 | #include
7 | #include
8 | #include "morton2D_LUTs.h"
9 | #include "morton_common.h"
10 |
11 | using namespace std;
12 |
13 | // Encode methods
14 | template inline morton m2D_e_sLUT(const coord x, const coord y);
15 | template inline morton m2D_e_sLUT_ET(const coord x, const coord y);
16 | template inline morton m2D_e_LUT(const coord x, const coord y);
17 | template inline morton m2D_e_LUT_ET(const coord x, const coord y);
18 | template inline morton m2D_e_magicbits(const coord x, const coord y);
19 | template inline morton m2D_e_for(const coord x, const coord y);
20 | template inline morton m2D_e_for_ET(const coord x, const coord y);
21 |
22 | // Decode methods
23 | template inline void m2D_d_sLUT(const morton m, coord& x, coord& y);
24 | template inline void m2D_d_sLUT_ET(const morton m, coord& x, coord& y);
25 | template inline void m2D_d_LUT(const morton m, coord& x, coord& y);
26 | template inline void m2D_d_LUT_ET(const morton m, coord& x, coord& y);
27 | template inline void m2D_d_magicbits(const morton m, coord& x, coord& y);
28 | template inline void m2D_d_for(const morton m, coord& x, coord& y);
29 |
30 | // ENCODE 2D Morton code : Pre-shifted LookUpTable (sLUT)
31 | template
32 | inline morton m2D_e_sLUT(const coord x, const coord y) {
33 | morton answer = 0;
34 | const static morton EIGHTBITMASK = 0x000000FF;
35 | for (unsigned int i = sizeof(coord); i > 0; --i) {
36 | unsigned int shift = (i - 1) * 8;
37 | answer =
38 | answer << 16 |
39 | Morton2D_encode_y_256[(y >> shift) & EIGHTBITMASK] |
40 | Morton2D_encode_x_256[(x >> shift) & EIGHTBITMASK];
41 | }
42 | return answer;
43 | }
44 |
45 | // ENCODE 2D Morton code : LookUpTable (LUT)
46 | template
47 | inline morton m2D_e_LUT(const coord x, const coord y) {
48 | morton answer = 0;
49 | const static morton EIGHTBITMASK = 0x000000FF;
50 | for (unsigned int i = sizeof(coord); i > 0; --i) {
51 | unsigned int shift = (i - 1) * 8;
52 | answer =
53 | answer << 16 |
54 | (Morton2D_encode_x_256[(y >> shift) & EIGHTBITMASK] << 1) |
55 | (Morton2D_encode_x_256[(x >> shift) & EIGHTBITMASK]);
56 | }
57 | return answer;
58 | }
59 |
60 | // HELPER METHOD for Early Termination LUT Encode
61 | template
62 | inline morton compute2D_ET_LUT_encode(const coord c, const coord *LUT) {
63 | const static morton EIGHTBITMASK = 0x000000FF;
64 | unsigned long maxbit = 0;
65 | morton answer = 0;
66 | if (findFirstSetBit(c, &maxbit) == 0) { return 0; }
67 | unsigned int i = 0;
68 | while (maxbit >= i) {
69 | answer |= (LUT[(c >> i) & EIGHTBITMASK]) << i * 2;
70 | i += 8;
71 | }
72 | return answer;
73 | }
74 |
75 | // ENCODE 2D Morton code : Pre-shifted LUT (Early termination version)
76 | // This version tries to terminate early when there are no more bits to process
77 | // Figuring this out is probably too costly in most cases.
78 | template
79 | inline morton m2D_e_sLUT_ET(const coord x, const coord y) {
80 | morton answer_x = compute2D_ET_LUT_encode(x, Morton2D_encode_x_256);
81 | morton answer_y = compute2D_ET_LUT_encode(y, Morton2D_encode_y_256);
82 | return answer_y | answer_x;
83 | }
84 |
85 | // ENCODE 2D Morton code : LUT (Early termination version)
86 | template
87 | inline morton m2D_e_LUT_ET(const coord x, const coord y) {
88 | morton answer_x = compute2D_ET_LUT_encode(x, Morton2D_encode_x_256);
89 | morton answer_y = compute2D_ET_LUT_encode(y, Morton2D_encode_x_256);
90 | return (answer_y << 1) | answer_x;
91 | }
92 |
93 | // HELPER METHOD for Magic bits encoding - split by 2
94 | template
95 | inline morton morton2D_SplitBy2Bits(const coord a) {
96 | const morton* masks = (sizeof(morton) <= 4) ? reinterpret_cast(magicbit2D_masks32) : reinterpret_cast(magicbit2D_masks64);
97 | morton x = a;
98 | if (sizeof(morton) > 4) { x = (x | x << 32) & masks[0]; }
99 | x = (x | x << 16) & masks[1];
100 | x = (x | x << 8) & masks[2];
101 | x = (x | x << 4) & masks[3];
102 | x = (x | x << 2) & masks[4];
103 | x = (x | x << 1) & masks[5];
104 | return x;
105 | }
106 |
107 | // ENCODE 2D Morton code : Magic bits
108 | template
109 | inline morton m2D_e_magicbits(const coord x, const coord y) {
110 | return morton2D_SplitBy2Bits(x) | (morton2D_SplitBy2Bits(y) << 1);
111 | }
112 |
113 | // ENCODE 2D Morton code : For Loop
114 | template
115 | inline morton m2D_e_for(const coord x, const coord y){
116 | morton answer = 0;
117 | unsigned int checkbits = floor(sizeof(morton) * 4.0f);
118 | for (unsigned int i = 0; i <= checkbits; ++i) {
119 | morton mshifted = static_cast(0x1) << i; // Here we need to cast 0x1 to 64bits, otherwise there is a bug when morton code is larger than 32 bits
120 | unsigned int shift = 2 * i;
121 | answer |=
122 | ((x & mshifted) << shift)
123 | | ((y & mshifted) << (shift + 1));
124 | }
125 | return answer;
126 | }
127 |
128 | // ENCODE 2D Morton code : For Loop (Early termination version)
129 | template
130 | inline morton m2D_e_for_ET(const coord x, const coord y) {
131 | morton answer = 0;
132 | unsigned long x_max = 0, y_max = 0;
133 | unsigned int checkbits = sizeof(morton) * 4;
134 | findFirstSetBit(x, &x_max);
135 | findFirstSetBit(y, &y_max);
136 | checkbits = min(static_cast(checkbits), max(x_max, y_max) + 1ul);
137 | for (unsigned int i = 0; i <= checkbits; ++i) {
138 | morton m_shifted = static_cast(0x1) << i; // Here we need to cast 0x1 to 64bits, otherwise there is a bug when morton code is larger than 32 bits
139 | unsigned int shift = 2 * i;
140 | answer |= ((x & m_shifted) << shift)
141 | | ((y & m_shifted) << (shift + 1));
142 | }
143 | return answer;
144 | }
145 |
146 | // HELPER METHODE for LUT decoding
147 | template
148 | inline coord morton2D_DecodeCoord_LUT256(const morton m, const uint_fast8_t *LUT, const unsigned int startshift) {
149 | morton a = 0;
150 | morton EIGHTBITMASK = 0x000000ff;
151 | unsigned int loops = sizeof(morton);
152 | for (unsigned int i = 0; i < loops; ++i) {
153 | a |= (LUT[(m >> ((i * 8) + startshift)) & EIGHTBITMASK] << (4 * i));
154 | }
155 | return static_cast(a);
156 | }
157 |
158 | // DECODE 2D Morton code : Shifted LUT
159 | template
160 | inline void m2D_d_sLUT(const morton m, coord& x, coord& y) {
161 | x = morton2D_DecodeCoord_LUT256(m, Morton2D_decode_x_256, 0);
162 | y = morton2D_DecodeCoord_LUT256(m, Morton2D_decode_y_256, 0);
163 | }
164 |
165 | // DECODE 2D 64-bit morton code : LUT
166 | template
167 | inline void m2D_d_LUT(const morton m, coord& x, coord& y) {
168 | x = morton2D_DecodeCoord_LUT256(m, Morton2D_decode_x_256, 0);
169 | y = morton2D_DecodeCoord_LUT256(m, Morton2D_decode_x_256, 1);
170 | }
171 |
172 | // DECODE 2D Morton code : Shifted LUT (early termination)
173 | template
174 | inline void m2D_d_sLUT_ET(const morton m, coord& x, coord& y) {
175 | x = 0; y = 0;
176 | morton EIGHTBITMASK = 0x000000ff;
177 | unsigned long firstbit_location = 0;
178 | if (!findFirstSetBit(m, &firstbit_location)) { return; }
179 | unsigned int i = 0;
180 | unsigned int shiftback = 0;
181 | while (firstbit_location >= i) {
182 | morton m_shifted = (m >> i) & EIGHTBITMASK;
183 | x |= Morton2D_decode_x_256[m_shifted] << shiftback;
184 | y |= Morton2D_decode_y_256[m_shifted] << shiftback;
185 | shiftback += 4;
186 | i += 8;
187 | }
188 | }
189 |
190 | // DECODE 2D Morton code : LUT (early termination)
191 | template
192 | inline void m2D_d_LUT_ET(const morton m, coord& x, coord& y) {
193 | x = 0; y = 0;
194 | morton EIGHTBITMASK = 0x000000ff;
195 | unsigned long firstbit_location = 0;
196 | if (!findFirstSetBit(m, &firstbit_location)) { return; }
197 | unsigned int i = 0;
198 | unsigned int shiftback = 0;
199 | while (firstbit_location >= i) {
200 | morton m_shifted = (m >> i) & EIGHTBITMASK;
201 | x |= Morton2D_decode_x_256[(m >> i) & EIGHTBITMASK] << shiftback;
202 | y |= Morton2D_decode_x_256[(m >> (i+1)) & EIGHTBITMASK] << shiftback;
203 | shiftback += 4;
204 | i += 8;
205 | }
206 | }
207 |
208 | // HELPER method for Magicbits decoding
209 | template
210 | static inline coord morton2D_GetSecondBits(const morton m) {
211 | morton* masks = (sizeof(morton) <= 4) ? reinterpret_cast(magicbit2D_masks32) : reinterpret_cast(magicbit2D_masks64);
212 | morton x = m & masks[4];
213 | x = (x ^ (x >> 2)) & masks[3];
214 | x = (x ^ (x >> 4)) & masks[2];
215 | x = (x ^ (x >> 8)) & masks[1];
216 | if (sizeof(morton) > 4) x = (x ^ (x >> 16)) & masks[0];
217 | return static_cast(x);
218 | }
219 |
220 | // DECODE 2D Morton code : Magic bits
221 | // This method splits the morton codes bits by using certain patterns (magic bits)
222 | template
223 | inline void m2D_d_magicbits(const morton m, coord& x, coord& y) {
224 | x = morton2D_GetSecondBits(m);
225 | y = morton2D_GetSecondBits(m >> 1);
226 | }
227 |
228 |
229 | // DECODE 2D morton code : For loop
230 | template
231 | inline void m2D_d_for(const morton m, coord& x, coord& y) {
232 | x = 0; y = 0;
233 | unsigned int checkbits = sizeof(morton) * 4;
234 | for (unsigned int i = 0; i <= checkbits; ++i) {
235 | morton selector = 1;
236 | unsigned int shift_selector = 2 * i;
237 | x |= (m & (selector << shift_selector)) >> i;
238 | y |= (m & (selector << (shift_selector + 1))) >> (i + 1);
239 | }
240 | }
241 |
242 | // DECODE 3D Morton code : For loop (Early termination version)
243 | template
244 | inline void m2D_d_for_ET(const morton m, coord& x, coord& y) {
245 | x = 0; y = 0;
246 | float defaultbits = sizeof(morton) * 4;
247 | unsigned long firstbit_location = 0;
248 | if (!findFirstSetBit(m, &firstbit_location)) return;
249 | unsigned int checkbits = static_cast(min(defaultbits, firstbit_location / 2.0f));
250 | for (unsigned int i = 0; i <= checkbits; ++i) {
251 | morton selector = 1;
252 | unsigned int shift_selector = 2 * i;
253 | x |= (m & (selector << shift_selector)) >> i;
254 | y |= (m & (selector << (shift_selector + 1))) >> (i + 1);
255 | }
256 | }
257 |
--------------------------------------------------------------------------------
/extern/libmorton/libmorton/include/morton2D_LUTs.h:
--------------------------------------------------------------------------------
1 | #pragma once
2 |
3 | #include
4 |
5 | // Magicbits masks
6 | static uint_fast32_t magicbit2D_masks32[6] = { 0xFFFFFFFF, 0x0000FFFF, 0x00FF00FF, 0x0F0F0F0F, 0x33333333, 0x55555555 };
7 | static uint_fast64_t magicbit2D_masks64[6] = { 0x00000000FFFFFFFF, 0x0000FFFF0000FFFF, 0x00FF00FF00FF00FF,
8 | 0x0F0F0F0F0F0F0F0F, 0x3333333333333333, 0x5555555555555555 };
9 |
10 | static const uint_fast16_t Morton2D_encode_x_256[256] =
11 | {
12 | 0, 1, 4, 5, 16, 17, 20, 21,
13 | 64, 65, 68, 69, 80, 81, 84, 85,
14 | 256, 257, 260, 261, 272, 273, 276, 277,
15 | 320, 321, 324, 325, 336, 337, 340, 341,
16 | 1024, 1025, 1028, 1029, 1040, 1041, 1044, 1045,
17 | 1088, 1089, 1092, 1093, 1104, 1105, 1108, 1109,
18 | 1280, 1281, 1284, 1285, 1296, 1297, 1300, 1301,
19 | 1344, 1345, 1348, 1349, 1360, 1361, 1364, 1365,
20 | 4096, 4097, 4100, 4101, 4112, 4113, 4116, 4117,
21 | 4160, 4161, 4164, 4165, 4176, 4177, 4180, 4181,
22 | 4352, 4353, 4356, 4357, 4368, 4369, 4372, 4373,
23 | 4416, 4417, 4420, 4421, 4432, 4433, 4436, 4437,
24 | 5120, 5121, 5124, 5125, 5136, 5137, 5140, 5141,
25 | 5184, 5185, 5188, 5189, 5200, 5201, 5204, 5205,
26 | 5376, 5377, 5380, 5381, 5392, 5393, 5396, 5397,
27 | 5440, 5441, 5444, 5445, 5456, 5457, 5460, 5461,
28 | 16384, 16385, 16388, 16389, 16400, 16401, 16404, 16405,
29 | 16448, 16449, 16452, 16453, 16464, 16465, 16468, 16469,
30 | 16640, 16641, 16644, 16645, 16656, 16657, 16660, 16661,
31 | 16704, 16705, 16708, 16709, 16720, 16721, 16724, 16725,
32 | 17408, 17409, 17412, 17413, 17424, 17425, 17428, 17429,
33 | 17472, 17473, 17476, 17477, 17488, 17489, 17492, 17493,
34 | 17664, 17665, 17668, 17669, 17680, 17681, 17684, 17685,
35 | 17728, 17729, 17732, 17733, 17744, 17745, 17748, 17749,
36 | 20480, 20481, 20484, 20485, 20496, 20497, 20500, 20501,
37 | 20544, 20545, 20548, 20549, 20560, 20561, 20564, 20565,
38 | 20736, 20737, 20740, 20741, 20752, 20753, 20756, 20757,
39 | 20800, 20801, 20804, 20805, 20816, 20817, 20820, 20821,
40 | 21504, 21505, 21508, 21509, 21520, 21521, 21524, 21525,
41 | 21568, 21569, 21572, 21573, 21584, 21585, 21588, 21589,
42 | 21760, 21761, 21764, 21765, 21776, 21777, 21780, 21781,
43 | 21824, 21825, 21828, 21829, 21840, 21841, 21844, 21845
44 | };
45 |
46 | static const uint_fast16_t Morton2D_encode_y_256[256] =
47 | {
48 | 0, 2, 8, 10, 32, 34, 40, 42,
49 | 128, 130, 136, 138, 160, 162, 168, 170,
50 | 512, 514, 520, 522, 544, 546, 552, 554,
51 | 640, 642, 648, 650, 672, 674, 680, 682,
52 | 2048, 2050, 2056, 2058, 2080, 2082, 2088, 2090,
53 | 2176, 2178, 2184, 2186, 2208, 2210, 2216, 2218,
54 | 2560, 2562, 2568, 2570, 2592, 2594, 2600, 2602,
55 | 2688, 2690, 2696, 2698, 2720, 2722, 2728, 2730,
56 | 8192, 8194, 8200, 8202, 8224, 8226, 8232, 8234,
57 | 8320, 8322, 8328, 8330, 8352, 8354, 8360, 8362,
58 | 8704, 8706, 8712, 8714, 8736, 8738, 8744, 8746,
59 | 8832, 8834, 8840, 8842, 8864, 8866, 8872, 8874,
60 | 10240, 10242, 10248, 10250, 10272, 10274, 10280, 10282,
61 | 10368, 10370, 10376, 10378, 10400, 10402, 10408, 10410,
62 | 10752, 10754, 10760, 10762, 10784, 10786, 10792, 10794,
63 | 10880, 10882, 10888, 10890, 10912, 10914, 10920, 10922,
64 | 32768, 32770, 32776, 32778, 32800, 32802, 32808, 32810,
65 | 32896, 32898, 32904, 32906, 32928, 32930, 32936, 32938,
66 | 33280, 33282, 33288, 33290, 33312, 33314, 33320, 33322,
67 | 33408, 33410, 33416, 33418, 33440, 33442, 33448, 33450,
68 | 34816, 34818, 34824, 34826, 34848, 34850, 34856, 34858,
69 | 34944, 34946, 34952, 34954, 34976, 34978, 34984, 34986,
70 | 35328, 35330, 35336, 35338, 35360, 35362, 35368, 35370,
71 | 35456, 35458, 35464, 35466, 35488, 35490, 35496, 35498,
72 | 40960, 40962, 40968, 40970, 40992, 40994, 41000, 41002,
73 | 41088, 41090, 41096, 41098, 41120, 41122, 41128, 41130,
74 | 41472, 41474, 41480, 41482, 41504, 41506, 41512, 41514,
75 | 41600, 41602, 41608, 41610, 41632, 41634, 41640, 41642,
76 | 43008, 43010, 43016, 43018, 43040, 43042, 43048, 43050,
77 | 43136, 43138, 43144, 43146, 43168, 43170, 43176, 43178,
78 | 43520, 43522, 43528, 43530, 43552, 43554, 43560, 43562,
79 | 43648, 43650, 43656, 43658, 43680, 43682, 43688, 43690
80 | };
81 |
82 | static const uint_fast8_t Morton2D_decode_x_256[256]{
83 | 0,1,0,1,2,3,2,3,0,1,0,1,2,3,2,3,
84 | 4,5,4,5,6,7,6,7,4,5,4,5,6,7,6,7,
85 | 0,1,0,1,2,3,2,3,0,1,0,1,2,3,2,3,
86 | 4,5,4,5,6,7,6,7,4,5,4,5,6,7,6,7,
87 | 8,9,8,9,10,11,10,11,8,9,8,9,10,11,10,11,
88 | 12,13,12,13,14,15,14,15,12,13,12,13,14,15,14,15,
89 | 8,9,8,9,10,11,10,11,8,9,8,9,10,11,10,11,
90 | 12,13,12,13,14,15,14,15,12,13,12,13,14,15,14,15,
91 | 0,1,0,1,2,3,2,3,0,1,0,1,2,3,2,3,
92 | 4,5,4,5,6,7,6,7,4,5,4,5,6,7,6,7,
93 | 0,1,0,1,2,3,2,3,0,1,0,1,2,3,2,3,
94 | 4,5,4,5,6,7,6,7,4,5,4,5,6,7,6,7,
95 | 8,9,8,9,10,11,10,11,8,9,8,9,10,11,10,11,
96 | 12,13,12,13,14,15,14,15,12,13,12,13,14,15,14,15,
97 | 8,9,8,9,10,11,10,11,8,9,8,9,10,11,10,11,
98 | 12,13,12,13,14,15,14,15,12,13,12,13,14,15,14,15
99 | };
100 |
101 | static const uint_fast8_t Morton2D_decode_y_256[256]{
102 | 0,0,1,1,0,0,1,1,2,2,3,3,2,2,3,3,
103 | 0,0,1,1,0,0,1,1,2,2,3,3,2,2,3,3,
104 | 4,4,5,5,4,4,5,5,6,6,7,7,6,6,7,7,
105 | 4,4,5,5,4,4,5,5,6,6,7,7,6,6,7,7,
106 | 0,0,1,1,0,0,1,1,2,2,3,3,2,2,3,3,
107 | 0,0,1,1,0,0,1,1,2,2,3,3,2,2,3,3,
108 | 4,4,5,5,4,4,5,5,6,6,7,7,6,6,7,7,
109 | 4,4,5,5,4,4,5,5,6,6,7,7,6,6,7,7,
110 | 8,8,9,9,8,8,9,9,10,10,11,11,10,10,11,11,
111 | 8,8,9,9,8,8,9,9,10,10,11,11,10,10,11,11,
112 | 12,12,13,13,12,12,13,13,14,14,15,15,14,14,15,15,
113 | 12,12,13,13,12,12,13,13,14,14,15,15,14,14,15,15,
114 | 8,8,9,9,8,8,9,9,10,10,11,11,10,10,11,11,
115 | 8,8,9,9,8,8,9,9,10,10,11,11,10,10,11,11,
116 | 12,12,13,13,12,12,13,13,14,14,15,15,14,14,15,15,
117 | 12,12,13,13,12,12,13,13,14,14,15,15,14,14,15,15
118 | };
119 |
--------------------------------------------------------------------------------
/extern/libmorton/libmorton/include/morton3D.h:
--------------------------------------------------------------------------------
1 | #pragma once
2 |
3 | // Libmorton - Methods to encode/decode 64-bit morton codes from/to 32-bit (x,y,z) coordinates
4 | // Warning: morton.h will always point to the functions that use the fastest available method.
5 |
6 | #include
7 | #include
8 | #include "morton3D_LUTs.h"
9 | #include "morton_common.h"
10 |
11 | using namespace std;
12 |
13 | // AVAILABLE METHODS FOR ENCODING
14 | template inline morton m3D_e_sLUT(const coord x, const coord y, const coord z);
15 | template inline morton m3D_e_sLUT_ET(const coord x, const coord y, const coord z);
16 | template inline morton m3D_e_LUT(const coord x, const coord y, const coord z);
17 | template inline morton m3D_e_LUT_ET(const coord x, const coord y, const coord z);
18 | template inline morton m3D_e_magicbits(const coord x, const coord y, const coord z);
19 | template inline morton m3D_e_for(const coord x, const coord y, const coord z);
20 | template inline morton m3D_e_for_ET(const coord x, const coord y, const coord z);
21 |
22 | // AVAILABLE METHODS FOR DECODING
23 | template inline void m3D_d_sLUT(const morton m, coord& x, coord& y, coord& z);
24 | template inline void m3D_d_sLUT_ET(const morton m, coord& x, coord& y, coord& z);
25 | template inline void m3D_d_LUT(const morton m, coord& x, coord& y, coord& z);
26 | template inline void m3D_d_LUT_ET(const morton m, coord& x, coord& y, coord& z);
27 | template inline void m3D_d_magicbits(const morton m, coord& x, coord& y, coord& z);
28 | template inline void m3D_d_for(const morton m, coord& x, coord& y, coord& z);
29 | template inline void m3D_d_for_ET(const morton m, coord& x, coord& y, coord& z);
30 |
31 | // ENCODE 3D Morton code : Pre-Shifted LookUpTable (sLUT)
32 | template
33 | inline morton m3D_e_sLUT(const coord x, const coord y, const coord z) {
34 | morton answer = 0;
35 | const static morton EIGHTBITMASK = 0x000000FF;
36 | for (unsigned int i = sizeof(coord); i > 0; --i) {
37 | unsigned int shift = (i - 1) * 8;
38 | answer =
39 | answer << 24 |
40 | (Morton3D_encode_z_256[(z >> shift) & EIGHTBITMASK] |
41 | Morton3D_encode_y_256[(y >> shift) & EIGHTBITMASK] |
42 | Morton3D_encode_x_256[(x >> shift) & EIGHTBITMASK]);
43 | }
44 | return answer;
45 | }
46 |
47 | // ENCODE 3D Morton code : LookUpTable (LUT)
48 | template
49 | inline morton m3D_e_LUT(const coord x, const coord y, const coord z) {
50 | morton answer = 0;
51 | const static morton EIGHTBITMASK = 0x000000FF;
52 | for (unsigned int i = sizeof(coord); i > 0; --i) {
53 | unsigned int shift = (i - 1) * 8;
54 | answer =
55 | answer << 24 |
56 | (Morton3D_encode_x_256[(z >> shift) & EIGHTBITMASK] << 2) |
57 | (Morton3D_encode_x_256[(y >> shift) & EIGHTBITMASK] << 1) |
58 | Morton3D_encode_x_256[(x >> shift) & EIGHTBITMASK];
59 | }
60 | return answer;
61 | }
62 |
63 | // HELPER METHOD for ET LUT encode
64 | template
65 | inline morton compute3D_ET_LUT_encode(const coord c, const coord *LUT) {
66 | const static morton EIGHTBITMASK = 0x000000FF;
67 | unsigned long maxbit = 0;
68 | morton answer = 0;
69 | if (findFirstSetBit(c, &maxbit) == 0) { return 0; }
70 | for (int i = ceil((maxbit + 1) / 8.0f) ; i >= 0; --i){
71 | unsigned int shift = i* 8;
72 | answer = answer << 24 | (LUT[(c >> shift) & EIGHTBITMASK]);
73 | }
74 | return answer;
75 | }
76 |
77 | // ENCODE 3D Morton code : Pre-shifted LookUpTable (LUT) (Early Termination version)
78 | // This version tries to terminate early when there are no more bits to process
79 | // Figuring this out is probably too costly in most cases.
80 | template
81 | inline morton m3D_e_sLUT_ET(const coord x, const coord y, const coord z) {
82 | morton answer_x = compute3D_ET_LUT_encode(x, Morton3D_encode_x_256);
83 | morton answer_y = compute3D_ET_LUT_encode(y, Morton3D_encode_y_256);
84 | morton answer_z = compute3D_ET_LUT_encode(z, Morton3D_encode_z_256);
85 | return answer_z | answer_y | answer_x;
86 | }
87 |
88 | // ENCODE 3D Morton code : LookUpTable (LUT) (Early termination version)
89 | // This version tries to terminate early when there are no more bits to process
90 | // Figuring this out is probably too costly in most cases.
91 | template
92 | inline morton m3D_e_LUT_ET(const coord x, const coord y, const coord z) {
93 | morton answer_x = compute3D_ET_LUT_encode(x, Morton3D_encode_x_256);
94 | morton answer_y = compute3D_ET_LUT_encode(y, Morton3D_encode_x_256);
95 | morton answer_z = compute3D_ET_LUT_encode(z, Morton3D_encode_x_256);
96 | return (answer_z << 2) | (answer_y << 1) | answer_x;
97 | }
98 |
99 | // HELPER METHOD: Magic bits encoding (helper method)
100 | template
101 | static inline morton morton3D_SplitBy3bits(const coord a) {
102 | const morton* masks = (sizeof(morton) <= 4) ? reinterpret_cast(magicbit3D_masks32) : reinterpret_cast(magicbit3D_masks64);
103 | morton x = a;
104 | x = x & masks[0];
105 | x = (x | x << 16) & masks[1];
106 | x = (x | x << 8) & masks[2];
107 | x = (x | x << 4) & masks[3];
108 | x = (x | x << 2) & masks[4];
109 | return x;
110 | }
111 |
112 | // ENCODE 3D Morton code : Magic bits method
113 | // This method uses certain bit patterns (magic bits) to split bits in the coordinates
114 | template
115 | inline morton m3D_e_magicbits(const coord x, const coord y, const coord z){
116 | return morton3D_SplitBy3bits(x) | (morton3D_SplitBy3bits(y) << 1) | (morton3D_SplitBy3bits(z) << 2);
117 | }
118 |
119 | // ENCODE 3D Morton code : For loop
120 | // This is the most naive way of encoding coordinates into a morton code
121 | template
122 | inline morton m3D_e_for(const coord x, const coord y, const coord z){
123 | morton answer = 0;
124 | unsigned int checkbits = static_cast(floor((sizeof(morton) * 8.0f / 3.0f)));
125 | for (unsigned int i = 0; i < checkbits; ++i) {
126 | morton mshifted= static_cast(1) << i; // Here we need to cast 0x1 to 64bits, otherwise there is a bug when morton code is larger than 32 bits
127 | unsigned int shift = 2 * i; // because you have to shift back i and forth 3*i
128 | answer |= ((x & mshifted) << shift)
129 | | ((y & mshifted) << (shift + 1))
130 | | ((z & mshifted) << (shift + 2));
131 | }
132 | return answer;
133 | }
134 |
135 | // ENCODE 3D Morton code : For loop (Early termination version)
136 | // In case of the for loop, figuring out when to stop early has huge benefits.
137 | template
138 | inline morton m3D_e_for_ET(const coord x, const coord y, const coord z) {
139 | morton answer = 0;
140 | unsigned long x_max = 0, y_max = 0, z_max = 0;
141 | unsigned int checkbits = static_cast(floor((sizeof(morton) * 8.0f / 3.0f)));
142 | findFirstSetBit(x, &x_max);
143 | findFirstSetBit(y, &y_max);
144 | findFirstSetBit(z, &z_max);
145 | checkbits = min((unsigned long)checkbits, max(z_max, max(x_max, y_max)) + (unsigned long) 1);
146 | for (unsigned int i = 0; i < checkbits; ++i) {
147 | morton m_shifted = static_cast(1) << i; // Here we need to cast 0x1 to 64bits, otherwise there is a bug when morton code is larger than 32 bits
148 | unsigned int shift = 2 * i;
149 | answer |= ((x & m_shifted) << shift)
150 | | ((y & m_shifted) << (shift + 1))
151 | | ((z & m_shifted) << (shift + 2));
152 | }
153 | return answer;
154 | }
155 |
156 |
157 | // HELPER METHOD for LUT decoding
158 | // todo: wouldn't this be better with 8-bit aligned decode LUT?
159 | template
160 | inline coord morton3D_DecodeCoord_LUT256(const morton m, const uint_fast8_t *LUT, const unsigned int startshift) {
161 | morton a = 0;
162 | morton NINEBITMASK = 0x000001ff;
163 | unsigned int loops = (sizeof(morton) <= 4) ? 4 : 7; // ceil for 32bit, floor for 64bit
164 | for (unsigned int i = 0; i < loops; ++i){
165 | a |= (LUT[(m >> ((i * 9) + startshift)) & NINEBITMASK] << (3 * i));
166 | }
167 | return static_cast(a);
168 | }
169 |
170 | // DECODE 3D Morton code : Shifted LUT
171 | template
172 | inline void m3D_d_sLUT(const morton m, coord& x, coord& y, coord& z) {
173 | x = morton3D_DecodeCoord_LUT256(m, Morton3D_decode_x_512, 0);
174 | y = morton3D_DecodeCoord_LUT256(m, Morton3D_decode_y_512, 0);
175 | z = morton3D_DecodeCoord_LUT256(m, Morton3D_decode_z_512, 0);
176 | }
177 |
178 | // DECODE 3D Morton code : LUT
179 | template
180 | inline void m3D_d_LUT(const morton m, coord& x, coord& y, coord& z) {
181 | x = morton3D_DecodeCoord_LUT256(m, Morton3D_decode_x_512, 0);
182 | y = morton3D_DecodeCoord_LUT256(m, Morton3D_decode_x_512, 1);
183 | z = morton3D_DecodeCoord_LUT256(m, Morton3D_decode_x_512, 2);
184 | }
185 |
186 | // DECODE 3D Morton code : Shifted LUT (Early termination version)
187 | template
188 | inline void m3D_d_sLUT_ET(const morton m, coord& x, coord& y, coord& z){
189 | x = 0; y = 0; z = 0;
190 | morton NINEBITMASK = 0x000001ff;
191 | unsigned long firstbit_location = 0;
192 | if (!findFirstSetBit(m, &firstbit_location)) { return; }
193 | unsigned int i = 0;
194 | unsigned int shiftback = 0;
195 | while (firstbit_location >= i) {
196 | morton m_shifted = (m >> i) & NINEBITMASK;
197 | x |= Morton3D_decode_x_512[m_shifted] << shiftback;
198 | y |= Morton3D_decode_y_512[m_shifted] << shiftback;
199 | z |= Morton3D_decode_z_512[m_shifted] << shiftback;
200 | shiftback += 3;
201 | i += 9;
202 | }
203 | return;
204 | }
205 |
206 | // DECODE 3D Morton code : LUT (Early termination version)
207 | template
208 | inline void m3D_d_LUT_ET(const morton m, coord& x, coord& y, coord& z){
209 | x = 0; y = 0; z = 0;
210 | morton NINEBITMASK = 0x000001ff;
211 | unsigned long firstbit_location = 0;
212 | if (!findFirstSetBit(m, &firstbit_location)) { return; }
213 | unsigned int i = 0;
214 | unsigned int shiftback = 0;
215 | while (i <= firstbit_location) {
216 | x = x | Morton3D_decode_x_512[(m >> i) & NINEBITMASK] << shiftback;
217 | y = y | Morton3D_decode_x_512[(m >> (i+1)) & NINEBITMASK] << shiftback;
218 | z = z | Morton3D_decode_x_512[(m >> (i+2)) & NINEBITMASK] << shiftback;
219 | i += 9;
220 | shiftback += 3;
221 | }
222 | return;
223 | }
224 |
225 | // HELPER METHOD for Magic bits decoding
226 | template
227 | static inline coord morton3D_GetThirdBits(const morton m) {
228 | morton* masks = (sizeof(morton) <= 4) ? reinterpret_cast(magicbit3D_masks32) : reinterpret_cast(magicbit3D_masks64);
229 | morton x = m & masks[4];
230 | x = (x ^ (x >> 2)) & masks[3];
231 | x = (x ^ (x >> 4)) & masks[2];
232 | x = (x ^ (x >> 8)) & masks[1];
233 | x = (x ^ (x >> 16)) & masks[0];
234 | return static_cast(x);
235 | }
236 |
237 | // DECODE 3D Morton code : Magic bits
238 | // This method splits the morton codes bits by using certain patterns (magic bits)
239 | template
240 | inline void m3D_d_magicbits(const morton m, coord& x, coord& y, coord& z){
241 | x = morton3D_GetThirdBits(m);
242 | y = morton3D_GetThirdBits(m >> 1);
243 | z = morton3D_GetThirdBits(m >> 2);
244 | }
245 |
246 | // DECODE 3D Morton code : For loop
247 | template
248 | inline void m3D_d_for(const morton m, coord& x, coord& y, coord& z){
249 | x = 0; y = 0; z = 0;
250 | unsigned int checkbits = static_cast(floor((sizeof(morton) * 8.0f / 3.0f)));
251 | for (unsigned int i = 0; i <= checkbits; ++i) {
252 | morton selector = 1;
253 | unsigned int shift_selector = 3 * i;
254 | unsigned int shiftback = 2 * i;
255 | x |= (m & (selector << shift_selector)) >> (shiftback);
256 | y |= (m & (selector << (shift_selector + 1))) >> (shiftback + 1);
257 | z |= (m & (selector << (shift_selector + 2))) >> (shiftback + 2);
258 | }
259 | }
260 |
261 | // DECODE 3D Morton code : For loop (Early termination version)
262 | template
263 | inline void m3D_d_for_ET(const morton m, coord& x, coord& y, coord& z) {
264 | x = 0; y = 0; z = 0;
265 | float defaultbits = floor((sizeof(morton) * 8.0f / 3.0f));
266 | unsigned long firstbit_location = 0;
267 | if(!findFirstSetBit(m, &firstbit_location)) return;
268 | unsigned int checkbits = static_cast(min(defaultbits, firstbit_location / 3.0f));
269 | for (unsigned int i = 0; i <= checkbits; ++i) {
270 | morton selector = 1;
271 | unsigned int shift_selector = 3 * i;
272 | unsigned int shiftback = 2 * i;
273 | x |= (m & (selector << shift_selector)) >> (shiftback);
274 | y |= (m & (selector << (shift_selector + 1))) >> (shiftback + 1);
275 | z |= (m & (selector << (shift_selector + 2))) >> (shiftback + 2);
276 | }
277 | }
278 |
--------------------------------------------------------------------------------
/extern/libmorton/libmorton/include/morton3D_LUTs.h:
--------------------------------------------------------------------------------
1 | #pragma once
2 |
3 | #include
4 |
5 | // Magicbits masks
6 | static uint_fast32_t magicbit3D_masks32[5] = { 0x000003ff, 0x30000ff, 0x0300f00f, 0x30c30c3, 0x9249249 };
7 | static uint_fast64_t magicbit3D_masks64[5] = { 0x1f000000001ffff, 0x1f0000ff0000ff, 0x100f00f00f00f00f, 0x10c30c30c30c30c3, 0x1249249249249249 };
8 |
9 | // Version with lookup table
10 | static const uint_fast32_t Morton3D_encode_x_256[256] =
11 | {
12 | 0x00000000,
13 | 0x00000001, 0x00000008, 0x00000009, 0x00000040, 0x00000041, 0x00000048, 0x00000049, 0x00000200,
14 | 0x00000201, 0x00000208, 0x00000209, 0x00000240, 0x00000241, 0x00000248, 0x00000249, 0x00001000,
15 | 0x00001001, 0x00001008, 0x00001009, 0x00001040, 0x00001041, 0x00001048, 0x00001049, 0x00001200,
16 | 0x00001201, 0x00001208, 0x00001209, 0x00001240, 0x00001241, 0x00001248, 0x00001249, 0x00008000,
17 | 0x00008001, 0x00008008, 0x00008009, 0x00008040, 0x00008041, 0x00008048, 0x00008049, 0x00008200,
18 | 0x00008201, 0x00008208, 0x00008209, 0x00008240, 0x00008241, 0x00008248, 0x00008249, 0x00009000,
19 | 0x00009001, 0x00009008, 0x00009009, 0x00009040, 0x00009041, 0x00009048, 0x00009049, 0x00009200,
20 | 0x00009201, 0x00009208, 0x00009209, 0x00009240, 0x00009241, 0x00009248, 0x00009249, 0x00040000,
21 | 0x00040001, 0x00040008, 0x00040009, 0x00040040, 0x00040041, 0x00040048, 0x00040049, 0x00040200,
22 | 0x00040201, 0x00040208, 0x00040209, 0x00040240, 0x00040241, 0x00040248, 0x00040249, 0x00041000,
23 | 0x00041001, 0x00041008, 0x00041009, 0x00041040, 0x00041041, 0x00041048, 0x00041049, 0x00041200,
24 | 0x00041201, 0x00041208, 0x00041209, 0x00041240, 0x00041241, 0x00041248, 0x00041249, 0x00048000,
25 | 0x00048001, 0x00048008, 0x00048009, 0x00048040, 0x00048041, 0x00048048, 0x00048049, 0x00048200,
26 | 0x00048201, 0x00048208, 0x00048209, 0x00048240, 0x00048241, 0x00048248, 0x00048249, 0x00049000,
27 | 0x00049001, 0x00049008, 0x00049009, 0x00049040, 0x00049041, 0x00049048, 0x00049049, 0x00049200,
28 | 0x00049201, 0x00049208, 0x00049209, 0x00049240, 0x00049241, 0x00049248, 0x00049249, 0x00200000,
29 | 0x00200001, 0x00200008, 0x00200009, 0x00200040, 0x00200041, 0x00200048, 0x00200049, 0x00200200,
30 | 0x00200201, 0x00200208, 0x00200209, 0x00200240, 0x00200241, 0x00200248, 0x00200249, 0x00201000,
31 | 0x00201001, 0x00201008, 0x00201009, 0x00201040, 0x00201041, 0x00201048, 0x00201049, 0x00201200,
32 | 0x00201201, 0x00201208, 0x00201209, 0x00201240, 0x00201241, 0x00201248, 0x00201249, 0x00208000,
33 | 0x00208001, 0x00208008, 0x00208009, 0x00208040, 0x00208041, 0x00208048, 0x00208049, 0x00208200,
34 | 0x00208201, 0x00208208, 0x00208209, 0x00208240, 0x00208241, 0x00208248, 0x00208249, 0x00209000,
35 | 0x00209001, 0x00209008, 0x00209009, 0x00209040, 0x00209041, 0x00209048, 0x00209049, 0x00209200,
36 | 0x00209201, 0x00209208, 0x00209209, 0x00209240, 0x00209241, 0x00209248, 0x00209249, 0x00240000,
37 | 0x00240001, 0x00240008, 0x00240009, 0x00240040, 0x00240041, 0x00240048, 0x00240049, 0x00240200,
38 | 0x00240201, 0x00240208, 0x00240209, 0x00240240, 0x00240241, 0x00240248, 0x00240249, 0x00241000,
39 | 0x00241001, 0x00241008, 0x00241009, 0x00241040, 0x00241041, 0x00241048, 0x00241049, 0x00241200,
40 | 0x00241201, 0x00241208, 0x00241209, 0x00241240, 0x00241241, 0x00241248, 0x00241249, 0x00248000,
41 | 0x00248001, 0x00248008, 0x00248009, 0x00248040, 0x00248041, 0x00248048, 0x00248049, 0x00248200,
42 | 0x00248201, 0x00248208, 0x00248209, 0x00248240, 0x00248241, 0x00248248, 0x00248249, 0x00249000,
43 | 0x00249001, 0x00249008, 0x00249009, 0x00249040, 0x00249041, 0x00249048, 0x00249049, 0x00249200,
44 | 0x00249201, 0x00249208, 0x00249209, 0x00249240, 0x00249241, 0x00249248, 0x00249249
45 | };
46 |
47 | static const uint_fast32_t Morton3D_encode_y_256[256] = {
48 | 0x00000000,
49 | 0x00000002, 0x00000010, 0x00000012, 0x00000080, 0x00000082, 0x00000090, 0x00000092, 0x00000400,
50 | 0x00000402, 0x00000410, 0x00000412, 0x00000480, 0x00000482, 0x00000490, 0x00000492, 0x00002000,
51 | 0x00002002, 0x00002010, 0x00002012, 0x00002080, 0x00002082, 0x00002090, 0x00002092, 0x00002400,
52 | 0x00002402, 0x00002410, 0x00002412, 0x00002480, 0x00002482, 0x00002490, 0x00002492, 0x00010000,
53 | 0x00010002, 0x00010010, 0x00010012, 0x00010080, 0x00010082, 0x00010090, 0x00010092, 0x00010400,
54 | 0x00010402, 0x00010410, 0x00010412, 0x00010480, 0x00010482, 0x00010490, 0x00010492, 0x00012000,
55 | 0x00012002, 0x00012010, 0x00012012, 0x00012080, 0x00012082, 0x00012090, 0x00012092, 0x00012400,
56 | 0x00012402, 0x00012410, 0x00012412, 0x00012480, 0x00012482, 0x00012490, 0x00012492, 0x00080000,
57 | 0x00080002, 0x00080010, 0x00080012, 0x00080080, 0x00080082, 0x00080090, 0x00080092, 0x00080400,
58 | 0x00080402, 0x00080410, 0x00080412, 0x00080480, 0x00080482, 0x00080490, 0x00080492, 0x00082000,
59 | 0x00082002, 0x00082010, 0x00082012, 0x00082080, 0x00082082, 0x00082090, 0x00082092, 0x00082400,
60 | 0x00082402, 0x00082410, 0x00082412, 0x00082480, 0x00082482, 0x00082490, 0x00082492, 0x00090000,
61 | 0x00090002, 0x00090010, 0x00090012, 0x00090080, 0x00090082, 0x00090090, 0x00090092, 0x00090400,
62 | 0x00090402, 0x00090410, 0x00090412, 0x00090480, 0x00090482, 0x00090490, 0x00090492, 0x00092000,
63 | 0x00092002, 0x00092010, 0x00092012, 0x00092080, 0x00092082, 0x00092090, 0x00092092, 0x00092400,
64 | 0x00092402, 0x00092410, 0x00092412, 0x00092480, 0x00092482, 0x00092490, 0x00092492, 0x00400000,
65 | 0x00400002, 0x00400010, 0x00400012, 0x00400080, 0x00400082, 0x00400090, 0x00400092, 0x00400400,
66 | 0x00400402, 0x00400410, 0x00400412, 0x00400480, 0x00400482, 0x00400490, 0x00400492, 0x00402000,
67 | 0x00402002, 0x00402010, 0x00402012, 0x00402080, 0x00402082, 0x00402090, 0x00402092, 0x00402400,
68 | 0x00402402, 0x00402410, 0x00402412, 0x00402480, 0x00402482, 0x00402490, 0x00402492, 0x00410000,
69 | 0x00410002, 0x00410010, 0x00410012, 0x00410080, 0x00410082, 0x00410090, 0x00410092, 0x00410400,
70 | 0x00410402, 0x00410410, 0x00410412, 0x00410480, 0x00410482, 0x00410490, 0x00410492, 0x00412000,
71 | 0x00412002, 0x00412010, 0x00412012, 0x00412080, 0x00412082, 0x00412090, 0x00412092, 0x00412400,
72 | 0x00412402, 0x00412410, 0x00412412, 0x00412480, 0x00412482, 0x00412490, 0x00412492, 0x00480000,
73 | 0x00480002, 0x00480010, 0x00480012, 0x00480080, 0x00480082, 0x00480090, 0x00480092, 0x00480400,
74 | 0x00480402, 0x00480410, 0x00480412, 0x00480480, 0x00480482, 0x00480490, 0x00480492, 0x00482000,
75 | 0x00482002, 0x00482010, 0x00482012, 0x00482080, 0x00482082, 0x00482090, 0x00482092, 0x00482400,
76 | 0x00482402, 0x00482410, 0x00482412, 0x00482480, 0x00482482, 0x00482490, 0x00482492, 0x00490000,
77 | 0x00490002, 0x00490010, 0x00490012, 0x00490080, 0x00490082, 0x00490090, 0x00490092, 0x00490400,
78 | 0x00490402, 0x00490410, 0x00490412, 0x00490480, 0x00490482, 0x00490490, 0x00490492, 0x00492000,
79 | 0x00492002, 0x00492010, 0x00492012, 0x00492080, 0x00492082, 0x00492090, 0x00492092, 0x00492400,
80 | 0x00492402, 0x00492410, 0x00492412, 0x00492480, 0x00492482, 0x00492490, 0x00492492
81 | };
82 |
83 | static const uint_fast32_t Morton3D_encode_z_256[256] = {
84 | 0x00000000,
85 | 0x00000004, 0x00000020, 0x00000024, 0x00000100, 0x00000104, 0x00000120, 0x00000124, 0x00000800,
86 | 0x00000804, 0x00000820, 0x00000824, 0x00000900, 0x00000904, 0x00000920, 0x00000924, 0x00004000,
87 | 0x00004004, 0x00004020, 0x00004024, 0x00004100, 0x00004104, 0x00004120, 0x00004124, 0x00004800,
88 | 0x00004804, 0x00004820, 0x00004824, 0x00004900, 0x00004904, 0x00004920, 0x00004924, 0x00020000,
89 | 0x00020004, 0x00020020, 0x00020024, 0x00020100, 0x00020104, 0x00020120, 0x00020124, 0x00020800,
90 | 0x00020804, 0x00020820, 0x00020824, 0x00020900, 0x00020904, 0x00020920, 0x00020924, 0x00024000,
91 | 0x00024004, 0x00024020, 0x00024024, 0x00024100, 0x00024104, 0x00024120, 0x00024124, 0x00024800,
92 | 0x00024804, 0x00024820, 0x00024824, 0x00024900, 0x00024904, 0x00024920, 0x00024924, 0x00100000,
93 | 0x00100004, 0x00100020, 0x00100024, 0x00100100, 0x00100104, 0x00100120, 0x00100124, 0x00100800,
94 | 0x00100804, 0x00100820, 0x00100824, 0x00100900, 0x00100904, 0x00100920, 0x00100924, 0x00104000,
95 | 0x00104004, 0x00104020, 0x00104024, 0x00104100, 0x00104104, 0x00104120, 0x00104124, 0x00104800,
96 | 0x00104804, 0x00104820, 0x00104824, 0x00104900, 0x00104904, 0x00104920, 0x00104924, 0x00120000,
97 | 0x00120004, 0x00120020, 0x00120024, 0x00120100, 0x00120104, 0x00120120, 0x00120124, 0x00120800,
98 | 0x00120804, 0x00120820, 0x00120824, 0x00120900, 0x00120904, 0x00120920, 0x00120924, 0x00124000,
99 | 0x00124004, 0x00124020, 0x00124024, 0x00124100, 0x00124104, 0x00124120, 0x00124124, 0x00124800,
100 | 0x00124804, 0x00124820, 0x00124824, 0x00124900, 0x00124904, 0x00124920, 0x00124924, 0x00800000,
101 | 0x00800004, 0x00800020, 0x00800024, 0x00800100, 0x00800104, 0x00800120, 0x00800124, 0x00800800,
102 | 0x00800804, 0x00800820, 0x00800824, 0x00800900, 0x00800904, 0x00800920, 0x00800924, 0x00804000,
103 | 0x00804004, 0x00804020, 0x00804024, 0x00804100, 0x00804104, 0x00804120, 0x00804124, 0x00804800,
104 | 0x00804804, 0x00804820, 0x00804824, 0x00804900, 0x00804904, 0x00804920, 0x00804924, 0x00820000,
105 | 0x00820004, 0x00820020, 0x00820024, 0x00820100, 0x00820104, 0x00820120, 0x00820124, 0x00820800,
106 | 0x00820804, 0x00820820, 0x00820824, 0x00820900, 0x00820904, 0x00820920, 0x00820924, 0x00824000,
107 | 0x00824004, 0x00824020, 0x00824024, 0x00824100, 0x00824104, 0x00824120, 0x00824124, 0x00824800,
108 | 0x00824804, 0x00824820, 0x00824824, 0x00824900, 0x00824904, 0x00824920, 0x00824924, 0x00900000,
109 | 0x00900004, 0x00900020, 0x00900024, 0x00900100, 0x00900104, 0x00900120, 0x00900124, 0x00900800,
110 | 0x00900804, 0x00900820, 0x00900824, 0x00900900, 0x00900904, 0x00900920, 0x00900924, 0x00904000,
111 | 0x00904004, 0x00904020, 0x00904024, 0x00904100, 0x00904104, 0x00904120, 0x00904124, 0x00904800,
112 | 0x00904804, 0x00904820, 0x00904824, 0x00904900, 0x00904904, 0x00904920, 0x00904924, 0x00920000,
113 | 0x00920004, 0x00920020, 0x00920024, 0x00920100, 0x00920104, 0x00920120, 0x00920124, 0x00920800,
114 | 0x00920804, 0x00920820, 0x00920824, 0x00920900, 0x00920904, 0x00920920, 0x00920924, 0x00924000,
115 | 0x00924004, 0x00924020, 0x00924024, 0x00924100, 0x00924104, 0x00924120, 0x00924124, 0x00924800,
116 | 0x00924804, 0x00924820, 0x00924824, 0x00924900, 0x00924904, 0x00924920, 0x00924924
117 | };
118 |
119 | static const uint_fast8_t Morton3D_decode_x_512[512] = {
120 | 0, 1, 0, 1, 0, 1, 0, 1, 2, 3, 2, 3, 2, 3, 2, 3,
121 | 0, 1, 0, 1, 0, 1, 0, 1, 2, 3, 2, 3, 2, 3, 2, 3,
122 | 0, 1, 0, 1, 0, 1, 0, 1, 2, 3, 2, 3, 2, 3, 2, 3,
123 | 0, 1, 0, 1, 0, 1, 0, 1, 2, 3, 2, 3, 2, 3, 2, 3,
124 | 4, 5, 4, 5, 4, 5, 4, 5, 6, 7, 6, 7, 6, 7, 6, 7,
125 | 4, 5, 4, 5, 4, 5, 4, 5, 6, 7, 6, 7, 6, 7, 6, 7,
126 | 4, 5, 4, 5, 4, 5, 4, 5, 6, 7, 6, 7, 6, 7, 6, 7,
127 | 4, 5, 4, 5, 4, 5, 4, 5, 6, 7, 6, 7, 6, 7, 6, 7,
128 | 0, 1, 0, 1, 0, 1, 0, 1, 2, 3, 2, 3, 2, 3, 2, 3,
129 | 0, 1, 0, 1, 0, 1, 0, 1, 2, 3, 2, 3, 2, 3, 2, 3,
130 | 0, 1, 0, 1, 0, 1, 0, 1, 2, 3, 2, 3, 2, 3, 2, 3,
131 | 0, 1, 0, 1, 0, 1, 0, 1, 2, 3, 2, 3, 2, 3, 2, 3,
132 | 4, 5, 4, 5, 4, 5, 4, 5, 6, 7, 6, 7, 6, 7, 6, 7,
133 | 4, 5, 4, 5, 4, 5, 4, 5, 6, 7, 6, 7, 6, 7, 6, 7,
134 | 4, 5, 4, 5, 4, 5, 4, 5, 6, 7, 6, 7, 6, 7, 6, 7,
135 | 4, 5, 4, 5, 4, 5, 4, 5, 6, 7, 6, 7, 6, 7, 6, 7,
136 | 0, 1, 0, 1, 0, 1, 0, 1, 2, 3, 2, 3, 2, 3, 2, 3,
137 | 0, 1, 0, 1, 0, 1, 0, 1, 2, 3, 2, 3, 2, 3, 2, 3,
138 | 0, 1, 0, 1, 0, 1, 0, 1, 2, 3, 2, 3, 2, 3, 2, 3,
139 | 0, 1, 0, 1, 0, 1, 0, 1, 2, 3, 2, 3, 2, 3, 2, 3,
140 | 4, 5, 4, 5, 4, 5, 4, 5, 6, 7, 6, 7, 6, 7, 6, 7,
141 | 4, 5, 4, 5, 4, 5, 4, 5, 6, 7, 6, 7, 6, 7, 6, 7,
142 | 4, 5, 4, 5, 4, 5, 4, 5, 6, 7, 6, 7, 6, 7, 6, 7,
143 | 4, 5, 4, 5, 4, 5, 4, 5, 6, 7, 6, 7, 6, 7, 6, 7,
144 | 0, 1, 0, 1, 0, 1, 0, 1, 2, 3, 2, 3, 2, 3, 2, 3,
145 | 0, 1, 0, 1, 0, 1, 0, 1, 2, 3, 2, 3, 2, 3, 2, 3,
146 | 0, 1, 0, 1, 0, 1, 0, 1, 2, 3, 2, 3, 2, 3, 2, 3,
147 | 0, 1, 0, 1, 0, 1, 0, 1, 2, 3, 2, 3, 2, 3, 2, 3,
148 | 4, 5, 4, 5, 4, 5, 4, 5, 6, 7, 6, 7, 6, 7, 6, 7,
149 | 4, 5, 4, 5, 4, 5, 4, 5, 6, 7, 6, 7, 6, 7, 6, 7,
150 | 4, 5, 4, 5, 4, 5, 4, 5, 6, 7, 6, 7, 6, 7, 6, 7,
151 | 4, 5, 4, 5, 4, 5, 4, 5, 6, 7, 6, 7, 6, 7, 6, 7
152 | };
153 |
154 | static const uint_fast8_t Morton3D_decode_y_512[512] = {
155 | 0, 0, 1, 1, 0, 0, 1, 1, 0, 0, 1, 1, 0, 0, 1, 1,
156 | 2, 2, 3, 3, 2, 2, 3, 3, 2, 2, 3, 3, 2, 2, 3, 3,
157 | 0, 0, 1, 1, 0, 0, 1, 1, 0, 0, 1, 1, 0, 0, 1, 1,
158 | 2, 2, 3, 3, 2, 2, 3, 3, 2, 2, 3, 3, 2, 2, 3, 3,
159 | 0, 0, 1, 1, 0, 0, 1, 1, 0, 0, 1, 1, 0, 0, 1, 1,
160 | 2, 2, 3, 3, 2, 2, 3, 3, 2, 2, 3, 3, 2, 2, 3, 3,
161 | 0, 0, 1, 1, 0, 0, 1, 1, 0, 0, 1, 1, 0, 0, 1, 1,
162 | 2, 2, 3, 3, 2, 2, 3, 3, 2, 2, 3, 3, 2, 2, 3, 3,
163 | 4, 4, 5, 5, 4, 4, 5, 5, 4, 4, 5, 5, 4, 4, 5, 5,
164 | 6, 6, 7, 7, 6, 6, 7, 7, 6, 6, 7, 7, 6, 6, 7, 7,
165 | 4, 4, 5, 5, 4, 4, 5, 5, 4, 4, 5, 5, 4, 4, 5, 5,
166 | 6, 6, 7, 7, 6, 6, 7, 7, 6, 6, 7, 7, 6, 6, 7, 7,
167 | 4, 4, 5, 5, 4, 4, 5, 5, 4, 4, 5, 5, 4, 4, 5, 5,
168 | 6, 6, 7, 7, 6, 6, 7, 7, 6, 6, 7, 7, 6, 6, 7, 7,
169 | 4, 4, 5, 5, 4, 4, 5, 5, 4, 4, 5, 5, 4, 4, 5, 5,
170 | 6, 6, 7, 7, 6, 6, 7, 7, 6, 6, 7, 7, 6, 6, 7, 7,
171 | 0, 0, 1, 1, 0, 0, 1, 1, 0, 0, 1, 1, 0, 0, 1, 1,
172 | 2, 2, 3, 3, 2, 2, 3, 3, 2, 2, 3, 3, 2, 2, 3, 3,
173 | 0, 0, 1, 1, 0, 0, 1, 1, 0, 0, 1, 1, 0, 0, 1, 1,
174 | 2, 2, 3, 3, 2, 2, 3, 3, 2, 2, 3, 3, 2, 2, 3, 3,
175 | 0, 0, 1, 1, 0, 0, 1, 1, 0, 0, 1, 1, 0, 0, 1, 1,
176 | 2, 2, 3, 3, 2, 2, 3, 3, 2, 2, 3, 3, 2, 2, 3, 3,
177 | 0, 0, 1, 1, 0, 0, 1, 1, 0, 0, 1, 1, 0, 0, 1, 1,
178 | 2, 2, 3, 3, 2, 2, 3, 3, 2, 2, 3, 3, 2, 2, 3, 3,
179 | 4, 4, 5, 5, 4, 4, 5, 5, 4, 4, 5, 5, 4, 4, 5, 5,
180 | 6, 6, 7, 7, 6, 6, 7, 7, 6, 6, 7, 7, 6, 6, 7, 7,
181 | 4, 4, 5, 5, 4, 4, 5, 5, 4, 4, 5, 5, 4, 4, 5, 5,
182 | 6, 6, 7, 7, 6, 6, 7, 7, 6, 6, 7, 7, 6, 6, 7, 7,
183 | 4, 4, 5, 5, 4, 4, 5, 5, 4, 4, 5, 5, 4, 4, 5, 5,
184 | 6, 6, 7, 7, 6, 6, 7, 7, 6, 6, 7, 7, 6, 6, 7, 7,
185 | 4, 4, 5, 5, 4, 4, 5, 5, 4, 4, 5, 5, 4, 4, 5, 5,
186 | 6, 6, 7, 7, 6, 6, 7, 7, 6, 6, 7, 7, 6, 6, 7, 7
187 | };
188 |
189 | static const uint_fast8_t Morton3D_decode_z_512[512] = {
190 | 0, 0, 0, 0, 1, 1, 1, 1, 0, 0, 0, 0, 1, 1, 1, 1,
191 | 0, 0, 0, 0, 1, 1, 1, 1, 0, 0, 0, 0, 1, 1, 1, 1,
192 | 2, 2, 2, 2, 3, 3, 3, 3, 2, 2, 2, 2, 3, 3, 3, 3,
193 | 2, 2, 2, 2, 3, 3, 3, 3, 2, 2, 2, 2, 3, 3, 3, 3,
194 | 0, 0, 0, 0, 1, 1, 1, 1, 0, 0, 0, 0, 1, 1, 1, 1,
195 | 0, 0, 0, 0, 1, 1, 1, 1, 0, 0, 0, 0, 1, 1, 1, 1,
196 | 2, 2, 2, 2, 3, 3, 3, 3, 2, 2, 2, 2, 3, 3, 3, 3,
197 | 2, 2, 2, 2, 3, 3, 3, 3, 2, 2, 2, 2, 3, 3, 3, 3,
198 | 0, 0, 0, 0, 1, 1, 1, 1, 0, 0, 0, 0, 1, 1, 1, 1,
199 | 0, 0, 0, 0, 1, 1, 1, 1, 0, 0, 0, 0, 1, 1, 1, 1,
200 | 2, 2, 2, 2, 3, 3, 3, 3, 2, 2, 2, 2, 3, 3, 3, 3,
201 | 2, 2, 2, 2, 3, 3, 3, 3, 2, 2, 2, 2, 3, 3, 3, 3,
202 | 0, 0, 0, 0, 1, 1, 1, 1, 0, 0, 0, 0, 1, 1, 1, 1,
203 | 0, 0, 0, 0, 1, 1, 1, 1, 0, 0, 0, 0, 1, 1, 1, 1,
204 | 2, 2, 2, 2, 3, 3, 3, 3, 2, 2, 2, 2, 3, 3, 3, 3,
205 | 2, 2, 2, 2, 3, 3, 3, 3, 2, 2, 2, 2, 3, 3, 3, 3,
206 | 4, 4, 4, 4, 5, 5, 5, 5, 4, 4, 4, 4, 5, 5, 5, 5,
207 | 4, 4, 4, 4, 5, 5, 5, 5, 4, 4, 4, 4, 5, 5, 5, 5,
208 | 6, 6, 6, 6, 7, 7, 7, 7, 6, 6, 6, 6, 7, 7, 7, 7,
209 | 6, 6, 6, 6, 7, 7, 7, 7, 6, 6, 6, 6, 7, 7, 7, 7,
210 | 4, 4, 4, 4, 5, 5, 5, 5, 4, 4, 4, 4, 5, 5, 5, 5,
211 | 4, 4, 4, 4, 5, 5, 5, 5, 4, 4, 4, 4, 5, 5, 5, 5,
212 | 6, 6, 6, 6, 7, 7, 7, 7, 6, 6, 6, 6, 7, 7, 7, 7,
213 | 6, 6, 6, 6, 7, 7, 7, 7, 6, 6, 6, 6, 7, 7, 7, 7,
214 | 4, 4, 4, 4, 5, 5, 5, 5, 4, 4, 4, 4, 5, 5, 5, 5,
215 | 4, 4, 4, 4, 5, 5, 5, 5, 4, 4, 4, 4, 5, 5, 5, 5,
216 | 6, 6, 6, 6, 7, 7, 7, 7, 6, 6, 6, 6, 7, 7, 7, 7,
217 | 6, 6, 6, 6, 7, 7, 7, 7, 6, 6, 6, 6, 7, 7, 7, 7,
218 | 4, 4, 4, 4, 5, 5, 5, 5, 4, 4, 4, 4, 5, 5, 5, 5,
219 | 4, 4, 4, 4, 5, 5, 5, 5, 4, 4, 4, 4, 5, 5, 5, 5,
220 | 6, 6, 6, 6, 7, 7, 7, 7, 6, 6, 6, 6, 7, 7, 7, 7,
221 | 6, 6, 6, 6, 7, 7, 7, 7, 6, 6, 6, 6, 7, 7, 7, 7
222 | };
--------------------------------------------------------------------------------
/extern/libmorton/libmorton/include/morton_BMI.h:
--------------------------------------------------------------------------------
1 | #pragma once
2 |
3 | #if defined(__BMI2__)
4 |
5 | #endif
--------------------------------------------------------------------------------
/extern/libmorton/libmorton/include/morton_LUT_generators.h:
--------------------------------------------------------------------------------
1 | #pragma once
2 |
3 | #include "morton2D.h"
4 | #include "morton3D.h"
5 | #include
6 |
7 | template
8 | void printTable(const element* table, size_t howmany, unsigned int splitat){
9 | for (size_t i = 0; i < howmany; i++){
10 | if (i % splitat == 0){ cout << endl; }
11 | printf("%u ,", static_cast(table[i]));
12 | }
13 | cout << endl;
14 | }
15 |
16 | void generate2D_EncodeLUT(size_t how_many_bits, uint_fast16_t*& x_table, uint_fast16_t*& y_table, bool print_tables){
17 | size_t total = 1 << how_many_bits;
18 | x_table = (uint_fast16_t*)malloc(total * sizeof(uint_fast16_t));
19 | y_table = (uint_fast16_t*)malloc(total * sizeof(uint_fast16_t));
20 |
21 | for (uint_fast32_t i = 0; i < total; i++){
22 | x_table[i] = (uint_fast16_t) m2D_e_magicbits(i, 0);
23 | y_table[i] = (uint_fast16_t)m2D_e_magicbits(0, i);
24 | }
25 |
26 | if (print_tables){
27 | cout << "X Table " << endl;
28 | printTable(x_table, total, 8);
29 | cout << "Y Table " << endl;
30 | printTable(y_table, total, 8);
31 | }
32 | }
33 |
34 | void generate2D_DecodeLUT(size_t how_many_bits, uint_fast8_t*& x_table, uint_fast8_t*& y_table, bool print_tables){
35 | size_t total = 1 << how_many_bits;
36 | x_table = (uint_fast8_t*)malloc(total * sizeof(uint_fast8_t));
37 | y_table = (uint_fast8_t*)malloc(total * sizeof(uint_fast8_t));
38 |
39 | //generate tables
40 | for (size_t i = 0; i < total; i++) {
41 | m2D_d_for(i, x_table[i], y_table[i]);
42 | }
43 |
44 | if (print_tables) {
45 | cout << "X Table " << endl;
46 | printTable(x_table, total, 16);
47 | cout << "Y Table " << endl;
48 | printTable(y_table, total, 16);
49 | }
50 | }
51 |
52 | void generate3D_EncodeLUT(size_t how_many_bits, uint_fast32_t*& x_table, uint_fast32_t*& y_table, uint_fast32_t*& z_table, bool print_tables){
53 | // how many items
54 | size_t total = 1 << how_many_bits;
55 | x_table = (uint_fast32_t*)malloc(total * sizeof(uint_fast32_t));
56 | y_table = (uint_fast32_t*)malloc(total * sizeof(uint_fast32_t));
57 | z_table = (uint_fast32_t*)malloc(total * sizeof(uint_fast32_t));
58 |
59 | for (uint_fast32_t i = 0; i < total; i++){
60 | x_table[i] = (uint_fast32_t) m3D_e_magicbits(i, 0, 0);
61 | y_table[i] = (uint_fast32_t) m3D_e_magicbits(0, i, 0);
62 | z_table[i] = (uint_fast32_t) m3D_e_magicbits(0, 0, i);
63 | }
64 |
65 | if (print_tables){
66 | cout << "X Table " << endl;
67 | printTable(x_table, total, 8);
68 | cout << "Y Table " << endl;
69 | printTable(y_table, total, 8);
70 | cout << "Z Table " << endl;
71 | printTable(z_table, total, 8);
72 | }
73 | }
74 |
75 | // Generate a decode tables for 3D morton code
76 | // how_many_bits should be a multiple of three
77 | void generate3D_DecodeLUT(size_t how_many_bits, uint_fast8_t*& x_table, uint_fast8_t*& y_table, uint_fast8_t*& z_table, bool print_tables){
78 | size_t total = 1 << how_many_bits;
79 | x_table = (uint_fast8_t*) malloc(total * sizeof(uint_fast8_t));
80 | y_table = (uint_fast8_t*) malloc(total * sizeof(uint_fast8_t));
81 | z_table = (uint_fast8_t*) malloc(total * sizeof(uint_fast8_t));
82 |
83 | //generate tables
84 | for (size_t i = 0; i < total; i++){
85 | x_table[i] = morton3D_GetThirdBits(i);
86 | y_table[i] = morton3D_GetThirdBits(i >> 1);
87 | z_table[i] = morton3D_GetThirdBits(i >> 2);
88 | }
89 |
90 | if (print_tables){
91 | cout << "X Table " << endl;
92 | printTable(x_table, total, 16);
93 | cout << "Y Table " << endl;
94 | printTable(y_table, total, 16);
95 | cout << "Z Table " << endl;
96 | printTable(z_table, total, 16);
97 | }
98 | }
99 |
--------------------------------------------------------------------------------
/extern/libmorton/libmorton/include/morton_common.h:
--------------------------------------------------------------------------------
1 | #pragma once
2 |
3 | // Libmorton - Common helper methods needed in Morton encoding/decoding
4 |
5 | #include
6 | #if _MSC_VER
7 | #include
8 | #endif
9 |
10 | template
11 | inline bool findFirstSetBit(const morton x, unsigned long* firstbit_location) {
12 | #if _MSC_VER && !_WIN64
13 | // 32 BIT on 32 BIT
14 | if (sizeof(morton) <= 4) {
15 | return _BitScanReverse(firstbit_location, x) != 0;
16 | }
17 | // 64 BIT on 32 BIT
18 | else {
19 | *firstbit_location = 0;
20 | if (_BitScanReverse(firstbit_location, (x >> 32))) { // check first part
21 | firstbit_location += 32;
22 | return true;
23 | }
24 | return _BitScanReverse(firstbit_location, (x & 0xFFFFFFFF)) != 0;
25 | }
26 | #elif _MSC_VER && _WIN64
27 | // 32 or 64 BIT on 64 BIT
28 | return _BitScanReverse64(firstbit_location, x) != 0;
29 | #elif __GNUC__
30 | if (x == 0) {
31 | return false;
32 | }
33 | else {
34 | *firstbit_location = static_cast((sizeof(morton)*8) - __builtin_clzll(x));
35 | return true;
36 | }
37 | #endif
38 | }
--------------------------------------------------------------------------------
/include/CompactNSearch:
--------------------------------------------------------------------------------
1 | #include "CompactNSearch.h"
2 |
--------------------------------------------------------------------------------
/include/CompactNSearch.h:
--------------------------------------------------------------------------------
1 | #pragma once
2 |
3 | #include "Config.h"
4 | #include "DataStructures.h"
5 | #include "PointSet.h"
6 |
7 | #include
8 |
9 | namespace CompactNSearch
10 | {
11 |
12 | struct NeighborhoodSearchNotInitialized : public std::exception
13 | {
14 | virtual char const* what() const noexcept override { return "Neighborhood search was not initialized."; }
15 | };
16 |
17 | /**
18 | * @class NeighborhoodSearch
19 | * Stores point data multiple set of points in which neighborhood information for a fixed
20 | * radius r should be generated.
21 | */
22 | class NeighborhoodSearch
23 | {
24 |
25 | public:
26 |
27 | /**
28 | * Constructor.
29 | * Creates a new instance of the neighborhood search class.
30 | * @param r Search radius. If two points are closer to each other than a distance r they are considered neighbors.
31 | * @param erase_empty_cells If true. Empty cells in spatial hashing grid are erased if the points move.
32 | */
33 | NeighborhoodSearch(Real r, bool erase_empty_cells = false);
34 |
35 | /**
36 | * Destructor.
37 | */
38 | virtual ~NeighborhoodSearch() = default;
39 |
40 | /**
41 | * Get method to access a point set.
42 | * @param i Index of the point set to retrieve.
43 | */
44 | PointSet const& point_set(unsigned int i) const { return m_point_sets[i]; }
45 |
46 | /**
47 | * Get method to access a point set.
48 | * @param i Index of the point set to retrieve.
49 | */
50 | PointSet & point_set(unsigned int i) { return m_point_sets[i]; }
51 |
52 |
53 | /**
54 | * Returns the number of point sets contained in the search.
55 | */
56 | std::size_t n_point_sets() const { return m_point_sets.size(); }
57 |
58 | /**
59 | * Get method to access the list of point sets.
60 | */
61 | std::vector const& point_sets() const { return m_point_sets; }
62 |
63 | /**
64 | * Get method to access the list of point sets.
65 | */
66 | std::vector & point_sets() { return m_point_sets; }
67 |
68 | /**
69 | * Increases the size of a point set under the assumption that the existing points remain at
70 | * the same position.
71 | * @param i Index of point set that will be resized.
72 | * @param x Pointer to the point position data. Must point to continguous data of 3 * n
73 | * real values.
74 | * @param n Number of points.
75 | */
76 | void resize_point_set(unsigned int i, Real const* x, std::size_t n);
77 |
78 | /**
79 | * Creates and adds a new set of points.
80 | * @param x Pointer to the point position data. Must point to continguous data of 3 * n
81 | * real values.
82 | * @param n Number of points.
83 | * @param is_dynamic Specifies whether the point positions will change for future queries.
84 | * @param search_neighbors If true, neighbors in all other point sets are searched.
85 | * @param find_neighbors If true, the new point set is activated in the neighborhood search of all other point sets.
86 | * @returns Returns unique identifier in form of an index assigned to the newly created point
87 | * set.
88 | */
89 | unsigned int add_point_set(Real const* x, std::size_t n, bool is_dynamic = true,
90 | bool search_neighbors = true, bool find_neighbors = true, void *user_data = nullptr)
91 | {
92 | m_point_sets.push_back({x, n, is_dynamic, user_data});
93 | m_activation_table.add_point_set(search_neighbors, find_neighbors);
94 | return static_cast(m_point_sets.size() - 1);
95 | }
96 |
97 | /**
98 | * Performs the actual query. This method will assign a list of neighboring points to each point
99 | * every added point set.
100 | */
101 | void find_neighbors(bool points_changed = true);
102 |
103 | /**
104 | * Performs the actual query for a single point. This method returns a list of neighboring points. Note: That points_changed() must be called each time
105 | * when the positions of a point set changed.
106 | */
107 | void find_neighbors(unsigned int point_set_id, unsigned int point_index, std::vector> &neighbors);
108 |
109 | /**
110 | * Performs the actual query for a single point x. This method returns a list of neighboring points in all existing point sets. Note: That points_changed() must be called each time
111 | * when the positions of a point set changed.
112 | */
113 | void find_neighbors(Real const* x, std::vector> &neighbors);
114 |
115 | /**
116 | * Update neighborhood search data structures after a position change.
117 | * If general find_neighbors() function is called there is no requirement to manually update the point sets.
118 | * Otherwise, in case of using point-wise search (find_neighbors(i, j, neighbors)) the method must be called explicitly.
119 | * TODO: Implement function for individual pointset. -> update_point_set(i)
120 | */
121 | void update_point_sets();
122 |
123 | /**
124 | * Update neighborhood search data structures after changing the activation table.
125 | * If general find_neighbors() function is called there is no requirement to manually update the point sets.
126 | * Otherwise, in case of using point-wise search (find_neighbors(i, j, neighbors)) the method must be called explicitly.
127 | */
128 | void update_activation_table();
129 |
130 |
131 | /*
132 | * Generates a sort table according to a space-filling Z curve. Any array-based per point
133 | * information can then be reordered using the function sort_field of the PointSet class.
134 | * Please note that the position data will not be modified by this class, such that the user has
135 | * to invoke the sort_field function on the position array. Moreover, be aware the the grid has
136 | * be reinitialized after each sort. Therefore, the points should not be reordered too
137 | * frequently.
138 | */
139 | void z_sort();
140 |
141 | /*
142 | * @returns Returns the radius in which point neighbors are searched.
143 | */
144 | Real radius() const { return std::sqrt(m_r2); }
145 |
146 | /**
147 | * Sets the radius in which point point neighbors are searched.
148 | * @param r Search radius.
149 | */
150 | void set_radius(Real r)
151 | {
152 | m_r2 = r * r;
153 | m_inv_cell_size = static_cast(1.0 / r);
154 | m_initialized = false;
155 | }
156 |
157 | /** Activate/deactivate that neighbors in point set j are found when searching for neighbors of point set i.
158 | * @param i Index of searching point set.
159 | * @param j Index of point set of which points should/shouldn't be found by point set i.
160 | * @param active Flag in order to (de)activate that points in i find point in j.
161 | */
162 | void set_active(unsigned int i, unsigned int j, bool active)
163 | {
164 | m_activation_table.set_active(i, j, active);
165 | m_initialized = false;
166 | }
167 |
168 | /** Activate/Deactivate all point set pairs containing the given index. If search_neighbors is true, neighbors in all other point sets are searched.
169 | * If find_neighbors is true, the new point set is activated in the neighborhood search of all other point sets.
170 | * @param i Index of searching point set.
171 | * @param search_neighbors If true/false enables/disables that point set i searches points in all other point sets.
172 | * @param find_neighbors If true/false enable/disables that point set i is found by all other point sets.
173 | */
174 | void set_active(unsigned int i, bool search_neighbors = true, bool find_neighbors = true)
175 | {
176 | m_activation_table.set_active(i, search_neighbors, find_neighbors);
177 | m_initialized = false;
178 | }
179 |
180 | /** Activate/Deactivate all point set pairs.
181 | */
182 | void set_active(bool active)
183 | {
184 | m_activation_table.set_active(active);
185 | m_initialized = false;
186 | }
187 |
188 | /** Returns true if point set i searchs points in point set j.
189 | * @param i Searching point set.
190 | * @param j Set of points to be found by i.
191 | */
192 | bool is_active(unsigned int i, unsigned int j) const
193 | {
194 | return m_activation_table.is_active(i, j);
195 | }
196 |
197 | private:
198 |
199 | void init();
200 | void update_hash_table(std::vector& to_delete);
201 | void erase_empty_entries(std::vector const& to_delete);
202 | void query();
203 | void query(unsigned int point_set_id, unsigned int point_index, std::vector> &neighbors);
204 | void query(Real const* xa, std::vector> &neighbors);
205 |
206 | HashKey cell_index(Real const* x) const;
207 |
208 | private:
209 |
210 |
211 | std::vector m_point_sets;
212 | ActivationTable m_activation_table, m_old_activation_table;
213 |
214 | Real m_inv_cell_size;
215 | Real m_r2;
216 | std::unordered_map m_map;
217 | std::vector m_entries;
218 |
219 | bool m_erase_empty_cells;
220 | bool m_initialized;
221 | };
222 |
223 | }
224 |
--------------------------------------------------------------------------------
/include/Config.h:
--------------------------------------------------------------------------------
1 | #pragma once
2 |
3 | namespace CompactNSearch
4 | {
5 | #ifdef USE_DOUBLE
6 | using Real = double;
7 | #else
8 | using Real = float;
9 | #endif
10 | }
11 |
12 | #define INITIAL_NUMBER_OF_INDICES 50
13 | #define INITIAL_NUMBER_OF_NEIGHBORS 50
14 |
15 | #ifdef _MSC_VER
16 | #include
17 | #elif defined(__APPLE__) && defined(__clang__)
18 | #include
19 | #include
20 | #else
21 | #include
22 | #endif
23 |
--------------------------------------------------------------------------------
/include/DataStructures.h:
--------------------------------------------------------------------------------
1 | #pragma once
2 |
3 | #include "Config.h"
4 |
5 | #include