half_edge.h 13 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372
  1. // Copyright 2009-2021 Intel Corporation
  2. // SPDX-License-Identifier: Apache-2.0
  3. #pragma once
  4. #include "catmullclark_coefficients.h"
  5. namespace embree
  6. {
  7. class __aligned(32) HalfEdge
  8. {
  9. friend class SubdivMesh;
  10. public:
  11. enum PatchType : char {
  12. BILINEAR_PATCH = 0, //!< a bilinear patch
  13. REGULAR_QUAD_PATCH = 1, //!< a regular quad patch can be represented as a B-Spline
  14. IRREGULAR_QUAD_PATCH = 2, //!< an irregular quad patch can be represented as a Gregory patch
  15. COMPLEX_PATCH = 3 //!< these patches need subdivision and cannot be processed by the above fast code paths
  16. };
  17. enum VertexType : char {
  18. REGULAR_VERTEX = 0, //!< regular vertex
  19. NON_MANIFOLD_EDGE_VERTEX = 1, //!< vertex of a non-manifold edge
  20. };
  21. __forceinline friend PatchType max( const PatchType& ty0, const PatchType& ty1) {
  22. return (PatchType) max((int)ty0,(int)ty1);
  23. }
  24. struct Edge
  25. {
  26. /*! edge constructor */
  27. __forceinline Edge(const uint32_t v0, const uint32_t v1)
  28. : v0(v0), v1(v1) {}
  29. /*! create an 64 bit identifier that is unique for the not oriented edge */
  30. __forceinline operator uint64_t() const
  31. {
  32. uint32_t p0 = v0, p1 = v1;
  33. if (p0<p1) std::swap(p0,p1);
  34. return (((uint64_t)p0) << 32) | (uint64_t)p1;
  35. }
  36. public:
  37. uint32_t v0,v1; //!< start and end vertex of the edge
  38. };
  39. HalfEdge ()
  40. : vtx_index(-1), next_half_edge_ofs(0), prev_half_edge_ofs(0), opposite_half_edge_ofs(0), edge_crease_weight(0),
  41. vertex_crease_weight(0), edge_level(0), patch_type(COMPLEX_PATCH), vertex_type(REGULAR_VERTEX)
  42. {
  43. static_assert(sizeof(HalfEdge) == 32, "invalid half edge size");
  44. }
  45. __forceinline bool hasOpposite() const { return opposite_half_edge_ofs != 0; }
  46. __forceinline void setOpposite(HalfEdge* opposite) { opposite_half_edge_ofs = int(opposite-this); }
  47. __forceinline HalfEdge* next() { assert( next_half_edge_ofs != 0 ); return &this[next_half_edge_ofs]; }
  48. __forceinline const HalfEdge* next() const { assert( next_half_edge_ofs != 0 ); return &this[next_half_edge_ofs]; }
  49. __forceinline HalfEdge* prev() { assert( prev_half_edge_ofs != 0 ); return &this[prev_half_edge_ofs]; }
  50. __forceinline const HalfEdge* prev() const { assert( prev_half_edge_ofs != 0 ); return &this[prev_half_edge_ofs]; }
  51. __forceinline HalfEdge* opposite() { assert( opposite_half_edge_ofs != 0 ); return &this[opposite_half_edge_ofs]; }
  52. __forceinline const HalfEdge* opposite() const { assert( opposite_half_edge_ofs != 0 ); return &this[opposite_half_edge_ofs]; }
  53. __forceinline HalfEdge* rotate() { return opposite()->next(); }
  54. __forceinline const HalfEdge* rotate() const { return opposite()->next(); }
  55. __forceinline unsigned int getStartVertexIndex() const { return vtx_index; }
  56. __forceinline unsigned int getEndVertexIndex () const { return next()->vtx_index; }
  57. __forceinline Edge getEdge () const { return Edge(getStartVertexIndex(),getEndVertexIndex()); }
  58. /*! tests if the start vertex of the edge is regular */
  59. __forceinline PatchType vertexType() const
  60. {
  61. const HalfEdge* p = this;
  62. size_t face_valence = 0;
  63. bool hasBorder = false;
  64. do
  65. {
  66. /* we need subdivision to handle edge creases */
  67. if (p->hasOpposite() && p->edge_crease_weight > 0.0f)
  68. return COMPLEX_PATCH;
  69. face_valence++;
  70. /* test for quad */
  71. const HalfEdge* pp = p;
  72. pp = pp->next(); if (pp == p) return COMPLEX_PATCH;
  73. pp = pp->next(); if (pp == p) return COMPLEX_PATCH;
  74. pp = pp->next(); if (pp == p) return COMPLEX_PATCH;
  75. pp = pp->next(); if (pp != p) return COMPLEX_PATCH;
  76. /* continue with next face */
  77. p = p->prev();
  78. if (likely(p->hasOpposite()))
  79. p = p->opposite();
  80. /* if there is no opposite go the long way to the other side of the border */
  81. else
  82. {
  83. face_valence++;
  84. hasBorder = true;
  85. p = this;
  86. while (p->hasOpposite())
  87. p = p->rotate();
  88. }
  89. } while (p != this);
  90. /* calculate vertex type */
  91. if (face_valence == 2 && hasBorder) {
  92. if (vertex_crease_weight == 0.0f ) return REGULAR_QUAD_PATCH;
  93. else if (vertex_crease_weight == float(inf)) return REGULAR_QUAD_PATCH;
  94. else return COMPLEX_PATCH;
  95. }
  96. else if (vertex_crease_weight != 0.0f) return COMPLEX_PATCH;
  97. else if (face_valence == 3 && hasBorder) return REGULAR_QUAD_PATCH;
  98. else if (face_valence == 4 && !hasBorder) return REGULAR_QUAD_PATCH;
  99. else return IRREGULAR_QUAD_PATCH;
  100. }
  101. /*! tests if this edge is part of a bilinear patch */
  102. __forceinline bool bilinearVertex() const {
  103. return vertex_crease_weight == float(inf) && edge_crease_weight == float(inf);
  104. }
  105. /*! calculates the type of the patch */
  106. __forceinline PatchType patchType() const
  107. {
  108. const HalfEdge* p = this;
  109. PatchType ret = REGULAR_QUAD_PATCH;
  110. bool bilinear = true;
  111. ret = max(ret,p->vertexType());
  112. bilinear &= p->bilinearVertex();
  113. if ((p = p->next()) == this) return COMPLEX_PATCH;
  114. ret = max(ret,p->vertexType());
  115. bilinear &= p->bilinearVertex();
  116. if ((p = p->next()) == this) return COMPLEX_PATCH;
  117. ret = max(ret,p->vertexType());
  118. bilinear &= p->bilinearVertex();
  119. if ((p = p->next()) == this) return COMPLEX_PATCH;
  120. ret = max(ret,p->vertexType());
  121. bilinear &= p->bilinearVertex();
  122. if ((p = p->next()) != this) return COMPLEX_PATCH;
  123. if (bilinear) return BILINEAR_PATCH;
  124. return ret;
  125. }
  126. /*! tests if the face is a regular b-spline face */
  127. __forceinline bool isRegularFace() const {
  128. return patch_type == REGULAR_QUAD_PATCH;
  129. }
  130. /*! tests if the face can be diced (using bspline or gregory patch) */
  131. __forceinline bool isGregoryFace() const {
  132. return patch_type == IRREGULAR_QUAD_PATCH || patch_type == REGULAR_QUAD_PATCH;
  133. }
  134. /*! tests if the base vertex of this half edge is a corner vertex */
  135. __forceinline bool isCorner() const {
  136. return !hasOpposite() && !prev()->hasOpposite();
  137. }
  138. /*! tests if the vertex is attached to any border */
  139. __forceinline bool vertexHasBorder() const
  140. {
  141. const HalfEdge* p = this;
  142. do {
  143. if (!p->hasOpposite()) return true;
  144. p = p->rotate();
  145. } while (p != this);
  146. return false;
  147. }
  148. /*! tests if the face this half edge belongs to has some border */
  149. __forceinline bool faceHasBorder() const
  150. {
  151. const HalfEdge* p = this;
  152. do {
  153. if (p->vertexHasBorder() && (p->vertex_type != HalfEdge::NON_MANIFOLD_EDGE_VERTEX)) return true;
  154. p = p->next();
  155. } while (p != this);
  156. return false;
  157. }
  158. /*! calculates conservative bounds of a catmull clark subdivision face */
  159. __forceinline BBox3fa bounds(const BufferView<Vec3fa>& vertices) const
  160. {
  161. BBox3fa bounds = this->get1RingBounds(vertices);
  162. for (const HalfEdge* p=this->next(); p!=this; p=p->next())
  163. bounds.extend(p->get1RingBounds(vertices));
  164. return bounds;
  165. }
  166. /*! tests if this is a valid patch */
  167. __forceinline bool valid(const BufferView<Vec3fa>& vertices) const
  168. {
  169. size_t N = 1;
  170. if (!this->validRing(vertices)) return false;
  171. for (const HalfEdge* p=this->next(); p!=this; p=p->next(), N++) {
  172. if (!p->validRing(vertices)) return false;
  173. }
  174. return N >= 3 && N <= MAX_PATCH_VALENCE;
  175. }
  176. /*! counts number of polygon edges */
  177. __forceinline unsigned int numEdges() const
  178. {
  179. unsigned int N = 1;
  180. for (const HalfEdge* p=this->next(); p!=this; p=p->next(), N++);
  181. return N;
  182. }
  183. /*! calculates face and edge valence */
  184. __forceinline void calculateFaceValenceAndEdgeValence(size_t& faceValence, size_t& edgeValence) const
  185. {
  186. faceValence = 0;
  187. edgeValence = 0;
  188. const HalfEdge* p = this;
  189. do
  190. {
  191. /* calculate bounds of current face */
  192. unsigned int numEdges = p->numEdges();
  193. assert(numEdges >= 3);
  194. edgeValence += numEdges-2;
  195. faceValence++;
  196. p = p->prev();
  197. /* continue with next face */
  198. if (likely(p->hasOpposite()))
  199. p = p->opposite();
  200. /* if there is no opposite go the long way to the other side of the border */
  201. else {
  202. faceValence++;
  203. edgeValence++;
  204. p = this;
  205. while (p->hasOpposite())
  206. p = p->opposite()->next();
  207. }
  208. } while (p != this);
  209. }
  210. /*! stream output */
  211. friend __forceinline std::ostream &operator<<(std::ostream &o, const HalfEdge &h)
  212. {
  213. return o << "{ " <<
  214. "vertex = " << h.vtx_index << ", " << //" -> " << h.next()->vtx_index << ", " <<
  215. "prev = " << h.prev_half_edge_ofs << ", " <<
  216. "next = " << h.next_half_edge_ofs << ", " <<
  217. "opposite = " << h.opposite_half_edge_ofs << ", " <<
  218. "edge_crease = " << h.edge_crease_weight << ", " <<
  219. "vertex_crease = " << h.vertex_crease_weight << ", " <<
  220. //"edge_level = " << h.edge_level <<
  221. " }";
  222. }
  223. private:
  224. /*! calculates the bounds of the face associated with the half-edge */
  225. __forceinline BBox3fa getFaceBounds(const BufferView<Vec3fa>& vertices) const
  226. {
  227. BBox3fa b = vertices[getStartVertexIndex()];
  228. for (const HalfEdge* p = next(); p!=this; p=p->next()) {
  229. b.extend(vertices[p->getStartVertexIndex()]);
  230. }
  231. return b;
  232. }
  233. /*! calculates the bounds of the 1-ring associated with the vertex of the half-edge */
  234. __forceinline BBox3fa get1RingBounds(const BufferView<Vec3fa>& vertices) const
  235. {
  236. BBox3fa bounds = empty;
  237. const HalfEdge* p = this;
  238. do
  239. {
  240. /* calculate bounds of current face */
  241. bounds.extend(p->getFaceBounds(vertices));
  242. p = p->prev();
  243. /* continue with next face */
  244. if (likely(p->hasOpposite()))
  245. p = p->opposite();
  246. /* if there is no opposite go the long way to the other side of the border */
  247. else {
  248. p = this;
  249. while (p->hasOpposite())
  250. p = p->opposite()->next();
  251. }
  252. } while (p != this);
  253. return bounds;
  254. }
  255. /*! tests if this is a valid face */
  256. __forceinline bool validFace(const BufferView<Vec3fa>& vertices, size_t& N) const
  257. {
  258. const Vec3fa v = vertices[getStartVertexIndex()];
  259. if (!isvalid(v)) return false;
  260. size_t n = 1;
  261. for (const HalfEdge* p = next(); p!=this; p=p->next(), n++) {
  262. const Vec3fa v = vertices[p->getStartVertexIndex()];
  263. if (!isvalid(v)) return false;
  264. }
  265. N += n-2;
  266. return n >= 3 && n <= MAX_PATCH_VALENCE;
  267. }
  268. /*! tests if this is a valid ring */
  269. __forceinline bool validRing(const BufferView<Vec3fa>& vertices) const
  270. {
  271. size_t faceValence = 0;
  272. size_t edgeValence = 0;
  273. const HalfEdge* p = this;
  274. do
  275. {
  276. /* calculate bounds of current face */
  277. if (!p->validFace(vertices,edgeValence))
  278. return false;
  279. faceValence++;
  280. p = p->prev();
  281. /* continue with next face */
  282. if (likely(p->hasOpposite()))
  283. p = p->opposite();
  284. /* if there is no opposite go the long way to the other side of the border */
  285. else {
  286. faceValence++;
  287. edgeValence++;
  288. p = this;
  289. while (p->hasOpposite())
  290. p = p->opposite()->next();
  291. }
  292. } while (p != this);
  293. return faceValence <= MAX_RING_FACE_VALENCE && edgeValence <= MAX_RING_EDGE_VALENCE;
  294. }
  295. private:
  296. unsigned int vtx_index; //!< index of edge start vertex
  297. int next_half_edge_ofs; //!< relative offset to next half edge of face
  298. int prev_half_edge_ofs; //!< relative offset to previous half edge of face
  299. int opposite_half_edge_ofs; //!< relative offset to opposite half edge
  300. public:
  301. float edge_crease_weight; //!< crease weight attached to edge
  302. float vertex_crease_weight; //!< crease weight attached to start vertex
  303. float edge_level; //!< subdivision factor for edge
  304. PatchType patch_type; //!< stores type of subdiv patch
  305. VertexType vertex_type; //!< stores type of the start vertex
  306. char align[2];
  307. };
  308. }