hacdHACD.h 17 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282
  1. /* Copyright (c) 2011 Khaled Mamou (kmamou at gmail dot com)
  2. All rights reserved.
  3. Redistribution and use in source and binary forms, with or without modification, are permitted provided that the following conditions are met:
  4. 1. Redistributions of source code must retain the above copyright notice, this list of conditions and the following disclaimer.
  5. 2. 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.
  6. 3. The names of the contributors may not be used to endorse or promote products derived from this software without specific prior written permission.
  7. THIS 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.
  8. */
  9. #pragma once
  10. #ifndef HACD_HACD_H
  11. #define HACD_HACD_H
  12. #include "hacdVersion.h"
  13. #include "hacdVector.h"
  14. #include "hacdGraph.h"
  15. #include "hacdICHull.h"
  16. #include <set>
  17. #include <vector>
  18. #include <queue>
  19. #include <functional>
  20. namespace HACD
  21. {
  22. const double sc_pi = 3.14159265;
  23. class HACD;
  24. // just to be able to set the capcity of the container
  25. template<class _Ty, class _Container = std::vector<_Ty>, class _Pr = std::less<typename _Container::value_type> >
  26. class reservable_priority_queue: public std::priority_queue<_Ty, _Container, _Pr>
  27. {
  28. typedef typename std::priority_queue<_Ty, _Container, _Pr>::size_type size_type;
  29. public:
  30. reservable_priority_queue(size_type capacity = 0) { reserve(capacity); };
  31. void reserve(size_type capacity) { this->c.reserve(capacity); }
  32. size_type capacity() const { return this->c.capacity(); }
  33. };
  34. //! priority queque element
  35. class GraphEdgePriorityQueue
  36. {
  37. public:
  38. //! Constructor
  39. //! @param name edge's id
  40. //! @param priority edge's priority
  41. GraphEdgePriorityQueue(long name, Real priority)
  42. {
  43. m_name = name;
  44. m_priority = priority;
  45. }
  46. //! Destructor
  47. ~GraphEdgePriorityQueue(void){}
  48. private:
  49. long m_name; //!< edge name
  50. Real m_priority; //!< priority
  51. //! Operator < for GraphEdgePQ
  52. friend bool operator<(const GraphEdgePriorityQueue & lhs, const GraphEdgePriorityQueue & rhs);
  53. //! Operator > for GraphEdgePQ
  54. friend bool operator>(const GraphEdgePriorityQueue & lhs, const GraphEdgePriorityQueue & rhs);
  55. friend class HACD;
  56. };
  57. inline bool operator<(const GraphEdgePriorityQueue & lhs, const GraphEdgePriorityQueue & rhs)
  58. {
  59. return lhs.m_priority<rhs.m_priority;
  60. }
  61. inline bool operator>(const GraphEdgePriorityQueue & lhs, const GraphEdgePriorityQueue & rhs)
  62. {
  63. return lhs.m_priority>rhs.m_priority;
  64. }
  65. typedef bool (*CallBackFunction)(const char *, double, double, size_t);
  66. //! Provides an implementation of the Hierarchical Approximate Convex Decomposition (HACD) technique described in "A Simple and Efficient Approach for 3D Mesh Approximate Convex Decomposition" Game Programming Gems 8 - Chapter 2.8, p.202. A short version of the chapter was published in ICIP09 and is available at ftp://ftp.elet.polimi.it/users/Stefano.Tubaro/ICIP_USB_Proceedings_v2/pdfs/0003501.pdf
  67. class HACD
  68. {
  69. public:
  70. //! Gives the triangles partitionas an array of size m_nTriangles where the i-th element specifies the cluster to which belong the i-th triangle
  71. //! @return triangles partition
  72. const long * GetPartition() const { return m_partition;}
  73. //! Sets the scale factor
  74. //! @param scale scale factor
  75. void SetScaleFactor(double scale) { m_scale = scale;}
  76. //! Gives the scale factor
  77. //! @return scale factor
  78. double GetScaleFactor() const { return m_scale;}
  79. //! Sets the call-back function
  80. //! @param callBack pointer to the call-back function
  81. void SetCallBack(CallBackFunction callBack) { m_callBack = callBack;}
  82. //! Gives the call-back function
  83. //! @return pointer to the call-back function
  84. CallBackFunction GetCallBack() const { return m_callBack;}
  85. //! Specifies whether faces points should be added when computing the concavity
  86. //! @param addFacesPoints true = faces points should be added
  87. void SetAddFacesPoints(bool addFacesPoints) { m_addFacesPoints = addFacesPoints;}
  88. //! Specifies wheter faces points should be added when computing the concavity
  89. //! @return true = faces points should be added
  90. bool GetAddFacesPoints() const { return m_addFacesPoints;}
  91. //! Specifies whether extra points should be added when computing the concavity
  92. //! @param addExteraDistPoints true = extra points should be added
  93. void SetAddExtraDistPoints(bool addExtraDistPoints) { m_addExtraDistPoints = addExtraDistPoints;}
  94. //! Specifies wheter extra points should be added when computing the concavity
  95. //! @return true = extra points should be added
  96. bool GetAddExtraDistPoints() const { return m_addExtraDistPoints;}
  97. //! Specifies whether extra points should be added when computing the concavity
  98. //! @param addExteraDistPoints true = extra points should be added
  99. void SetAddNeighboursDistPoints(bool addNeighboursDistPoints) { m_addNeighboursDistPoints = addNeighboursDistPoints;}
  100. //! Specifies wheter extra points should be added when computing the concavity
  101. //! @return true = extra points should be added
  102. bool GetAddNeighboursDistPoints() const { return m_addNeighboursDistPoints;}
  103. //! Sets the points of the input mesh (Remark: the input points will be scaled and shifted. Use DenormalizeData() to invert those operations)
  104. //! @param points pointer to the input points
  105. void SetPoints(Vec3<Real> * points) { m_points = points;}
  106. //! Gives the points of the input mesh (Remark: the input points will be scaled and shifted. Use DenormalizeData() to invert those operations)
  107. //! @return pointer to the input points
  108. const Vec3<Real> * GetPoints() const { return m_points;}
  109. //! Sets the triangles of the input mesh.
  110. //! @param triangles points pointer to the input points
  111. void SetTriangles(Vec3<long> * triangles) { m_triangles = triangles;}
  112. //! Gives the triangles in the input mesh
  113. //! @return pointer to the input triangles
  114. const Vec3<long> * GetTriangles() const { return m_triangles;}
  115. //! Sets the number of points in the input mesh.
  116. //! @param nPoints number of points the input mesh
  117. void SetNPoints(size_t nPoints) { m_nPoints = nPoints;}
  118. //! Gives the number of points in the input mesh.
  119. //! @return number of points the input mesh
  120. size_t GetNPoints() const { return m_nPoints;}
  121. //! Sets the number of triangles in the input mesh.
  122. //! @param nTriangles number of triangles in the input mesh
  123. void SetNTriangles(size_t nTriangles) { m_nTriangles = nTriangles;}
  124. //! Gives the number of triangles in the input mesh.
  125. //! @return number of triangles the input mesh
  126. size_t GetNTriangles() const { return m_nTriangles;}
  127. //! Sets the minimum number of clusters to be generated.
  128. //! @param nClusters minimum number of clusters
  129. void SetNClusters(size_t nClusters) { m_nMinClusters = nClusters;}
  130. //! Gives the number of generated clusters.
  131. //! @return number of generated clusters
  132. size_t GetNClusters() const { return m_nClusters;}
  133. //! Sets the maximum allowed concavity.
  134. //! @param concavity maximum concavity
  135. void SetConcavity(double concavity) { m_concavity = concavity;}
  136. //! Gives the maximum allowed concavity.
  137. //! @return maximum concavity
  138. double GetConcavity() const { return m_concavity;}
  139. //! Sets the maximum allowed distance to get CCs connected.
  140. //! @param concavity maximum distance to get CCs connected
  141. void SetConnectDist(double ccConnectDist) { m_ccConnectDist = ccConnectDist;}
  142. //! Gives the maximum allowed distance to get CCs connected.
  143. //! @return maximum distance to get CCs connected
  144. double GetConnectDist() const { return m_ccConnectDist;}
  145. //! Sets the volume weight.
  146. //! @param beta volume weight
  147. void SetVolumeWeight(double beta) { m_beta = beta;}
  148. //! Gives the volume weight.
  149. //! @return volume weight
  150. double GetVolumeWeight() const { return m_beta;}
  151. //! Sets the compacity weight (i.e. parameter alpha in ftp://ftp.elet.polimi.it/users/Stefano.Tubaro/ICIP_USB_Proceedings_v2/pdfs/0003501.pdf).
  152. //! @param alpha compacity weight
  153. void SetCompacityWeight(double alpha) { m_alpha = alpha;}
  154. //! Gives the compacity weight (i.e. parameter alpha in ftp://ftp.elet.polimi.it/users/Stefano.Tubaro/ICIP_USB_Proceedings_v2/pdfs/0003501.pdf).
  155. //! @return compacity weight
  156. double GetCompacityWeight() const { return m_alpha;}
  157. //! Sets the maximum number of vertices for each generated convex-hull.
  158. //! @param nVerticesPerCH maximum # vertices per CH
  159. void SetNVerticesPerCH(size_t nVerticesPerCH) { m_nVerticesPerCH = nVerticesPerCH;}
  160. //! Gives the maximum number of vertices for each generated convex-hull.
  161. //! @return maximum # vertices per CH
  162. size_t GetNVerticesPerCH() const { return m_nVerticesPerCH;}
  163. //! Gives the number of vertices for the cluster number numCH.
  164. //! @return number of vertices
  165. size_t GetNPointsCH(size_t numCH) const;
  166. //! Gives the number of triangles for the cluster number numCH.
  167. //! @param numCH cluster's number
  168. //! @return number of triangles
  169. size_t GetNTrianglesCH(size_t numCH) const;
  170. //! Gives the vertices and the triangles of the cluster number numCH.
  171. //! @param numCH cluster's number
  172. //! @param points pointer to the vector of points to be filled
  173. //! @param triangles pointer to the vector of triangles to be filled
  174. //! @return true if sucess
  175. bool GetCH(size_t numCH, Vec3<Real> * const points, Vec3<long> * const triangles);
  176. //! Computes the HACD decomposition.
  177. //! @param fullCH specifies whether to generate convex-hulls with a full or limited (i.e. < m_nVerticesPerCH) number of vertices
  178. //! @param exportDistPoints specifies wheter distance points should ne exported or not (used only for debugging).
  179. //! @return true if sucess
  180. bool Compute(bool fullCH=false, bool exportDistPoints=false);
  181. //! Saves the generated convex-hulls in a VRML 2.0 file.
  182. //! @param fileName the output file name
  183. //! @param uniColor specifies whether the different convex-hulls should have the same color or not
  184. //! @param numCluster specifies the cluster to be saved, if numCluster < 0 export all clusters
  185. //! @return true if sucess
  186. bool Save(const char * fileName, bool uniColor, long numCluster=-1) const;
  187. //! Shifts and scales to the data to have all the coordinates between 0.0 and 1000.0.
  188. void NormalizeData();
  189. //! Inverse the operations applied by NormalizeData().
  190. void DenormalizeData();
  191. //! Constructor.
  192. HACD(void);
  193. //! Destructor.
  194. ~HACD(void);
  195. private:
  196. //! Gives the edge index.
  197. //! @param a first vertex id
  198. //! @param b second vertex id
  199. //! @return edge's index
  200. static unsigned long long GetEdgeIndex(unsigned long long a, unsigned long long b)
  201. {
  202. if (a > b) return (a << 32) + b;
  203. else return (b << 32) + a;
  204. }
  205. //! Computes the concavity of a cluster.
  206. //! @param ch the cluster's convex-hull
  207. //! @param distPoints the cluster's points
  208. //! @return cluster's concavity
  209. double Concavity(ICHull & ch, std::map<long, DPoint> & distPoints);
  210. //! Computes the perimeter of a cluster.
  211. //! @param triIndices the cluster's triangles
  212. //! @param distPoints the cluster's points
  213. //! @return cluster's perimeter
  214. double ComputePerimeter(const std::vector<long> & triIndices) const;
  215. //! Creates the Graph by associating to each mesh triangle a vertex in the graph and to each couple of adjacent triangles an edge in the graph.
  216. void CreateGraph();
  217. //! Initializes the graph costs and computes the vertices normals
  218. void InitializeDualGraph();
  219. //! Computes the cost of an edge
  220. //! @param e edge's id
  221. void ComputeEdgeCost(size_t e);
  222. //! Initializes the priority queue
  223. //! @param fast specifies whether fast mode is used
  224. //! @return true if success
  225. bool InitializePriorityQueue();
  226. //! Cleans the intersection between convex-hulls
  227. void CleanClusters();
  228. //! Computes convex-hulls from partition information
  229. //! @param fullCH specifies whether to generate convex-hulls with a full or limited (i.e. < m_nVerticesPerCH) number of vertices
  230. void ComputeConvexHulls(bool fullCH);
  231. //! Simplifies the graph
  232. //! @param fast specifies whether fast mode is used
  233. void Simplify();
  234. private:
  235. double m_scale; //>! scale factor used for NormalizeData() and DenormalizeData()
  236. Vec3<long> * m_triangles; //>! pointer the triangles array
  237. Vec3<Real> * m_points; //>! pointer the points array
  238. Vec3<Real> * m_facePoints; //>! pointer to the faces points array
  239. Vec3<Real> * m_faceNormals; //>! pointer to the faces normals array
  240. Vec3<Real> * m_normals; //>! pointer the normals array
  241. size_t m_nTriangles; //>! number of triangles in the original mesh
  242. size_t m_nPoints; //>! number of vertices in the original mesh
  243. size_t m_nClusters; //>! number of clusters
  244. size_t m_nMinClusters; //>! minimum number of clusters
  245. double m_ccConnectDist; //>! maximum allowed distance to connect CCs
  246. double m_concavity; //>! maximum concavity
  247. double m_alpha; //>! compacity weigth
  248. double m_beta; //>! volume weigth
  249. double m_diag; //>! length of the BB diagonal
  250. Vec3<Real> m_barycenter; //>! barycenter of the mesh
  251. std::vector< long > m_cVertices; //>! array of vertices each belonging to a different cluster
  252. ICHull * m_convexHulls; //>! convex-hulls associated with the final HACD clusters
  253. Graph m_graph; //>! simplification graph
  254. size_t m_nVerticesPerCH; //>! maximum number of vertices per convex-hull
  255. reservable_priority_queue<GraphEdgePriorityQueue,
  256. std::vector<GraphEdgePriorityQueue>,
  257. std::greater<std::vector<GraphEdgePriorityQueue>::value_type> > m_pqueue; //!> priority queue
  258. HACD(const HACD & rhs);
  259. CallBackFunction m_callBack; //>! call-back function
  260. long * m_partition; //>! array of size m_nTriangles where the i-th element specifies the cluster to which belong the i-th triangle
  261. bool m_addFacesPoints; //>! specifies whether to add faces points or not
  262. bool m_addExtraDistPoints; //>! specifies whether to add extra points for concave shapes or not
  263. bool m_addNeighboursDistPoints; //>! specifies whether to add extra points from adjacent clusters or not
  264. };
  265. }
  266. #endif