Path: blob/master/thirdparty/embree/kernels/subdiv/half_edge.h
9913 views
// Copyright 2009-2021 Intel Corporation1// SPDX-License-Identifier: Apache-2.023#pragma once45#include "catmullclark_coefficients.h"67namespace embree8{9class __aligned(32) HalfEdge10{11friend class SubdivMesh;12public:1314enum PatchType : char {15BILINEAR_PATCH = 0, //!< a bilinear patch16REGULAR_QUAD_PATCH = 1, //!< a regular quad patch can be represented as a B-Spline17IRREGULAR_QUAD_PATCH = 2, //!< an irregular quad patch can be represented as a Gregory patch18COMPLEX_PATCH = 3 //!< these patches need subdivision and cannot be processed by the above fast code paths19};2021enum VertexType : char {22REGULAR_VERTEX = 0, //!< regular vertex23NON_MANIFOLD_EDGE_VERTEX = 1, //!< vertex of a non-manifold edge24};2526__forceinline friend PatchType max( const PatchType& ty0, const PatchType& ty1) {27return (PatchType) max((int)ty0,(int)ty1);28}2930struct Edge31{32/*! edge constructor */33__forceinline Edge(const uint32_t v0, const uint32_t v1)34: v0(v0), v1(v1) {}3536/*! create an 64 bit identifier that is unique for the not oriented edge */37__forceinline operator uint64_t() const38{39uint32_t p0 = v0, p1 = v1;40if (p0<p1) std::swap(p0,p1);41return (((uint64_t)p0) << 32) | (uint64_t)p1;42}4344public:45uint32_t v0,v1; //!< start and end vertex of the edge46};4748HalfEdge ()49: vtx_index(-1), next_half_edge_ofs(0), prev_half_edge_ofs(0), opposite_half_edge_ofs(0), edge_crease_weight(0),50vertex_crease_weight(0), edge_level(0), patch_type(COMPLEX_PATCH), vertex_type(REGULAR_VERTEX)51{52static_assert(sizeof(HalfEdge) == 32, "invalid half edge size");53}5455__forceinline bool hasOpposite() const { return opposite_half_edge_ofs != 0; }56__forceinline void setOpposite(HalfEdge* opposite) { opposite_half_edge_ofs = int(opposite-this); }5758__forceinline HalfEdge* next() { assert( next_half_edge_ofs != 0 ); return &this[next_half_edge_ofs]; }59__forceinline const HalfEdge* next() const { assert( next_half_edge_ofs != 0 ); return &this[next_half_edge_ofs]; }6061__forceinline HalfEdge* prev() { assert( prev_half_edge_ofs != 0 ); return &this[prev_half_edge_ofs]; }62__forceinline const HalfEdge* prev() const { assert( prev_half_edge_ofs != 0 ); return &this[prev_half_edge_ofs]; }6364__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]; }6667__forceinline HalfEdge* rotate() { return opposite()->next(); }68__forceinline const HalfEdge* rotate() const { return opposite()->next(); }6970__forceinline unsigned int getStartVertexIndex() const { return vtx_index; }71__forceinline unsigned int getEndVertexIndex () const { return next()->vtx_index; }72__forceinline Edge getEdge () const { return Edge(getStartVertexIndex(),getEndVertexIndex()); }737475/*! tests if the start vertex of the edge is regular */76__forceinline PatchType vertexType() const77{78const HalfEdge* p = this;79size_t face_valence = 0;80bool hasBorder = false;8182do83{84/* we need subdivision to handle edge creases */85if (p->hasOpposite() && p->edge_crease_weight > 0.0f)86return COMPLEX_PATCH;8788face_valence++;8990/* test for quad */91const HalfEdge* pp = p;92pp = pp->next(); if (pp == p) return COMPLEX_PATCH;93pp = pp->next(); if (pp == p) return COMPLEX_PATCH;94pp = pp->next(); if (pp == p) return COMPLEX_PATCH;95pp = pp->next(); if (pp != p) return COMPLEX_PATCH;9697/* continue with next face */98p = p->prev();99if (likely(p->hasOpposite()))100p = p->opposite();101102/* if there is no opposite go the long way to the other side of the border */103else104{105face_valence++;106hasBorder = true;107p = this;108while (p->hasOpposite())109p = p->rotate();110}111} while (p != this);112113/* calculate vertex type */114if (face_valence == 2 && hasBorder) {115if (vertex_crease_weight == 0.0f ) return REGULAR_QUAD_PATCH;116else if (vertex_crease_weight == float(inf)) return REGULAR_QUAD_PATCH;117else return COMPLEX_PATCH;118}119else if (vertex_crease_weight != 0.0f) return COMPLEX_PATCH;120else if (face_valence == 3 && hasBorder) return REGULAR_QUAD_PATCH;121else if (face_valence == 4 && !hasBorder) return REGULAR_QUAD_PATCH;122else return IRREGULAR_QUAD_PATCH;123}124125/*! tests if this edge is part of a bilinear patch */126__forceinline bool bilinearVertex() const {127return vertex_crease_weight == float(inf) && edge_crease_weight == float(inf);128}129130/*! calculates the type of the patch */131__forceinline PatchType patchType() const132{133const HalfEdge* p = this;134PatchType ret = REGULAR_QUAD_PATCH;135bool bilinear = true;136137ret = max(ret,p->vertexType());138bilinear &= p->bilinearVertex();139if ((p = p->next()) == this) return COMPLEX_PATCH;140141ret = max(ret,p->vertexType());142bilinear &= p->bilinearVertex();143if ((p = p->next()) == this) return COMPLEX_PATCH;144145ret = max(ret,p->vertexType());146bilinear &= p->bilinearVertex();147if ((p = p->next()) == this) return COMPLEX_PATCH;148149ret = max(ret,p->vertexType());150bilinear &= p->bilinearVertex();151if ((p = p->next()) != this) return COMPLEX_PATCH;152153if (bilinear) return BILINEAR_PATCH;154return ret;155}156157/*! tests if the face is a regular b-spline face */158__forceinline bool isRegularFace() const {159return patch_type == REGULAR_QUAD_PATCH;160}161162/*! tests if the face can be diced (using bspline or gregory patch) */163__forceinline bool isGregoryFace() const {164return patch_type == IRREGULAR_QUAD_PATCH || patch_type == REGULAR_QUAD_PATCH;165}166167/*! tests if the base vertex of this half edge is a corner vertex */168__forceinline bool isCorner() const {169return !hasOpposite() && !prev()->hasOpposite();170}171172/*! tests if the vertex is attached to any border */173__forceinline bool vertexHasBorder() const174{175const HalfEdge* p = this;176do {177if (!p->hasOpposite()) return true;178p = p->rotate();179} while (p != this);180return false;181}182183/*! tests if the face this half edge belongs to has some border */184__forceinline bool faceHasBorder() const185{186const HalfEdge* p = this;187do {188if (p->vertexHasBorder() && (p->vertex_type != HalfEdge::NON_MANIFOLD_EDGE_VERTEX)) return true;189p = p->next();190} while (p != this);191return false;192}193194/*! calculates conservative bounds of a catmull clark subdivision face */195__forceinline BBox3fa bounds(const BufferView<Vec3fa>& vertices) const196{197BBox3fa bounds = this->get1RingBounds(vertices);198for (const HalfEdge* p=this->next(); p!=this; p=p->next())199bounds.extend(p->get1RingBounds(vertices));200return bounds;201}202203/*! tests if this is a valid patch */204__forceinline bool valid(const BufferView<Vec3fa>& vertices) const205{206size_t N = 1;207if (!this->validRing(vertices)) return false;208for (const HalfEdge* p=this->next(); p!=this; p=p->next(), N++) {209if (!p->validRing(vertices)) return false;210}211return N >= 3 && N <= MAX_PATCH_VALENCE;212}213214/*! counts number of polygon edges */215__forceinline unsigned int numEdges() const216{217unsigned int N = 1;218for (const HalfEdge* p=this->next(); p!=this; p=p->next(), N++);219return N;220}221222/*! calculates face and edge valence */223__forceinline void calculateFaceValenceAndEdgeValence(size_t& faceValence, size_t& edgeValence) const224{225faceValence = 0;226edgeValence = 0;227228const HalfEdge* p = this;229do230{231/* calculate bounds of current face */232unsigned int numEdges = p->numEdges();233assert(numEdges >= 3);234edgeValence += numEdges-2;235236faceValence++;237p = p->prev();238239/* continue with next face */240if (likely(p->hasOpposite()))241p = p->opposite();242243/* if there is no opposite go the long way to the other side of the border */244else {245faceValence++;246edgeValence++;247p = this;248while (p->hasOpposite())249p = p->opposite()->next();250}251252} while (p != this);253}254255/*! stream output */256friend __forceinline std::ostream &operator<<(std::ostream &o, const HalfEdge &h)257{258return o << "{ " <<259"vertex = " << h.vtx_index << ", " << //" -> " << h.next()->vtx_index << ", " <<260"prev = " << h.prev_half_edge_ofs << ", " <<261"next = " << h.next_half_edge_ofs << ", " <<262"opposite = " << h.opposite_half_edge_ofs << ", " <<263"edge_crease = " << h.edge_crease_weight << ", " <<264"vertex_crease = " << h.vertex_crease_weight << ", " <<265//"edge_level = " << h.edge_level <<266" }";267}268269private:270271/*! calculates the bounds of the face associated with the half-edge */272__forceinline BBox3fa getFaceBounds(const BufferView<Vec3fa>& vertices) const273{274BBox3fa b = vertices[getStartVertexIndex()];275for (const HalfEdge* p = next(); p!=this; p=p->next()) {276b.extend(vertices[p->getStartVertexIndex()]);277}278return b;279}280281/*! calculates the bounds of the 1-ring associated with the vertex of the half-edge */282__forceinline BBox3fa get1RingBounds(const BufferView<Vec3fa>& vertices) const283{284BBox3fa bounds = empty;285const HalfEdge* p = this;286do287{288/* calculate bounds of current face */289bounds.extend(p->getFaceBounds(vertices));290p = p->prev();291292/* continue with next face */293if (likely(p->hasOpposite()))294p = p->opposite();295296/* if there is no opposite go the long way to the other side of the border */297else {298p = this;299while (p->hasOpposite())300p = p->opposite()->next();301}302303} while (p != this);304305return bounds;306}307308/*! tests if this is a valid face */309__forceinline bool validFace(const BufferView<Vec3fa>& vertices, size_t& N) const310{311const Vec3fa v = vertices[getStartVertexIndex()];312if (!isvalid(v)) return false;313size_t n = 1;314for (const HalfEdge* p = next(); p!=this; p=p->next(), n++) {315const Vec3fa v = vertices[p->getStartVertexIndex()];316if (!isvalid(v)) return false;317}318N += n-2;319return n >= 3 && n <= MAX_PATCH_VALENCE;320}321322/*! tests if this is a valid ring */323__forceinline bool validRing(const BufferView<Vec3fa>& vertices) const324{325size_t faceValence = 0;326size_t edgeValence = 0;327328const HalfEdge* p = this;329do330{331/* calculate bounds of current face */332if (!p->validFace(vertices,edgeValence))333return false;334335faceValence++;336p = p->prev();337338/* continue with next face */339if (likely(p->hasOpposite()))340p = p->opposite();341342/* if there is no opposite go the long way to the other side of the border */343else {344faceValence++;345edgeValence++;346p = this;347while (p->hasOpposite())348p = p->opposite()->next();349}350351} while (p != this);352353return faceValence <= MAX_RING_FACE_VALENCE && edgeValence <= MAX_RING_EDGE_VALENCE;354}355356private:357unsigned int vtx_index; //!< index of edge start vertex358int next_half_edge_ofs; //!< relative offset to next half edge of face359int prev_half_edge_ofs; //!< relative offset to previous half edge of face360int opposite_half_edge_ofs; //!< relative offset to opposite half edge361362public:363float edge_crease_weight; //!< crease weight attached to edge364float vertex_crease_weight; //!< crease weight attached to start vertex365float edge_level; //!< subdivision factor for edge366PatchType patch_type; //!< stores type of subdiv patch367VertexType vertex_type; //!< stores type of the start vertex368char align[2];369};370}371372373