00001
00002
00003
00004
00005
00006
00007
00008
00009
00010
00011
00012
00013
00014
00015 #pragma once
00016 #ifndef VHACD_VOLUME_H
00017 #define VHACD_VOLUME_H
00018 #include "vhacdMesh.h"
00019 #include "vhacdVector.h"
00020 #include <assert.h>
00021
00022 #ifdef _MSC_VER
00023 #pragma warning(push)
00024 #pragma warning(disable:4456 4701)
00025 #endif
00026
00027 namespace VHACD {
00028
00029 enum VOXEL_VALUE {
00030 PRIMITIVE_UNDEFINED = 0,
00031 PRIMITIVE_OUTSIDE_SURFACE = 1,
00032 PRIMITIVE_INSIDE_SURFACE = 2,
00033 PRIMITIVE_ON_SURFACE = 3
00034 };
00035
00036 struct Voxel {
00037 public:
00038 short m_coord[3];
00039 short m_data;
00040 };
00041
00042 class PrimitiveSet {
00043 public:
00044 virtual ~PrimitiveSet(){};
00045 virtual PrimitiveSet* Create() const = 0;
00046 virtual const size_t GetNPrimitives() const = 0;
00047 virtual const size_t GetNPrimitivesOnSurf() const = 0;
00048 virtual const size_t GetNPrimitivesInsideSurf() const = 0;
00049 virtual const double GetEigenValue(AXIS axis) const = 0;
00050 virtual const double ComputeMaxVolumeError() const = 0;
00051 virtual const double ComputeVolume() const = 0;
00052 virtual void Clip(const Plane& plane, PrimitiveSet* const positivePart,
00053 PrimitiveSet* const negativePart) const = 0;
00054 virtual void Intersect(const Plane& plane, SArray<Vec3<double> >* const positivePts,
00055 SArray<Vec3<double> >* const negativePts, const size_t sampling) const = 0;
00056 virtual void ComputeExteriorPoints(const Plane& plane, const Mesh& mesh,
00057 SArray<Vec3<double> >* const exteriorPts) const = 0;
00058 virtual void ComputeClippedVolumes(const Plane& plane, double& positiveVolume,
00059 double& negativeVolume) const = 0;
00060 virtual void SelectOnSurface(PrimitiveSet* const onSurfP) const = 0;
00061 virtual void ComputeConvexHull(Mesh& meshCH, const size_t sampling = 1) const = 0;
00062 virtual void ComputeBB() = 0;
00063 virtual void ComputePrincipalAxes() = 0;
00064 virtual void AlignToPrincipalAxes() = 0;
00065 virtual void RevertAlignToPrincipalAxes() = 0;
00066 virtual void Convert(Mesh& mesh, const VOXEL_VALUE value) const = 0;
00067 const Mesh& GetConvexHull() const { return m_convexHull; };
00068 Mesh& GetConvexHull() { return m_convexHull; };
00069 private:
00070 Mesh m_convexHull;
00071 };
00072
00074 class VoxelSet : public PrimitiveSet {
00075 friend class Volume;
00076
00077 public:
00079 ~VoxelSet(void);
00081 VoxelSet();
00082
00083 const size_t GetNPrimitives() const { return m_voxels.Size(); }
00084 const size_t GetNPrimitivesOnSurf() const { return m_numVoxelsOnSurface; }
00085 const size_t GetNPrimitivesInsideSurf() const { return m_numVoxelsInsideSurface; }
00086 const double GetEigenValue(AXIS axis) const { return m_D[axis][axis]; }
00087 const double ComputeVolume() const { return m_unitVolume * m_voxels.Size(); }
00088 const double ComputeMaxVolumeError() const { return m_unitVolume * m_numVoxelsOnSurface; }
00089 const Vec3<short>& GetMinBBVoxels() const { return m_minBBVoxels; }
00090 const Vec3<short>& GetMaxBBVoxels() const { return m_maxBBVoxels; }
00091 const Vec3<double>& GetMinBB() const { return m_minBB; }
00092 const double& GetScale() const { return m_scale; }
00093 const double& GetUnitVolume() const { return m_unitVolume; }
00094 Vec3<double> GetPoint(Vec3<short> voxel) const
00095 {
00096 return Vec3<double>(voxel[0] * m_scale + m_minBB[0],
00097 voxel[1] * m_scale + m_minBB[1],
00098 voxel[2] * m_scale + m_minBB[2]);
00099 }
00100 Vec3<double> GetPoint(const Voxel& voxel) const
00101 {
00102 return Vec3<double>(voxel.m_coord[0] * m_scale + m_minBB[0],
00103 voxel.m_coord[1] * m_scale + m_minBB[1],
00104 voxel.m_coord[2] * m_scale + m_minBB[2]);
00105 }
00106 Vec3<double> GetPoint(Vec3<double> voxel) const
00107 {
00108 return Vec3<double>(voxel[0] * m_scale + m_minBB[0],
00109 voxel[1] * m_scale + m_minBB[1],
00110 voxel[2] * m_scale + m_minBB[2]);
00111 }
00112 void GetPoints(const Voxel& voxel, Vec3<double>* const pts) const;
00113 void ComputeConvexHull(Mesh& meshCH, const size_t sampling = 1) const;
00114 void Clip(const Plane& plane, PrimitiveSet* const positivePart, PrimitiveSet* const negativePart) const;
00115 void Intersect(const Plane& plane, SArray<Vec3<double> >* const positivePts,
00116 SArray<Vec3<double> >* const negativePts, const size_t sampling) const;
00117 void ComputeExteriorPoints(const Plane& plane, const Mesh& mesh,
00118 SArray<Vec3<double> >* const exteriorPts) const;
00119 void ComputeClippedVolumes(const Plane& plane, double& positiveVolume, double& negativeVolume) const;
00120 void SelectOnSurface(PrimitiveSet* const onSurfP) const;
00121 void ComputeBB();
00122 void Convert(Mesh& mesh, const VOXEL_VALUE value) const;
00123 void ComputePrincipalAxes();
00124 PrimitiveSet* Create() const
00125 {
00126 return new VoxelSet();
00127 }
00128 void AlignToPrincipalAxes(){};
00129 void RevertAlignToPrincipalAxes(){};
00130 Voxel* const GetVoxels() { return m_voxels.Data(); }
00131 const Voxel* const GetVoxels() const { return m_voxels.Data(); }
00132
00133 private:
00134 size_t m_numVoxelsOnSurface;
00135 size_t m_numVoxelsInsideSurface;
00136 Vec3<double> m_minBB;
00137 double m_scale;
00138 SArray<Voxel, 8> m_voxels;
00139 double m_unitVolume;
00140 Vec3<double> m_minBBPts;
00141 Vec3<double> m_maxBBPts;
00142 Vec3<short> m_minBBVoxels;
00143 Vec3<short> m_maxBBVoxels;
00144 Vec3<short> m_barycenter;
00145 double m_Q[3][3];
00146 double m_D[3][3];
00147 Vec3<double> m_barycenterPCA;
00148 };
00149
00150 struct Tetrahedron {
00151 public:
00152 Vec3<double> m_pts[4];
00153 unsigned char m_data;
00154 };
00155
00157 class TetrahedronSet : public PrimitiveSet {
00158 friend class Volume;
00159
00160 public:
00162 ~TetrahedronSet(void);
00164 TetrahedronSet();
00165
00166 const size_t GetNPrimitives() const { return m_tetrahedra.Size(); }
00167 const size_t GetNPrimitivesOnSurf() const { return m_numTetrahedraOnSurface; }
00168 const size_t GetNPrimitivesInsideSurf() const { return m_numTetrahedraInsideSurface; }
00169 const Vec3<double>& GetMinBB() const { return m_minBB; }
00170 const Vec3<double>& GetMaxBB() const { return m_maxBB; }
00171 const Vec3<double>& GetBarycenter() const { return m_barycenter; }
00172 const double GetEigenValue(AXIS axis) const { return m_D[axis][axis]; }
00173 const double GetSacle() const { return m_scale; }
00174 const double ComputeVolume() const;
00175 const double ComputeMaxVolumeError() const;
00176 void ComputeConvexHull(Mesh& meshCH, const size_t sampling = 1) const;
00177 void ComputePrincipalAxes();
00178 void AlignToPrincipalAxes();
00179 void RevertAlignToPrincipalAxes();
00180 void Clip(const Plane& plane, PrimitiveSet* const positivePart, PrimitiveSet* const negativePart) const;
00181 void Intersect(const Plane& plane, SArray<Vec3<double> >* const positivePts,
00182 SArray<Vec3<double> >* const negativePts, const size_t sampling) const;
00183 void ComputeExteriorPoints(const Plane& plane, const Mesh& mesh,
00184 SArray<Vec3<double> >* const exteriorPts) const;
00185 void ComputeClippedVolumes(const Plane& plane, double& positiveVolume, double& negativeVolume) const;
00186 void SelectOnSurface(PrimitiveSet* const onSurfP) const;
00187 void ComputeBB();
00188 void Convert(Mesh& mesh, const VOXEL_VALUE value) const;
00189 inline bool Add(Tetrahedron& tetrahedron);
00190 PrimitiveSet* Create() const
00191 {
00192 return new TetrahedronSet();
00193 }
00194 static const double EPS;
00195
00196 private:
00197 void AddClippedTetrahedra(const Vec3<double> (&pts)[10], const int32_t nPts);
00198
00199 size_t m_numTetrahedraOnSurface;
00200 size_t m_numTetrahedraInsideSurface;
00201 double m_scale;
00202 Vec3<double> m_minBB;
00203 Vec3<double> m_maxBB;
00204 Vec3<double> m_barycenter;
00205 SArray<Tetrahedron, 8> m_tetrahedra;
00206 double m_Q[3][3];
00207 double m_D[3][3];
00208 };
00209
00211 class Volume {
00212 public:
00214 ~Volume(void);
00215
00217 Volume();
00218
00220 template <class T>
00221 void Voxelize(const T* const points, const uint32_t stridePoints, const uint32_t nPoints,
00222 const int32_t* const triangles, const uint32_t strideTriangles, const uint32_t nTriangles,
00223 const size_t dim, const Vec3<double>& barycenter, const double (&rot)[3][3]);
00224 unsigned char& GetVoxel(const size_t i, const size_t j, const size_t k)
00225 {
00226 assert(i < m_dim[0] || i >= 0);
00227 assert(j < m_dim[0] || j >= 0);
00228 assert(k < m_dim[0] || k >= 0);
00229 return m_data[i + j * m_dim[0] + k * m_dim[0] * m_dim[1]];
00230 }
00231 const unsigned char& GetVoxel(const size_t i, const size_t j, const size_t k) const
00232 {
00233 assert(i < m_dim[0] || i >= 0);
00234 assert(j < m_dim[0] || j >= 0);
00235 assert(k < m_dim[0] || k >= 0);
00236 return m_data[i + j * m_dim[0] + k * m_dim[0] * m_dim[1]];
00237 }
00238 const size_t GetNPrimitivesOnSurf() const { return m_numVoxelsOnSurface; }
00239 const size_t GetNPrimitivesInsideSurf() const { return m_numVoxelsInsideSurface; }
00240 void Convert(Mesh& mesh, const VOXEL_VALUE value) const;
00241 void Convert(VoxelSet& vset) const;
00242 void Convert(TetrahedronSet& tset) const;
00243 void AlignToPrincipalAxes(double (&rot)[3][3]) const;
00244
00245 private:
00246 void FillOutsideSurface(const size_t i0, const size_t j0, const size_t k0, const size_t i1,
00247 const size_t j1, const size_t k1);
00248 void FillInsideSurface();
00249 template <class T>
00250 void ComputeBB(const T* const points, const uint32_t stridePoints, const uint32_t nPoints,
00251 const Vec3<double>& barycenter, const double (&rot)[3][3]);
00252 void Allocate();
00253 void Free();
00254
00255 Vec3<double> m_minBB;
00256 Vec3<double> m_maxBB;
00257 double m_scale;
00258 size_t m_dim[3];
00259 size_t m_numVoxelsOnSurface;
00260 size_t m_numVoxelsInsideSurface;
00261 size_t m_numVoxelsOutsideSurface;
00262 unsigned char* m_data;
00263 };
00264 int32_t TriBoxOverlap(const Vec3<double>& boxcenter, const Vec3<double>& boxhalfsize, const Vec3<double>& triver0,
00265 const Vec3<double>& triver1, const Vec3<double>& triver2);
00266 template <class T>
00267 inline void ComputeAlignedPoint(const T* const points, const uint32_t idx, const Vec3<double>& barycenter,
00268 const double (&rot)[3][3], Vec3<double>& pt){};
00269 template <>
00270 inline void ComputeAlignedPoint<float>(const float* const points, const uint32_t idx, const Vec3<double>& barycenter, const double (&rot)[3][3], Vec3<double>& pt)
00271 {
00272 double x = points[idx + 0] - barycenter[0];
00273 double y = points[idx + 1] - barycenter[1];
00274 double z = points[idx + 2] - barycenter[2];
00275 pt[0] = rot[0][0] * x + rot[1][0] * y + rot[2][0] * z;
00276 pt[1] = rot[0][1] * x + rot[1][1] * y + rot[2][1] * z;
00277 pt[2] = rot[0][2] * x + rot[1][2] * y + rot[2][2] * z;
00278 }
00279 template <>
00280 inline void ComputeAlignedPoint<double>(const double* const points, const uint32_t idx, const Vec3<double>& barycenter, const double (&rot)[3][3], Vec3<double>& pt)
00281 {
00282 double x = points[idx + 0] - barycenter[0];
00283 double y = points[idx + 1] - barycenter[1];
00284 double z = points[idx + 2] - barycenter[2];
00285 pt[0] = rot[0][0] * x + rot[1][0] * y + rot[2][0] * z;
00286 pt[1] = rot[0][1] * x + rot[1][1] * y + rot[2][1] * z;
00287 pt[2] = rot[0][2] * x + rot[1][2] * y + rot[2][2] * z;
00288 }
00289 template <class T>
00290 void Volume::ComputeBB(const T* const points, const uint32_t stridePoints, const uint32_t nPoints,
00291 const Vec3<double>& barycenter, const double (&rot)[3][3])
00292 {
00293 Vec3<double> pt;
00294 ComputeAlignedPoint(points, 0, barycenter, rot, pt);
00295 m_maxBB = pt;
00296 m_minBB = pt;
00297 for (uint32_t v = 1; v < nPoints; ++v) {
00298 ComputeAlignedPoint(points, v * stridePoints, barycenter, rot, pt);
00299 for (int32_t i = 0; i < 3; ++i) {
00300 if (pt[i] < m_minBB[i])
00301 m_minBB[i] = pt[i];
00302 else if (pt[i] > m_maxBB[i])
00303 m_maxBB[i] = pt[i];
00304 }
00305 }
00306 }
00307 template <class T>
00308 void Volume::Voxelize(const T* const points, const uint32_t stridePoints, const uint32_t nPoints,
00309 const int32_t* const triangles, const uint32_t strideTriangles, const uint32_t nTriangles,
00310 const size_t dim, const Vec3<double>& barycenter, const double (&rot)[3][3])
00311 {
00312 if (nPoints == 0) {
00313 return;
00314 }
00315 ComputeBB(points, stridePoints, nPoints, barycenter, rot);
00316
00317 double d[3] = { m_maxBB[0] - m_minBB[0], m_maxBB[1] - m_minBB[1], m_maxBB[2] - m_minBB[2] };
00318 double r;
00319 if (d[0] > d[1] && d[0] > d[2]) {
00320 r = d[0];
00321 m_dim[0] = dim;
00322 m_dim[1] = 2 + static_cast<size_t>(dim * d[1] / d[0]);
00323 m_dim[2] = 2 + static_cast<size_t>(dim * d[2] / d[0]);
00324 }
00325 else if (d[1] > d[0] && d[1] > d[2]) {
00326 r = d[1];
00327 m_dim[1] = dim;
00328 m_dim[0] = 2 + static_cast<size_t>(dim * d[0] / d[1]);
00329 m_dim[2] = 2 + static_cast<size_t>(dim * d[2] / d[1]);
00330 }
00331 else {
00332 r = d[2];
00333 m_dim[2] = dim;
00334 m_dim[0] = 2 + static_cast<size_t>(dim * d[0] / d[2]);
00335 m_dim[1] = 2 + static_cast<size_t>(dim * d[1] / d[2]);
00336 }
00337
00338 m_scale = r / (dim - 1);
00339 double invScale = (dim - 1) / r;
00340
00341 Allocate();
00342 m_numVoxelsOnSurface = 0;
00343 m_numVoxelsInsideSurface = 0;
00344 m_numVoxelsOutsideSurface = 0;
00345
00346 Vec3<double> p[3];
00347 size_t i, j, k;
00348 size_t i0, j0, k0;
00349 size_t i1, j1, k1;
00350 Vec3<double> boxcenter;
00351 Vec3<double> pt;
00352 const Vec3<double> boxhalfsize(0.5, 0.5, 0.5);
00353 for (size_t t = 0, ti = 0; t < nTriangles; ++t, ti += strideTriangles) {
00354 Vec3<int32_t> tri(triangles[ti + 0],
00355 triangles[ti + 1],
00356 triangles[ti + 2]);
00357 for (int32_t c = 0; c < 3; ++c) {
00358 ComputeAlignedPoint(points, tri[c] * stridePoints, barycenter, rot, pt);
00359 p[c][0] = (pt[0] - m_minBB[0]) * invScale;
00360 p[c][1] = (pt[1] - m_minBB[1]) * invScale;
00361 p[c][2] = (pt[2] - m_minBB[2]) * invScale;
00362 i = static_cast<size_t>(p[c][0] + 0.5);
00363 j = static_cast<size_t>(p[c][1] + 0.5);
00364 k = static_cast<size_t>(p[c][2] + 0.5);
00365 assert(i < m_dim[0] && i >= 0 && j < m_dim[1] && j >= 0 && k < m_dim[2] && k >= 0);
00366
00367 if (c == 0) {
00368 i0 = i1 = i;
00369 j0 = j1 = j;
00370 k0 = k1 = k;
00371 }
00372 else {
00373 if (i < i0)
00374 i0 = i;
00375 if (j < j0)
00376 j0 = j;
00377 if (k < k0)
00378 k0 = k;
00379 if (i > i1)
00380 i1 = i;
00381 if (j > j1)
00382 j1 = j;
00383 if (k > k1)
00384 k1 = k;
00385 }
00386 }
00387 if (i0 > 0)
00388 --i0;
00389 if (j0 > 0)
00390 --j0;
00391 if (k0 > 0)
00392 --k0;
00393 if (i1 < m_dim[0])
00394 ++i1;
00395 if (j1 < m_dim[1])
00396 ++j1;
00397 if (k1 < m_dim[2])
00398 ++k1;
00399 for (size_t i = i0; i < i1; ++i) {
00400 boxcenter[0] = (double)i;
00401 for (size_t j = j0; j < j1; ++j) {
00402 boxcenter[1] = (double)j;
00403 for (size_t k = k0; k < k1; ++k) {
00404 boxcenter[2] = (double)k;
00405 int32_t res = TriBoxOverlap(boxcenter, boxhalfsize, p[0], p[1], p[2]);
00406 unsigned char& value = GetVoxel(i, j, k);
00407 if (res == 1 && value == PRIMITIVE_UNDEFINED) {
00408 value = PRIMITIVE_ON_SURFACE;
00409 ++m_numVoxelsOnSurface;
00410 }
00411 }
00412 }
00413 }
00414 }
00415 FillOutsideSurface(0, 0, 0, m_dim[0], m_dim[1], 1);
00416 FillOutsideSurface(0, 0, m_dim[2] - 1, m_dim[0], m_dim[1], m_dim[2]);
00417 FillOutsideSurface(0, 0, 0, m_dim[0], 1, m_dim[2]);
00418 FillOutsideSurface(0, m_dim[1] - 1, 0, m_dim[0], m_dim[1], m_dim[2]);
00419 FillOutsideSurface(0, 0, 0, 1, m_dim[1], m_dim[2]);
00420 FillOutsideSurface(m_dim[0] - 1, 0, 0, m_dim[0], m_dim[1], m_dim[2]);
00421 FillInsideSurface();
00422 }
00423 }
00424
00425 #ifdef _MSC_VER
00426 #pragma warning(pop)
00427 #endif
00428
00429
00430 #endif // VHACD_VOLUME_H