CellModules
grid.hpp
Go to the documentation of this file.
1#ifndef GRID_HPP
2#define GRID_HPP
3
4#include <array>
5#include <deque>
6#include <iostream>
7#include <set>
8#include <unordered_map>
9#include <vector>
11#include "unique_vector.hpp"
12#include "utils.hpp"
13
14namespace MecaCell {
15
21template <typename O> class Grid {
22 private:
23 double cellSize; // actually it's 1/cellSize, just so we can multiply instead of divide
24 std::unordered_map<Vec, size_t> um; // position -> orderedVec index
26
27 public:
28 Grid(double cs) : cellSize(1.0 / cs) {}
29 size_t size() { return um.size(); };
31 std::unordered_map<Vec, size_t> &getUnorderedMap() { return um; }
32
33 double getCellSize() const { return 1.0 / cellSize; }
34
36 return orderedVec;
37 }
38
39 std::array<vector<vector<O>>, 8> getThreadSafeGrid() const {
40 // same color batches can be safely treated in parallel (if max O size < cellSize)
41 std::array<std::vector<std::vector<O>>, 8> res;
42 for (const auto &c : orderedVec) res[vecToColor(c.first)].push_back(c.second);
43 return res;
44 }
45
46 std::array<vector<vector<O>>, 8> getThreadSafeGrid(size_t minEl) const {
47 // same color batches can be safely treated in parallel (if max O size < cellSize)
48 std::array<std::vector<std::vector<O>>, 8> res;
49 for (const auto &c : orderedVec) res[vecToColor(c.first)].push_back(c.second);
50 if (minEl > 1) {
51 for (auto &color : res) {
52 if (color.size() > 1) {
53 for (auto it = std::next(color.begin()); it != color.end();) {
54 if ((*std::prev(it)).size() <
55 minEl) { // batch too small, we merge with the previous one
56 auto &b = *it; // current batch
57 auto pv = std::prev(it);
58 auto &a = *pv; // prev one
59 a.insert(a.end(), b.begin(), b.end());
60 it = color.erase(it);
61 } else {
62 ++it;
63 }
64 }
65 }
66 }
67 }
68 return res;
69 }
70
71 inline size_t vecToColor(const Vec &v) const {
72 return (abs((int)v.x()) % 2) + (abs((int)v.y()) % 2) * 2 + (abs((int)v.z()) % 2) * 4;
73 }
74
75 template <typename V> void insert(V &&k, const O &o) {
76 if (!um.count(std::forward<V>(k))) {
77 um[std::forward<V>(k)] = orderedVec.size();
78 orderedVec.push_back({std::forward<V>(k), std::vector<O>()});
79 }
80 orderedVec[um[std::forward<V>(k)]].second.push_back(o);
81 }
82
83 void insertOnlyCenter(const O &obj) {
84 insert(getIndexFromPosition(ptr(obj)->getPosition()), obj);
85 }
86
87 void insert(const O &obj) {
88 const Vec &center = ptr(obj)->getPosition();
89 const double &radius = ptr(obj)->getBoundingBoxRadius();
90 Vec minCorner = getIndexFromPosition(center - radius);
91 Vec maxCorner = getIndexFromPosition(center + radius);
92 for (double i = minCorner.x(); i <= maxCorner.x(); ++i) {
93 for (double j = minCorner.y(); j <= maxCorner.y(); ++j) {
94 for (double k = minCorner.z(); k <= maxCorner.z(); ++k) {
95 insert(Vec(i, j, k), obj);
96 }
97 }
98 }
99 }
100
101 // double cx = i * cubeSize;
102 // if (abs(cx - center.x()) > abs(cx + cubeSize - center.x())) cx += cubeSize;
103 // double cy = j * cubeSize;
104 // if (abs(cy - center.y()) > abs(cy + cubeSize - center.y())) cy += cubeSize;
105 // double cz = k * cubeSize;
106 // if (abs(cz - center.z()) > abs(cz + cubeSize - center.z())) cz += cubeSize;
107
108 void insertPrecise(const O &obj) {
109 // good for gridSize << boundingboxRadius
110 const Vec &center = ptr(obj)->getPosition();
111 const double &radius = ptr(obj)->getBoundingBoxRadius();
112 const double sqRadius = radius * radius;
113 const double cubeSize = 1.0 / cellSize;
114 Vec minCorner = getIndexFromPosition(center - radius);
115 Vec maxCorner = getIndexFromPosition(center + radius);
116 for (double i = minCorner.x(); i <= maxCorner.x(); ++i) {
117 for (double j = minCorner.y(); j <= maxCorner.y(); ++j) {
118 for (double k = minCorner.z(); k <= maxCorner.z(); ++k) {
119 // we test if this cube's center overlaps with the sphere
120 // i j k coords are the bottom front left coords of a 1/cellSize cube
121 // we need the closest corner of a grid cell relative to the center of the obj
122
123 double cx = (i + 0.5) * cubeSize;
124 // if (abs(cx - center.x()) > abs(cx + cubeSize - center.x())) cx += cubeSize;
125 double cy = (j + 0.5) * cubeSize;
126 // if (abs(cy - center.y()) > abs(cy + cubeSize - center.y())) cy += cubeSize;
127 double cz = (k + 0.5) * cubeSize;
128 // if (abs(cz - center.z()) > abs(cz + cubeSize - center.z())) cz += cubeSize;
129
130 Vec cubeCenter(cx, cy, cz);
131 // std::cerr << "Pour centre = " << center << ", rayon = " << radius
132 //<< ", cubeSize = " << cubeSize << " : minCorner = " << minCorner
133 //<< ", maxCorner = " << maxCorner << ", bfl = " << Vec(i, j, k)
134 //<< "(soit " << Vec(i * cubeSize, j * cubeSize, k * cubeSize)
135 //<< ") et closestCorner = " << cubeCenter;
136
137 if ((cubeCenter - center).sqlength() < sqRadius) {
138 // std::cerr << " [OK]" << std::endl;
139 insert(Vec(i, j, k), obj);
140 } else {
141 // std::cerr << " [REFUS]" << std::endl;
142 }
143 }
144 }
145 }
146 }
147
148 void insert(const O &obj, const Vec &p0, const Vec &p1,
149 const Vec &p2) { // insert triangles
150 Vec blf(min(p0.x(), min(p1.x(), p2.x())), min(p0.y(), min(p1.y(), p2.y())),
151 min(p0.z(), min(p1.z(), p2.z())));
152 Vec trb(max(p0.x(), max(p1.x(), p2.x())), max(p0.y(), max(p1.y(), p2.y())),
153 max(p0.z(), max(p1.z(), p2.z())));
154 double cs = 1.0 / cellSize;
155 getIndexFromPosition(blf).iterateTo(getIndexFromPosition(trb) + 1, [&](const Vec &v) {
156 Vec center = cs * v;
157 std::pair<bool, Vec> projec = projectionIntriangle(p0, p1, p2, center);
158 if ((center - projec.second).sqlength() < 0.8 * cs * cs) {
159 if (projec.first || closestDistToTriangleEdge(p0, p1, p2, center) < 0.87 * cs) {
160 insert(v, obj);
161 }
162 }
163 });
164 }
165
166 Vec getIndexFromPosition(const Vec &v) const {
167 Vec res = v * cellSize;
168 return Vec(floor(res.x()), floor(res.y()), floor(res.z()));
169 }
170
171 vector<O> retrieve(const Vec &center, double radius) const {
173 Vec minCorner = getIndexFromPosition(center - radius);
174 Vec maxCorner = getIndexFromPosition(center + radius);
175 for (double i = minCorner.x(); i <= maxCorner.x(); ++i) {
176 for (double j = minCorner.y(); j <= maxCorner.y(); ++j) {
177 for (double k = minCorner.z(); k <= maxCorner.z(); ++k) {
178 const Vector3D v(i, j, k);
179 if (um.count(v))
180 res.insert(orderedVec[um.at(v)].second.begin(),
181 orderedVec[um.at(v)].second.end());
182 }
183 }
184 }
185 return res.getUnderlyingVector();
186 }
187
188 vector<O> retrieve(const O &obj) const {
189 return retrieve(ptr(obj)->getPosition(), ptr(obj)->getBoundingBoxRadius());
190 }
191
192 double computeSurface() const {
193 if (Vec::dimension == 3) {
194 double res = 0.0; // first = surface, second = volume;
195 double faceArea = pow(1.0 / cellSize, 2);
196 for (auto &i : um) {
197 res += (6.0 - static_cast<double>(getNbNeighbours(i.first))) * faceArea;
198 }
199 return res;
200 }
201 return pow(1.0 / cellSize, 2) * static_cast<double>(um.size());
202 }
203
204 double getVolume() const {
205 if (Vec::dimension == 3)
206 return pow(1.0 / cellSize, 3) * static_cast<double>(um.size());
207 return 0.0;
208 }
209
210 double computeSphericity() const {
211 auto s = computeSurface();
212 if (s <= 0) return -1;
213 return (cbrt(M_PI) * (pow(6.0 * getVolume(), (2.0 / 3.0)))) / s;
214 }
215
216 // nb of occupied neighbour grid cells
217 int getNbNeighbours(const Vec &cell) const {
218 int res = 0;
219 if (um.count(cell - Vec(0, 0, 1))) ++res;
220 if (um.count(cell - Vec(0, 1, 0))) ++res;
221 if (um.count(cell - Vec(1, 0, 0))) ++res;
222 if (um.count(cell + Vec(0, 0, 1))) ++res;
223 if (um.count(cell + Vec(0, 1, 0))) ++res;
224 if (um.count(cell + Vec(1, 0, 0))) ++res;
225 return res;
226 }
227
228 void clear() {
229 um.clear();
230 orderedVec = decltype(orderedVec)();
231 }
232};
233} // namespace MecaCell
234#endif
double getBoundingBoxRadius() const
Definition: CellBody.hpp:65
double radius
Definition: CellBody.hpp:33
Infinite grid of fixed cell size for space partitioning.
Definition: grid.hpp:21
void clear()
Definition: grid.hpp:228
std::array< vector< vector< O > >, 8 > getThreadSafeGrid() const
Definition: grid.hpp:39
double computeSurface() const
Definition: grid.hpp:192
void insertOnlyCenter(const O &obj)
Definition: grid.hpp:83
void insert(const O &obj, const Vec &p0, const Vec &p1, const Vec &p2)
Definition: grid.hpp:148
Grid(double cs)
Definition: grid.hpp:28
std::array< vector< vector< O > >, 8 > getThreadSafeGrid(size_t minEl) const
Definition: grid.hpp:46
std::unordered_map< Vec, size_t > & getUnorderedMap()
Definition: grid.hpp:31
double computeSphericity() const
Definition: grid.hpp:210
vector< O > retrieve(const Vec &center, double radius) const
Definition: grid.hpp:171
double cellSize
Definition: grid.hpp:23
std::vector< std::pair< Vec, std::vector< O > > > orderedVec
Definition: grid.hpp:25
size_t vecToColor(const Vec &v) const
Definition: grid.hpp:71
double getVolume() const
Definition: grid.hpp:204
vector< O > retrieve(const O &obj) const
Definition: grid.hpp:188
std::unordered_map< Vec, size_t > um
Definition: grid.hpp:24
void insert(const O &obj)
Definition: grid.hpp:87
const std::vector< std::pair< Vec, std::vector< O > > > & getContent() const
Definition: grid.hpp:35
size_t size()
Definition: grid.hpp:29
int getNbNeighbours(const Vec &cell) const
Definition: grid.hpp:217
Vec getIndexFromPosition(const Vec &v) const
Definition: grid.hpp:166
double getCellSize() const
Definition: grid.hpp:33
void insertPrecise(const O &obj)
Definition: grid.hpp:108
void insert(V &&k, const O &o)
Definition: grid.hpp:75
std::vector< std::pair< Vec, std::vector< O > > > & getOrderedVec()
Definition: grid.hpp:30
general purpose 3D vector/point class.
Definition: vector3D.h:20
double x() const
Definition: vector3D.h:94
double y() const
Definition: vector3D.h:100
static const int dimension
Definition: vector3D.h:24
double z() const
Definition: vector3D.h:106
void iterateTo(const Vector3D &v, const std::function< void(const Vector3D &)> &fun, const double inc=1) const
helper method to iterates over a 3D rectangular cuboid bounded by two corner vectors
Definition: vector3D.h:498
A simple vector class template.
Definition: std.hpp:290
void insert(U &&u)
const std::vector< T > & getUnderlyingVector() const
this file contains various miscellanious utility functions & helpers *
T * ptr(T &obj)
returns a pointer (transforms reference into pointer)
Definition: utils.hpp:32
std::pair< bool, Vec > projectionIntriangle(const Vec &v0, const Vec &v1, const Vec &v2, const Vec &p, const double tolerance=0)
tests if the projection of a point along the normal of a triangle is inside said triangle
Definition: geometry.hpp:53
Vector3D Vec
alias for Vector3D
Definition: utils.hpp:22
double closestDistToTriangleEdge(const Vec &v0, const Vec &v1, const Vec &v2, const Vec &p)
computes the smallest distance to a triangle edge from a given point
Definition: geometry.hpp:79
int abs(int x)
Computes the absolute value of an integer.
Definition: std.hpp:83
double cbrt(double x)
Computes the cube root of a number.
Definition: std.hpp:215
double floor(double x)
Computes the floor of a number.
Definition: std.hpp:194
double pow(double base, double exponent)
Computes the power of a number.
Definition: std.hpp:43