68template<
typename Scalar>
77 : cs_(
cell_size), xmin_(xmin), ymin_(ymin)
80 nx_ =
static_cast<int>(std::ceil((xmax - xmin) / cs_)) + 2;
81 ny_ =
static_cast<int>(std::ceil((ymax - ymin) / cs_)) + 2;
82 const int total = nx_ * ny_;
83 start_.assign(total + 1, 0);
84 count_.assign(total, 0);
92 template<
typename PosAccessor>
95 const int total = nx_ * ny_;
98 std::fill(count_.begin(), count_.end(), 0);
99 for (
int i = 0;
i < n; ++
i)
104 for (
int c = 0; c < total; ++c)
105 start_[c + 1] = start_[c] + count_[c];
108 std::fill(count_.begin(), count_.end(), 0);
109 for (
int i = 0;
i < n; ++
i) {
111 sorted_[start_[
cid] + count_[
cid]] =
i;
122 const int cx = cell_x(
px);
123 const int cy = cell_y(
py);
124 for (
int dy = -1;
dy <= 1; ++
dy) {
125 const int qy = cy +
dy;
127 for (
int dx = -1; dx <= 1; ++dx) {
128 const int qx = cx + dx;
131 for (
int k = start_[
cid];
k < start_[
cid + 1]; ++
k)
148 static constexpr int FDX[4] = {+1, 0, +1, -1};
149 static constexpr int FDY[4] = { 0, +1, +1, +1};
151 for (
int cy = 0; cy < ny_; ++cy) {
152 for (
int cx = 0; cx < nx_; ++cx) {
153 const int cid = cy * nx_ + cx;
154 const int beg = start_[
cid];
155 const int end = start_[
cid + 1];
156 if (
beg == end)
continue;
159 for (
int a =
beg;
a < end; ++
a) {
160 for (
int b =
a + 1;
b < end; ++
b) {
161 f(sorted_[
a], sorted_[
b]);
166 for (
int d = 0;
d < 4; ++
d) {
174 for (
int a =
beg;
a < end; ++
a) {
176 f(sorted_[
a], sorted_[
b]);
186 const int cid = cy * nx_ + cx;
187 return { sorted_.data() + start_[
cid],
188 sorted_.data() + start_[
cid + 1] };
199 std::vector<int> sorted_;
200 std::vector<int> start_;
201 std::vector<int> count_;
203 int cell_x(
Scalar x)
const noexcept {
205 const int cx =
static_cast<int>(std::floor((x - xmin_) / cs_)) + 1;
206 return cx < 0 ? 0 : (cx >= nx_ ? nx_ - 1 : cx);
208 int cell_y(
Scalar y)
const noexcept {
209 const int cy =
static_cast<int>(std::floor((y - ymin_) / cs_)) + 1;
210 return cy < 0 ? 0 : (cy >= ny_ ? ny_ - 1 : cy);
212 int cell_id_of(std::pair<Scalar, Scalar> p)
const noexcept {
213 return cell_y(p.second) * nx_ + cell_x(p.first);
void query(Scalar px, Scalar py, F &&f) const
Point query: calls f(int j) for every particle in the 3x3 cell neighbourhood of (px,...
void iterate_pairs(F &&f) const
Newton's 3rd law pair traversal.
CellList2D(Scalar cell_size, Scalar xmin, Scalar xmax, Scalar ymin, Scalar ymax)
int n_particles() const noexcept
IntRange cell_particles(int cx, int cy) const noexcept
Direct access to sorted particle indices for cell (cx, cy).
void build(PosAccessor &&get_pos, int n)
Rebuild the cell list from n particles.
constexpr T ipow(T x) noexcept
Compute x^N at compile time via repeated squaring.
Lightweight read-only range over a contiguous int array (C++17-safe span).
const int * begin() const noexcept
bool empty() const noexcept
const int * end() const noexcept
int size() const noexcept