1/* Copyright (c) 2011 Khaled Mamou (kmamou at gmail dot com)
2All rights reserved.
3
4
5Redistribution and use in source and binary forms, with or without modification, are permitted provided that the following conditions are met:
6
71. Redistributions of source code must retain the above copyright notice, this list of conditions and the following disclaimer.
8
92. Redistributions in binary form must reproduce the above copyright notice, this list of conditions and the following disclaimer in the documentation and/or other materials provided with the distribution.
10
113. The names of the contributors may not be used to endorse or promote products derived from this software without specific prior written permission.
12
13THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
14*/
15#pragma once
16#ifndef VHACD_VHACD_H
17#define VHACD_VHACD_H
18
19#ifdef OPENCL_FOUND
20#ifdef __MACH__
21#include <OpenCL/cl.h>
22#else
23#include <CL/cl.h>
24#endif
25#endif //OPENCL_FOUND
26
27#include "vhacdMutex.h"
28#include "vhacdVolume.h"
29#include "vhacdRaycastMesh.h"
30#include <vector>
31
32#define USE_THREAD 1
33#define OCL_MIN_NUM_PRIMITIVES 4096
34#define CH_APP_MIN_NUM_PRIMITIVES 64000
35namespace VHACD {
36class VHACD : public IVHACD {
37public:
38 //! Constructor.
39 VHACD()
40 {
41#if USE_THREAD == 1 && _OPENMP
42 m_ompNumProcessors = 2 * omp_get_num_procs();
43 omp_set_num_threads(m_ompNumProcessors);
44#else //USE_THREAD == 1 && _OPENMP
45 m_ompNumProcessors = 1;
46#endif //USE_THREAD == 1 && _OPENMP
47#ifdef CL_VERSION_1_1
48 m_oclWorkGroupSize = 0;
49 m_oclDevice = 0;
50 m_oclQueue = 0;
51 m_oclKernelComputePartialVolumes = 0;
52 m_oclKernelComputeSum = 0;
53#endif //CL_VERSION_1_1
54 Init();
55 }
56 //! Destructor.
57 ~VHACD(void)
58 {
59 }
60 uint32_t GetNConvexHulls() const
61 {
62 return (uint32_t)m_convexHulls.Size();
63 }
64 void Cancel()
65 {
66 SetCancel(true);
67 }
68 void GetConvexHull(const uint32_t index, ConvexHull& ch) const
69 {
70 Mesh* mesh = m_convexHulls[index];
71 ch.m_nPoints = (uint32_t)mesh->GetNPoints();
72 ch.m_nTriangles = (uint32_t)mesh->GetNTriangles();
73 ch.m_points = mesh->GetPoints();
74 ch.m_triangles = (uint32_t *)mesh->GetTriangles();
75 ch.m_volume = mesh->ComputeVolume();
76 Vec3<double> &center = mesh->ComputeCenter();
77 ch.m_center[0] = center.X();
78 ch.m_center[1] = center.Y();
79 ch.m_center[2] = center.Z();
80 }
81 void Clean(void)
82 {
83 if (mRaycastMesh)
84 {
85 mRaycastMesh->release();
86 mRaycastMesh = nullptr;
87 }
88 delete m_volume;
89 delete m_pset;
90 size_t nCH = m_convexHulls.Size();
91 for (size_t p = 0; p < nCH; ++p) {
92 delete m_convexHulls[p];
93 }
94 m_convexHulls.Clear();
95 Init();
96 }
97 void Release(void)
98 {
99 delete this;
100 }
101 bool Compute(const float* const points,
102 const uint32_t nPoints,
103 const uint32_t* const triangles,
104 const uint32_t nTriangles,
105 const Parameters& params);
106 bool Compute(const double* const points,
107 const uint32_t nPoints,
108 const uint32_t* const triangles,
109 const uint32_t nTriangles,
110 const Parameters& params);
111 bool OCLInit(void* const oclDevice,
112 IUserLogger* const logger = 0);
113 bool OCLRelease(IUserLogger* const logger = 0);
114
115 virtual bool ComputeCenterOfMass(double centerOfMass[3]) const;
116
117private:
118 void SetCancel(bool cancel)
119 {
120 m_cancelMutex.Lock();
121 m_cancel = cancel;
122 m_cancelMutex.Unlock();
123 }
124 bool GetCancel()
125 {
126
127 m_cancelMutex.Lock();
128 bool cancel = m_cancel;
129 m_cancelMutex.Unlock();
130 return cancel;
131 }
132 void Update(const double stageProgress,
133 const double operationProgress,
134 const Parameters& params)
135 {
136 m_stageProgress = stageProgress;
137 m_operationProgress = operationProgress;
138 if (params.m_callback) {
139 params.m_callback->Update(m_overallProgress,
140 m_stageProgress,
141 m_operationProgress,
142 m_stage.c_str(),
143 m_operation.c_str());
144 }
145 }
146 void Init()
147 {
148 if (mRaycastMesh)
149 {
150 mRaycastMesh->release();
151 mRaycastMesh = nullptr;
152 }
153 memset(m_rot, 0, sizeof(double) * 9);
154 m_dim = 64;
155 m_volume = 0;
156 m_volumeCH0 = 0.0;
157 m_pset = 0;
158 m_overallProgress = 0.0;
159 m_stageProgress = 0.0;
160 m_operationProgress = 0.0;
161 m_stage = "";
162 m_operation = "";
163 m_barycenter[0] = m_barycenter[1] = m_barycenter[2] = 0.0;
164 m_rot[0][0] = m_rot[1][1] = m_rot[2][2] = 1.0;
165 SetCancel(false);
166 }
167 void ComputePrimitiveSet(const Parameters& params);
168 void ComputeACD(const Parameters& params);
169 void MergeConvexHulls(const Parameters& params);
170 void SimplifyConvexHull(Mesh* const ch, const size_t nvertices, const double minVolume);
171 void SimplifyConvexHulls(const Parameters& params);
172 void ComputeBestClippingPlane(const PrimitiveSet* inputPSet,
173 const double volume,
174 const SArray<Plane>& planes,
175 const Vec3<double>& preferredCuttingDirection,
176 const double w,
177 const double alpha,
178 const double beta,
179 const int32_t convexhullDownsampling,
180 const double progress0,
181 const double progress1,
182 Plane& bestPlane,
183 double& minConcavity,
184 const Parameters& params);
185 template <class T>
186 void AlignMesh(const T* const points,
187 const uint32_t stridePoints,
188 const uint32_t nPoints,
189 const int32_t* const triangles,
190 const uint32_t strideTriangles,
191 const uint32_t nTriangles,
192 const Parameters& params)
193 {
194 if (GetCancel() || !params.m_pca) {
195 return;
196 }
197 m_timer.Tic();
198
199 m_stage = "Align mesh";
200 m_operation = "Voxelization";
201
202 std::ostringstream msg;
203 if (params.m_logger) {
204 msg << "+ " << m_stage << std::endl;
205 params.m_logger->Log(msg.str().c_str());
206 }
207
208 Update(0.0, 0.0, params);
209 if (GetCancel()) {
210 return;
211 }
212 m_dim = (size_t)(pow((double)params.m_resolution, 1.0 / 3.0) + 0.5);
213 Volume volume;
214 volume.Voxelize(points, stridePoints, nPoints,
215 triangles, strideTriangles, nTriangles,
216 m_dim, m_barycenter, m_rot);
217 size_t n = volume.GetNPrimitivesOnSurf() + volume.GetNPrimitivesInsideSurf();
218 Update(50.0, 100.0, params);
219
220 if (params.m_logger) {
221 msg.str("");
222 msg << "\t dim = " << m_dim << "\t-> " << n << " voxels" << std::endl;
223 params.m_logger->Log(msg.str().c_str());
224 }
225 if (GetCancel()) {
226 return;
227 }
228 m_operation = "PCA";
229 Update(50.0, 0.0, params);
230 volume.AlignToPrincipalAxes(m_rot);
231 m_overallProgress = 1.0;
232 Update(100.0, 100.0, params);
233
234 m_timer.Toc();
235 if (params.m_logger) {
236 msg.str("");
237 msg << "\t time " << m_timer.GetElapsedTime() / 1000.0 << "s" << std::endl;
238 params.m_logger->Log(msg.str().c_str());
239 }
240 }
241 template <class T>
242 void VoxelizeMesh(const T* const points,
243 const uint32_t stridePoints,
244 const uint32_t nPoints,
245 const int32_t* const triangles,
246 const uint32_t strideTriangles,
247 const uint32_t nTriangles,
248 const Parameters& params)
249 {
250 if (GetCancel()) {
251 return;
252 }
253
254 m_timer.Tic();
255 m_stage = "Voxelization";
256
257 std::ostringstream msg;
258 if (params.m_logger) {
259 msg << "+ " << m_stage << std::endl;
260 params.m_logger->Log(msg.str().c_str());
261 }
262
263 delete m_volume;
264 m_volume = 0;
265 int32_t iteration = 0;
266 const int32_t maxIteration = 5;
267 double progress = 0.0;
268 while (iteration++ < maxIteration && !m_cancel) {
269 msg.str("");
270 msg << "Iteration " << iteration;
271 m_operation = msg.str();
272
273 progress = iteration * 100.0 / maxIteration;
274 Update(progress, 0.0, params);
275
276 m_volume = new Volume;
277 m_volume->Voxelize(points, stridePoints, nPoints,
278 triangles, strideTriangles, nTriangles,
279 m_dim, m_barycenter, m_rot);
280
281 Update(progress, 100.0, params);
282
283 size_t n = m_volume->GetNPrimitivesOnSurf() + m_volume->GetNPrimitivesInsideSurf();
284 if (params.m_logger) {
285 msg.str("");
286 msg << "\t dim = " << m_dim << "\t-> " << n << " voxels" << std::endl;
287 params.m_logger->Log(msg.str().c_str());
288 }
289
290 double a = pow((double)(params.m_resolution) / n, 0.33);
291 size_t dim_next = (size_t)(m_dim * a + 0.5);
292 if (n < params.m_resolution && iteration < maxIteration && m_volume->GetNPrimitivesOnSurf() < params.m_resolution / 8 && m_dim != dim_next) {
293 delete m_volume;
294 m_volume = 0;
295 m_dim = dim_next;
296 }
297 else {
298 break;
299 }
300 }
301 m_overallProgress = 10.0;
302 Update(100.0, 100.0, params);
303
304 m_timer.Toc();
305 if (params.m_logger) {
306 msg.str("");
307 msg << "\t time " << m_timer.GetElapsedTime() / 1000.0 << "s" << std::endl;
308 params.m_logger->Log(msg.str().c_str());
309 }
310 }
311 template <class T>
312 bool ComputeACD(const T* const points,
313 const uint32_t nPoints,
314 const uint32_t* const triangles,
315 const uint32_t nTriangles,
316 const Parameters& params)
317 {
318 Init();
319 if (params.m_projectHullVertices)
320 {
321 mRaycastMesh = RaycastMesh::createRaycastMesh(nPoints, points, nTriangles, (const uint32_t *)triangles);
322 }
323 if (params.m_oclAcceleration) {
324 // build kernels
325 }
326 AlignMesh(points, 3, nPoints, (int32_t *)triangles, 3, nTriangles, params);
327 VoxelizeMesh(points, 3, nPoints, (int32_t *)triangles, 3, nTriangles, params);
328 ComputePrimitiveSet(params);
329 ComputeACD(params);
330 MergeConvexHulls(params);
331 SimplifyConvexHulls(params);
332 if (params.m_oclAcceleration) {
333 // Release kernels
334 }
335 if (GetCancel()) {
336 Clean();
337 return false;
338 }
339 return true;
340 }
341
342private:
343 RaycastMesh *mRaycastMesh{ nullptr };
344 SArray<Mesh*> m_convexHulls;
345 std::string m_stage;
346 std::string m_operation;
347 double m_overallProgress;
348 double m_stageProgress;
349 double m_operationProgress;
350 double m_rot[3][3];
351 double m_volumeCH0;
352 Vec3<double> m_barycenter;
353 Timer m_timer;
354 size_t m_dim;
355 Volume* m_volume;
356 PrimitiveSet* m_pset;
357 Mutex m_cancelMutex;
358 bool m_cancel;
359 int32_t m_ompNumProcessors;
360#ifdef CL_VERSION_1_1
361 cl_device_id* m_oclDevice;
362 cl_context m_oclContext;
363 cl_program m_oclProgram;
364 cl_command_queue* m_oclQueue;
365 cl_kernel* m_oclKernelComputePartialVolumes;
366 cl_kernel* m_oclKernelComputeSum;
367 size_t m_oclWorkGroupSize;
368#endif //CL_VERSION_1_1
369};
370}
371#endif // VHACD_VHACD_H
372