half_edge.h 13 KB

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