1#include "GLPointVisualModule.h"
2#include "PoissonDiskSampling.h"
9 template <typename TDataType>
10 PoissonDiskSampling<TDataType>::PoissonDiskSampling()
11 : SdfSampler<TDataType>()
13 this->varSpacing()->setRange(0.001, 1.0);
14 area_a = this->varBox_a()->getData() - Coord(this->varSpacing()->getData() * 3);
15 area_b = this->varBox_b()->getData() + Coord(this->varSpacing()->getData() * 3);
16 desired_points = pointNumberRecommend();
19 template <typename TDataType>
20 int PoissonDiskSampling<TDataType>::pointNumberRecommend()
23 Coord box = area_b - area_a;
24 Real r = this->varSpacing()->getData();
26 (area_b[0] - area_a[0]) * (area_b[1] - area_a[1]) * (area_b[2] - area_a[2]) / (r * r * r);
29 template <typename TDataType>
30 void PoissonDiskSampling<TDataType>::ConstructGrid()
32 auto r = this->varSpacing()->getData();
39 std::cout << " The smapling distance in Poisson disk sampling module can not be ZERO!!!! " << std::endl;
43 nx = abs(area_b[0] - area_a[0]) / dx;
44 ny = abs(area_b[1] - area_a[1]) / dx;
45 nz = abs(area_b[2] - area_a[2]) / dx;
50 for (int i = 0; i < gnum; i++) m_grid[i] = -1;
54 template <typename TDataType>
55 GridIndex PoissonDiskSampling<TDataType>::searchGrid(Coord point)
58 index.i = (int)((point[0] - area_a[0]) / dx);
59 index.j = (int)((point[1] - area_a[1]) / dx);
60 index.k = (int)((point[2] - area_a[2]) / dx);
65 template <typename TDataType>
66 int PoissonDiskSampling<TDataType>::indexTransform(int i, int j, int k)
68 return i + j * nx + k * nx * ny;
72 template <typename TDataType>
73 bool PoissonDiskSampling<TDataType>::collisionJudge2D(Coord point)
76 auto r = this->varSpacing()->getData();
78 d_index = searchGrid(point);
79 for (int i = -2; i < 3; i++)
80 for (int j = -2; j < 3; j++)
82 int mi = d_index.i + i;
83 int mj = d_index.j + j;
84 if ((mi > 0) && (mj > 0) && (mi < nx) && (mj < ny))
86 int index = indexTransform(mi, mj, d_index.k);
87 if (m_grid[index] != -1)
89 Coord d = (points[m_grid[index]] - point);
90 if (sqrt(d[0] * d[0] + d[1] * d[1]) - r < EPSILON)
100 template <typename TDataType>
101 bool PoissonDiskSampling<TDataType>::collisionJudge(Coord point)
105 auto r = this->varSpacing()->getData();
107 d_index = searchGrid(point);
108 for (int i = -2; i < 3; i++)
109 for (int j = -2; j < 3; j++)
110 for (int k = -2; k < 3; k++)
113 int mi = d_index.i + i;
114 int mj = d_index.j + j;
115 int mk = d_index.k + k;
116 if ((mi > 0) && (mj > 0) && (mk > 0) && (mi < nx) && (mj < ny) && (mk < nz))
118 int index = indexTransform(mi, mj, mk);
119 if (m_grid[index] != -1)
121 Coord d = (points[m_grid[index]] - point);
122 if (sqrt(d[0] * d[0] + d[1] * d[1] + d[2] * d[2]) - r < EPSILON)
133 template<typename TDataType>
134 std::shared_ptr<DistanceField3D<TDataType>> PoissonDiskSampling<TDataType>::loadSdf()
136 auto varfilename = this->varSdfFileName()->getData();
137 auto filename = varfilename.string();
139 std::shared_ptr<DistanceField3D<TDataType>> sdf = std::make_shared<DistanceField3D<TDataType>>();
141 if (filename.size() > 0)
144 if (filename.size() < 5 || filename.substr(filename.size() - 4) != std::string(".sdf")) {
145 std::cerr << "Error: Expected OBJ file with filename of the form <name>.obj.\n";
149 std::ifstream infile(filename);
151 std::cerr << "Failed to open. Terminating.\n";
157 sdf->loadSDF(filename, false);
159 area_a = sdf->lowerBound();
160 area_b = sdf->upperBound();
162 this->varBox_a()->setValue(area_a);
163 this->varBox_b()->setValue(area_b);
165 m_h = sdf->getGridSpacing();
166 m_left = sdf->lowerBound();
168 std::cout << "SDF is loaded: " << area_a << ", " << area_b << std::endl;
178 template<typename Real, typename Coord, typename TDataType>
179 __global__ void PDS_PosDetect
181 DArray<Coord> posArr,
182 DistanceField3D<TDataType> df,
186 int pId = threadIdx.x + (blockIdx.x * blockDim.x);
187 if (pId >= posArr.size()) return;
188 Coord pos = posArr[pId];
191 df.getDistance(pos, temp_dist, normal);
192 dist[pId] = temp_dist;
198 template <typename TDataType>
199 typename TDataType::Real PoissonDiskSampling<TDataType>::lerp(Real a, Real b, Real alpha)
201 return (1.0f - alpha) * a + alpha * b;
205 template <typename TDataType>
206 typename TDataType::Real PoissonDiskSampling<TDataType>::getDistanceFromSDF(const Coord& p,
215 Coord fp = (p - m_left) * Coord(1.0 / m_h, 1.0 / m_h, 1.0 / m_h);
216 const int i = (int)floor(fp[0]);
217 const int j = (int)floor(fp[1]);
218 const int k = (int)floor(fp[2]);
220 bool m_bInverted = false;
222 if (i < 0 || i >= host_dist.nx() - 1 || j < 0 || j >= host_dist.ny() - 1 || k < 0 || k >= host_dist.nz() - 1) {
223 if (m_bInverted) d = -100000.0f;
229 Coord ip = Coord(i, j, k);
231 Coord alphav = fp - ip;
232 Real alpha = alphav[0];
233 Real beta = alphav[1];
234 Real gamma = alphav[2];
237 Real d000 = host_dist(i, j, k);
238 Real d100 = host_dist(i + 1, j, k);
239 Real d010 = host_dist(i, j + 1, k);
240 Real d110 = host_dist(i + 1, j + 1, k);
241 Real d001 = host_dist(i, j, k + 1);
242 Real d101 = host_dist(i + 1, j, k + 1);
243 Real d011 = host_dist(i, j + 1, k + 1);
244 Real d111 = host_dist(i + 1, j + 1, k + 1);
246 Real dx00 = lerp(d000, d100, alpha);
247 Real dx10 = lerp(d010, d110, alpha);
248 Real dxy0 = lerp(dx00, dx10, beta);
250 Real dx01 = lerp(d001, d101, alpha);
251 Real dx11 = lerp(d011, d111, alpha);
252 Real dxy1 = lerp(dx01, dx11, beta);
254 Real d0y0 = lerp(d000, d010, beta);
255 Real d0y1 = lerp(d001, d011, beta);
256 Real d0yz = lerp(d0y0, d0y1, gamma);
258 Real d1y0 = lerp(d100, d110, beta);
259 Real d1y1 = lerp(d101, d111, beta);
260 Real d1yz = lerp(d1y0, d1y1, gamma);
262 Real dx0z = lerp(dx00, dx01, gamma);
263 Real dx1z = lerp(dx10, dx11, gamma);
265 normal[0] = d0yz - d1yz;
266 normal[1] = dx0z - dx1z;
267 normal[2] = dxy0 - dxy1;
269 Real l = normal.norm();
270 if (l < 0.0001f) normal = Coord(0);
271 else normal = normal.normalize();
273 d = (1.0f - gamma) * dxy0 + gamma * dxy1;
277 template<typename TDataType>
278 typename TDataType::Coord PoissonDiskSampling<TDataType>::getOnePointInsideSDF()
281 for (Real ax = area_a[0]; ax < area_b[0]; ax += this->varSpacing()->getData())
282 for (Real ay = area_a[1]; ay < area_b[1]; ay += this->varSpacing()->getData())
283 for (Real az = area_a[2]; az < area_b[2]; az += this->varSpacing()->getData())
285 Real dr = getDistanceFromSDF(Coord(ax, ay, az), normal);
288 return Coord(ax, ay, az);
294 template<typename TDataType>
295 void PoissonDiskSampling<TDataType>::resetStates()
298 Real r = this->varSpacing()->getData();
300 auto vol = this->getVolume();
302 //Adaptive mesh to uniform mesh
303 inputSDF = this->convert2Uniform(vol, r);
305 Coord minPoint = inputSDF->lowerBound();
306 Coord maxPoint = inputSDF->upperBound();
307 area_a = minPoint - Coord(r * 3);
308 area_b = maxPoint + Coord(r * 3);
309 this->varBox_a()->setValue(area_a);
310 this->varBox_b()->setValue(area_b);
311 m_h = inputSDF->getGridSpacing();
312 m_left = inputSDF->lowerBound();
314 host_dist.resize(inputSDF->nx(), inputSDF->ny(), inputSDF->nz());
315 host_dist.assign(inputSDF->distances());
320 desired_points = pointNumberRecommend();
322 std::cout << "Poisson Disk Sampling Start." << std::endl;
325 this->ConstructGrid();
326 seed_point = (area_a + (area_b - area_a)) / 2;
328 /*The seed point must be inside the .SDF boundary */
329 seed_point = getOnePointInsideSDF();
331 points.push_back(seed_point);
332 gridIndex = searchGrid(seed_point);
333 int index = indexTransform(gridIndex.i, gridIndex.j, gridIndex.k);
339 while ((head < desired_points) && (head < tail))
341 Coord source = points[head];
343 for (int ppp = 0; ppp < attempted_Times; ppp++)
345 Real theta = (Real)(rand() % 100) / 100.0f;
346 theta = theta * 2 * 3.1415926535;
348 Real phi = (Real)(rand() % 100) / 100.0f;
349 phi = phi * 2 * 3.1415926535;
351 Real dr = (1 + (Real)(rand() % 100) / 100.0f) * r;
354 offset = Coord(cos(theta) * sin(phi) * dr, sin(theta) * sin(phi) * dr, cos(phi) * r);
356 Coord new_point = source + offset;
358 if (((new_point[0] > area_a[0] + r * 3) && (new_point[0] < area_b[0] - r * 3)
359 && (new_point[1] > area_a[1] + r * 3) && (new_point[1] < area_b[1] - r * 3)
360 && (new_point[2] > area_a[2] + r * 3) && (new_point[2] < area_b[2] - r * 3)
363 if (!collisionJudge(new_point) && (tail < desired_points) && (getDistanceFromSDF(new_point, normal) < 0.0f)) {
364 points.push_back(new_point);
365 gridIndex = searchGrid(new_point);
366 m_grid[indexTransform(gridIndex.i, gridIndex.j, gridIndex.k)] = tail;
373 auto ptSet = this->statePointSet()->getDataPtr();
374 ptSet->setPoints(points);
375 std::cout << "Poisson Disk Sampling is finished." << std::endl;
380 DEFINE_CLASS(PoissonDiskSampling);