OpenSubdiv/opensubdiv/hbr/vertex.h
Julian Fong 59edf56416 Change container get methods (HbrMesh::GetVertices, etc) to take
output iterators instead of std::vector - eases prman integration
for cases where std::list makes more sense.

Block allocate face children array in common case (<= 4 children).

Other, minor consistency edits.
2012-08-20 13:21:12 -07:00

1518 lines
49 KiB
C++

//
// Copyright (C) Pixar. All rights reserved.
//
// This license governs use of the accompanying software. If you
// use the software, you accept this license. If you do not accept
// the license, do not use the software.
//
// 1. Definitions
// The terms "reproduce," "reproduction," "derivative works," and
// "distribution" have the same meaning here as under U.S.
// copyright law. A "contribution" is the original software, or
// any additions or changes to the software.
// A "contributor" is any person or entity that distributes its
// contribution under this license.
// "Licensed patents" are a contributor's patent claims that read
// directly on its contribution.
//
// 2. Grant of Rights
// (A) Copyright Grant- Subject to the terms of this license,
// including the license conditions and limitations in section 3,
// each contributor grants you a non-exclusive, worldwide,
// royalty-free copyright license to reproduce its contribution,
// prepare derivative works of its contribution, and distribute
// its contribution or any derivative works that you create.
// (B) Patent Grant- Subject to the terms of this license,
// including the license conditions and limitations in section 3,
// each contributor grants you a non-exclusive, worldwide,
// royalty-free license under its licensed patents to make, have
// made, use, sell, offer for sale, import, and/or otherwise
// dispose of its contribution in the software or derivative works
// of the contribution in the software.
//
// 3. Conditions and Limitations
// (A) No Trademark License- This license does not grant you
// rights to use any contributor's name, logo, or trademarks.
// (B) If you bring a patent claim against any contributor over
// patents that you claim are infringed by the software, your
// patent license from such contributor to the software ends
// automatically.
// (C) If you distribute any portion of the software, you must
// retain all copyright, patent, trademark, and attribution
// notices that are present in the software.
// (D) If you distribute any portion of the software in source
// code form, you may do so only under this license by including a
// complete copy of this license with your distribution. If you
// distribute any portion of the software in compiled or object
// code form, you may only do so under a license that complies
// with this license.
// (E) The software is licensed "as-is." You bear the risk of
// using it. The contributors give no express warranties,
// guarantees or conditions. You may have additional consumer
// rights under your local laws which this license cannot change.
// To the extent permitted under your local laws, the contributors
// exclude the implied warranties of merchantability, fitness for
// a particular purpose and non-infringement.
//
#ifndef HBRVERTEX_H
#define HBRVERTEX_H
#include <assert.h>
#include <iostream>
#include <iterator>
#include <vector>
#include "../hbr/fvarData.h"
#include "../hbr/face.h"
#include "../version.h"
namespace OpenSubdiv {
namespace OPENSUBDIV_VERSION {
template <class T> class HbrHalfedge;
template <class T> class HbrHalfedgeCompare;
template <class T> class HbrVertex;
template <class T> class HbrVertexOperator;
template <class T> class HbrFaceOperator;
template <class T> class HbrHalfedgeOperator;
template <class T> class HbrVertex {
public:
HbrVertex();
HbrVertex(int vid, const T &data, int fvarwidth) {
Initialize(vid, data, fvarwidth);
}
void Initialize(int vid, const T &data, int fvarwidth);
~HbrVertex();
void Destroy();
// Registers an incident edge with the vertex
void AddIncidentEdge(HbrHalfedge<T>* edge);
// Unregister an incident edge with the vertex
void RemoveIncidentEdge(HbrHalfedge<T>* edge);
// Checks if removal of the indicated incident edge will result
// in a singular vertex
bool EdgeRemovalWillMakeSingular(HbrHalfedge<T>* edge) const;
// Sets up vertex flags after the vertex has been bound to a mesh
void Finish();
// Compute the valence of this vertex
int GetValence() const;
// Compute the valence of this vertex including only edges which
// are "coarse" (highest level edges)
int GetCoarseValence() const;
// Return vertex ID
int GetID() const { return id; }
// Return vertex data
T& GetData() { return data; }
// Return vertex data
const T& GetData() const { return data; }
// Returns the facevarying data which is matched to the face.
// This may either be the "generic" facevarying item (fvardata, so
// data.GetFace() == face) or one specifically registered to the
// face (in the middle of morefvardata, so data.GetFace() ==
// face). If we require storage for a facevarying data designed to
// store discontinuous values for this face, we must have called
// NewFVarData before GetFVarData will give it to us.
HbrFVarData<T>& GetFVarData(const HbrFace<T>* face);
// Returns new facevarying data matched to the face
HbrFVarData<T>& NewFVarData(const HbrFace<T>* face);
// Return any incident face attached to the vertex
HbrFace<T>* GetFace() const;
// Return the mesh to which this vertex belongs
HbrMesh<T>* GetMesh() const;
// Return an edge connected to dest
HbrHalfedge<T>* GetEdge(const HbrVertex<T>* dest) const;
// Given an edge, returns the next edge in counterclockwise order
// around this vertex. Note well: this is only the next halfedge,
// which means that all edges returned by this function are
// guaranteed to have the same origin vertex (ie this vertex). In
// boundary cases if you are interested in all edges you will not
// get the last edge with this function. For that reason,
// GetSurroundingEdges is preferred.
HbrHalfedge<T>* GetNextEdge(const HbrHalfedge<T>* edge) const;
// Given an edge, returns the previous edge (ie going clockwise)
// around this vertex
HbrHalfedge<T>* GetPreviousEdge(const HbrHalfedge<T>* edge) const;
// Quadedge-like algebra subset. Since we are dealing with
// halfedges and not symmetric edges, these functions accept a
// destination vertex which indicates the (possibly imaginary)
// halfedge we are considering, and return the destination vertex
// of the desired (also possibly imaginary) halfedge. Also,
// currently they are potentially very inefficient and should be
// avoided.
HbrVertex<T>* GetQEONext(const HbrVertex<T>* dest) const;
HbrVertex<T>* GetQEONext(const HbrHalfedge<T>* edge) const;
HbrVertex<T>* GetQEOPrev(const HbrHalfedge<T>* edge) const;
HbrVertex<T>* GetQEOPrev(const HbrVertex<T>* dest) const;
HbrVertex<T>* GetQELNext(const HbrVertex<T>* dest) const;
// Returns true if the vertex is on a boundary edge
bool OnBoundary() const;
// Returns true if the vertex has a facevarying mask which is
// smooth (0).
bool IsFVarSmooth(int datum);
// Returns true if all facevarying data has facevarying mask which
// is smooth
bool IsFVarAllSmooth();
// Returns true if the vertex has a facevarying mask which is dart
// (1).
bool IsFVarDart(int datum);
// Returns true if the vertex is a facevarying corner for any
// incident face, where "cornerness" is defined as having two
// incident edges that make up a face both being facevarying
// edges.
bool IsFVarCorner(int datum);
// Returns the sharpness of the vertex
float GetSharpness() const { return sharpness; }
// Sets the sharpness of the vertex
void SetSharpness(float sharp) { sharpness = sharp; ClearMask(); }
// Returns whether the corner is sharp at the current level of
// subdivision (next = false) or at the next level of subdivision
// (next = true).
bool IsSharp(bool next) const { return (next ? (sharpness > 0.0f) : (sharpness >= 1.0f)); }
// Sets the vertex mask if the vertex is sharp to reflect that
// it's a corner
void ClearMask() {
mask0 = mask1 = 0; validmask = 0; volatil = 0;
}
// Returns the integer mask of the vertex at the current level of
// subdivision (next = false) or at the next level of subdivision
// (next = true)
unsigned char GetMask(bool next);
// Returns the facevarying integer mask of the vertex
unsigned char GetFVarMask(int datum);
// Computes the "fractional mask" of the vertex at the current
// subdivision level, based on the fractional sharpnesses of any
// adjacent sharp edges. The fractional mask is a value between 0
// and 1
float GetFractionalMask() const;
// Returns whether the vertex is singular (has two separate
// incident halfedge cycles)
bool IsSingular() const { return nIncidentEdges > 1; }
// Collect the ring of edges around this vertex. Note well: not
// all edges in this list will have an orientation where the
// origin of the edge is this vertex! This function requires an
// output iterator; to get the edges into a std::vector, use
// GetSurroundingEdges(std::back_inserter(myvector))
template <typename OutputIterator>
void GetSurroundingEdges(OutputIterator edges) const;
// Apply an edge operator to each edge in the ring of edges
// around this vertex
void ApplyOperatorSurroundingEdges(HbrHalfedgeOperator<T> &op) const;
// Collect the ring of vertices around this vertex (the ones that
// share an edge with this vertex). This function requires an
// output iterator; to get the vertices into a std::vector, use
// GetSurroundingVertices(std::back_inserter(myvector))
template <typename OutputIterator>
void GetSurroundingVertices(OutputIterator vertices) const;
// Apply a vertex operator to each vertex in the ring of vertices
// around this vertex
void ApplyOperatorSurroundingVertices(HbrVertexOperator<T> &op) const;
// Applys an operator to the ring of faces around this vertex
void ApplyOperatorSurroundingFaces(HbrFaceOperator<T> &op) const;
// Returns the parent, which can be a edge, face, or vertex
HbrHalfedge<T>* GetParentEdge() const { return (parentType == k_ParentEdge ? parent.edge : 0); }
HbrFace<T>* GetParentFace() const { return (parentType == k_ParentFace ? parent.face : 0); }
HbrVertex<T>* GetParentVertex() const { return (parentType == k_ParentVertex ? parent.vertex : 0); }
// Set the parent pointer
void SetParent(HbrHalfedge<T>* edge) { assert(!edge || !parent.vertex); parentType = k_ParentEdge; parent.edge = edge; }
void SetParent(HbrFace<T>* face) { assert(!face || !parent.vertex); parentType = k_ParentFace; parent.face = face; }
void SetParent(HbrVertex<T>* vertex) { assert(!vertex || !parent.vertex); parentType = k_ParentVertex; parent.vertex = vertex; }
// Subdivides the vertex and returns the child vertex
HbrVertex<T>* Subdivide();
// Refines the ring of faces around this vertex
void Refine();
// Make sure the vertex has all faces in the ring around it
void GuaranteeNeighbors();
// Indicates that the vertex may have a missing face neighbor and
// may need to guarantee its neighbors in the future
void UnGuaranteeNeighbors() {
neighborsguaranteed = 0;
// Its mask is also invalidated
validmask = 0;
}
// Remove the reference to subdivided vertex
void RemoveChild() { vchild = 0; }
// Returns true if the vertex still has an incident edge (in other
// words, it belongs to a face)
bool IsReferenced() const { return references != 0; }
// Returns true if the vertex is extraordinary
bool IsExtraordinary() const { return extraordinary; }
// Tag the vertex as being extraordinary
void SetExtraordinary() { extraordinary = 1; }
// Returns whether the vertex is volatile (incident to a semisharp
// edge or semisharp corner)
bool IsVolatile() { if (!validmask) GetMask(false); return volatil; }
// Simple bookkeeping needed for garbage collection by HbrMesh
bool IsCollected() const { return collected; }
void SetCollected() { collected = 1; }
void ClearCollected() { collected = 0; }
// Bookkeeping to see if a vertex edit exists for this vertex
bool HasVertexEdit() const { return hasvertexedit; }
void SetVertexEdit() { hasvertexedit = 1; }
void ClearVertexEdit() { hasvertexedit = 0; }
// Returns memory statistics
unsigned long GetMemStats() const;
// Returns true if the vertex is connected. This means that it has
// an incident edge
bool IsConnected() const { return nIncidentEdges > 0; }
// Return an incident edge to this vertex, which happens to be the
// first halfedge of the cycles.
HbrHalfedge<T>* GetIncidentEdge() const { return nIncidentEdges ? incidentEdges[0] : 0; }
// Sharpness and mask constants
enum Mask {
k_Smooth = 0,
k_Dart = 1,
k_Crease = 2,
k_Corner = 3,
k_InfinitelySharp = 10
};
// Increment the usage counter on the vertex
void IncrementUsage() { used++; }
// Decrement the usage counter on the vertex
void DecrementUsage() { used--; }
// Check the usage counter on the vertex
bool IsUsed() const { return used || vchild; }
// Used by block allocator
HbrVertex<T>*& GetNext() { return vchild; }
// Returns the blind pointer to client data
void *GetClientData() const {
return clientData;
}
// Sets the blind pointer to client data
void SetClientData(void *data) {
clientData = data;
}
enum ParentType {
k_ParentNone, k_ParentFace, k_ParentEdge, k_ParentVertex
};
private:
// Splits a singular vertex into multiple nonsingular vertices
void splitSingular();
// Data
T data;
// Pointer to extra facevarying data. Space for this is allocated
// by NewFVarData
HbrFVarData<T> *morefvardata;
// Unique ID of this vertex
int id;
// Size of incident array
int nIncidentEdges;
// The number of halfedges which have this vertex as the incident
// edge. When references == 0, the vertex is safe to delete
int references;
// The number of faces marked "used" which share this vertex. May
// not be the same as references!
int used;
// Number of facevarying data allocated to this vertex in
// morefvardata
int nfvardata;
// Sharpness
float sharpness;
// Vertex masks, at this level of subdivision and at the next
// level of subdivision. Valid only when validmask = 1.
unsigned short mask0:3;
unsigned short mask1:3;
// Extraordinary bit
unsigned short extraordinary:1;
// Whether the current mask value is correct or should be recalculated
unsigned short validmask:1;
// Whether the vertex is "volatile" (is incident to a semisharp edge,
// or is a semisharp corner)
unsigned short volatil:1;
// Whether we can guarantee the existence of neighboring faces on
// this vertex
unsigned short neighborsguaranteed:1;
// Bookkeeping for HbrMesh
unsigned short collected:1;
// Whether the vertex has an edit. The edit is owned by a face
// so this is just a tag that indicates we need to search the
// vertex's neighboring faces for an edit
unsigned short hasvertexedit:1;
// Whether the vertex edit (if any) has been applied
unsigned short editsapplied:1;
// Whether Destroy() has been called
unsigned short destroyed:1;
// Parent type - can be face, edge, or vertex
unsigned short parentType:2;
// List of edge cycles. For "singular" vertices, the corresponding
// set of adjacent halfedges may consist of several cycles, and we
// need to account for all of them here. In cases where
// nIncidentEdges is 1 or less (i.e. the general nonsingular
// case), this memory actually points at memory allocated after
// the end of this object. Otherwise, it's an actual separately
// allocated array.
HbrHalfedge<T>** incidentEdges;
// Child vertex
HbrVertex<T>* vchild;
union {
HbrFace<T>* face;
HbrHalfedge<T>* edge;
HbrVertex<T>* vertex;
} parent;
// Blind client data pointer
void * clientData;
};
template <class T>
HbrVertex<T>::HbrVertex() :
morefvardata(0), id(-1), nIncidentEdges(0), references(0), used(0), nfvardata(0), sharpness(0.0f), extraordinary(0), validmask(0), volatil(0), neighborsguaranteed(0), collected(0), hasvertexedit(0), editsapplied(0), destroyed(0), parentType(k_ParentNone), incidentEdges(0), vchild(0), clientData(0) {
ClearMask();
parent.vertex = 0;
}
template <class T>
void
HbrVertex<T>::Initialize(int vid, const T &vdata, int fvarwidth) {
data = vdata;
morefvardata = 0 ;
id = vid;
references = 0;
used = 0;
extraordinary = 0;
ClearMask();
neighborsguaranteed = 0;
collected = 0;
hasvertexedit = 0;
editsapplied = 0;
destroyed = 0;
sharpness = 0.0f;
nIncidentEdges = 0;
vchild = 0;
assert(!parent.vertex);
parentType = k_ParentVertex;
parent.vertex = 0;
clientData = 0;
// Upstream allocator ensured the class was padded by an extra
// amount for this
char *buffer = ((char*) this + sizeof(*this));
incidentEdges = (HbrHalfedge<T>**) buffer;
buffer += sizeof(HbrHalfedge<T>*);
if (fvarwidth) {
// Upstream allocator ensured the class was padded by the
// appropriate size. GetFVarData will return a pointer to this
// memory, but it needs to be properly initialized.
// Run placement new to initialize datum
new (buffer) HbrFVarData<T>((float*) (buffer + sizeof(HbrFVarData<T>)));
}
}
template <class T>
HbrVertex<T>::~HbrVertex() {
Destroy();
}
template <class T>
void
HbrVertex<T>::Destroy() {
if (!destroyed) {
// Vertices are only safe for deletion if the number of incident
// edges is exactly zero.
assert(references == 0);
// Delete parent reference to self
if (parentType == k_ParentEdge && parent.edge) {
parent.edge->RemoveChild();
parent.edge = 0;
} else if (parentType == k_ParentFace && parent.face) {
parent.face->RemoveChild();
parent.face = 0;
} else if (parentType == k_ParentVertex && parent.vertex) {
parent.vertex->RemoveChild();
parent.vertex = 0;
}
// Orphan the child vertex
if (vchild) {
vchild->SetParent(static_cast<HbrVertex*>(0));
vchild = 0;
}
// We're skipping the placement destructors here, in the
// assumption that HbrFVarData's destructor doesn't actually do
// anything much
if (nfvardata) {
free(morefvardata);
nfvardata = 0;
}
destroyed = 1;
}
}
template <class T>
void
HbrVertex<T>::AddIncidentEdge(HbrHalfedge<T>* edge) {
assert(edge->GetOrgVertex() == this);
// First, maintain the property that all of the incident edges
// will always be a boundary edge if possible. If any of the
// incident edges are no longer boundaries at this point then they
// can be immediately removed.
int i, newEdgeCount = 0;
bool edgeFound = false;
for (i = 0; i < nIncidentEdges; ++i) {
if (incidentEdges[i] == edge) {
edgeFound = true;
}
if (incidentEdges[i]->IsBoundary()) {
incidentEdges[newEdgeCount++] = incidentEdges[i];
} else {
// Did this edge suddenly stop being a boundary because
// the newly introduced edge (or something close to it)
// closed a cycle? If so, we don't want to lose a pointer
// to this edge cycle! So check to see if this cycle is
// complete, and if so, keep it.
HbrHalfedge<T>* start = incidentEdges[i];
HbrHalfedge<T>* edge = start;
bool prevmatch = false;
do {
edge = GetNextEdge(edge);
// Check all previous incident edges, if already
// encountered then we have an edge to this cycle and
// don't need to proceed further with this check
for (int j = 0; j < i; ++j) {
if (incidentEdges[j] == edge) {
prevmatch = true;
break;
}
}
} while (!prevmatch && edge && edge != start);
if (!prevmatch && edge && edge == start) {
incidentEdges[newEdgeCount++] = incidentEdges[i];
}
}
}
// If we are now left with no incident edges, then this edge
// becomes the sole incident edge (since we always need somewhere
// to start, even if it's a uninterrupted cycle [ie it doesn't
// matter whether the edge is a boundary]). Restore incidentEdges
// array to point to the end of the object.
if (newEdgeCount == 0) {
if (!(edgeFound && nIncidentEdges == 1)) {
if (nIncidentEdges > 1) {
delete [] incidentEdges;
}
incidentEdges = (HbrHalfedge<T>**) ((char*) this + sizeof(*this));
incidentEdges[0] = edge;
nIncidentEdges = 1;
}
}
// Otherwise, we already have a set of incident edges - we only
// add this edge if it's a boundary edge, which would begin a new
// cycle.
else if (edge->IsBoundary()) {
if (!edgeFound) {
// Must add the new edge. May need to reallocate here.
if (newEdgeCount + 1 != nIncidentEdges) {
HbrHalfedge<T>** newIncidentEdges = 0;
if (newEdgeCount + 1 > 1) {
newIncidentEdges = new HbrHalfedge<T>*[newEdgeCount + 1];
} else {
newIncidentEdges = (HbrHalfedge<T>**) ((char*) this + sizeof(*this));
}
for (i = 0; i < newEdgeCount; ++i) {
newIncidentEdges[i] = incidentEdges[i];
}
if (nIncidentEdges > 1) {
delete[] incidentEdges;
}
nIncidentEdges = newEdgeCount + 1;
incidentEdges = newIncidentEdges;
}
incidentEdges[newEdgeCount] = edge;
} else {
// Edge is already in our list, so we don't need to add it
// again. However, we may need to reallocate due to above
// cleaning of nonboundary edges
if (newEdgeCount != nIncidentEdges) {
HbrHalfedge<T>** newIncidentEdges = 0;
if (newEdgeCount > 1) {
newIncidentEdges = new HbrHalfedge<T>*[newEdgeCount];
} else {
newIncidentEdges = (HbrHalfedge<T>**) ((char*) this + sizeof(*this));
}
for (i = 0; i < newEdgeCount; ++i) {
newIncidentEdges[i] = incidentEdges[i];
}
if (nIncidentEdges > 1) {
delete[] incidentEdges;
}
nIncidentEdges = newEdgeCount;
incidentEdges = newIncidentEdges;
}
}
}
else {
// Again, we may need to reallocate due to above cleaning of
// nonboundary edges
if (newEdgeCount != nIncidentEdges) {
HbrHalfedge<T>** newIncidentEdges = 0;
if (newEdgeCount > 1) {
newIncidentEdges = new HbrHalfedge<T>*[newEdgeCount];
} else {
newIncidentEdges = (HbrHalfedge<T>**) ((char*) this + sizeof(*this));
}
for (i = 0; i < newEdgeCount; ++i) {
newIncidentEdges[i] = incidentEdges[i];
}
if (nIncidentEdges > 1) {
delete[] incidentEdges;
}
nIncidentEdges = newEdgeCount;
incidentEdges = newIncidentEdges;
}
}
// For non-boundary edges, ensure that the incident edge starting
// the cycle is the lowest possible edge. By doing this,
// operations like GetSurroundingEdges will be guaranteed to
// return the same order of edges/faces through multi-threading.
if (!incidentEdges[0]->IsBoundary()) {
HbrHalfedge<T>* start = GetIncidentEdge();
incidentEdges[0] = start;
HbrFacePath incidentEdgePath = incidentEdges[0]->GetFace()->GetPath();
HbrHalfedge<T>* e = GetNextEdge(start);
while (e) {
if (e == start) break;
HbrFacePath ePath = e->GetFace()->GetPath();
if (ePath < incidentEdgePath) {
incidentEdges[0] = e;
incidentEdgePath = ePath;
}
HbrHalfedge<T>* next = GetNextEdge(e);
if (!next) {
e = e->GetPrev();
if (e->GetFace()->GetPath() < incidentEdges[0]->GetFace()->GetPath()) {
incidentEdges[0] = e;
}
break;
} else {
e = next;
}
}
}
references++;
}
template <class T>
void
HbrVertex<T>::RemoveIncidentEdge(HbrHalfedge<T>* edge) {
int i, j;
references--;
if (references) {
HbrHalfedge<T>* next;
// We may need to shuffle our halfedge cycles. First we check
// whether the edge being erased begins any edge cycles
bool edgeFound = false;
next = GetNextEdge(edge);
for (i = 0; i < nIncidentEdges; ++i) {
if (incidentEdges[i] == edge) {
// Edge cycle found. Replace the edge with the next edge
// in the cycle if possible.
if (next) {
incidentEdges[i] = next;
// We are done.
return;
}
// If no next edge is found it means the entire cycle
// has gone away.
edgeFound = true;
break;
}
}
// The edge cycle needs to disappear
if (edgeFound) {
assert(nIncidentEdges > 1);
HbrHalfedge<T>** newIncidentEdges = 0;
if (nIncidentEdges - 1 > 1) {
newIncidentEdges = new HbrHalfedge<T>*[nIncidentEdges - 1];
} else {
newIncidentEdges = (HbrHalfedge<T>**) ((char*) this + sizeof(*this));
}
j = 0;
for (i = 0; i < nIncidentEdges; ++i) {
if (incidentEdges[i] != edge) {
newIncidentEdges[j++] = incidentEdges[i];
}
}
assert(j == nIncidentEdges - 1);
if (nIncidentEdges > 1) {
delete[] incidentEdges;
}
nIncidentEdges--;
incidentEdges = newIncidentEdges;
return;
}
// Now deal with the case where we remove an edge
// which did not begin a boundary edge cycle. If this
// happens then the resulting unbroken cycle does
// get broken; in that case we replace the incident
// edge with the next one after this.
else if (nIncidentEdges == 1 && !incidentEdges[0]->IsBoundary()) {
if (next) {
incidentEdges[0] = next;
} else {
// hm, what does this mean for us? Not sure at the
// moment.
std::cout << "Could not split cycle!\n";
assert(0);
}
}
// (Is this another case or a specialization of the above?)
// When an edge in the middle of a boundary cycle goes away we
// need to mark a new cycle.
//
// If there is no next edge, it means that we didn't
// actually split the cycle, we just deleted the last edge
// in the cycle. As such nothing needs to occur because
// the "split" is already present.
else if (!edge->IsBoundary() && next) {
HbrHalfedge<T>** newIncidentEdges = 0;
if (nIncidentEdges + 1 > 1) {
newIncidentEdges = new HbrHalfedge<T>*[nIncidentEdges + 1];
} else {
newIncidentEdges = (HbrHalfedge<T>**) ((char*) this + sizeof(*this));
}
for (i = 0; i < nIncidentEdges; ++i) {
newIncidentEdges[i] = incidentEdges[i];
}
newIncidentEdges[nIncidentEdges] = next;
if (nIncidentEdges > 1) {
delete[] incidentEdges;
}
nIncidentEdges++;
incidentEdges = newIncidentEdges;
}
} else {
// No references left, we can just clear all the cycles
if (nIncidentEdges > 1) {
delete[] incidentEdges;
incidentEdges = (HbrHalfedge<T>**) ((char*) this + sizeof(*this));
}
nIncidentEdges = 0;
}
}
template <class T>
bool
HbrVertex<T>::EdgeRemovalWillMakeSingular(HbrHalfedge<T>* edge) const {
// Only edge left, or no incident edges at all (how?)
if (references <= 1 || nIncidentEdges <= 0) {
return false;
}
// There are at least two existing cycles. We could maybe consider
// the case where removal of this edge will actually make one of
// the edge cycles go away, possibly leaving behind just one, but
// we'll ignore that possibility for now
else if (nIncidentEdges > 1) {
return true;
}
// This is the incident edge starting a single cycle. Removal of
// the edge will replace the start of the cycle with the next
// edge, and we keep a single cycle.
else if (nIncidentEdges == 1 && incidentEdges[0] == edge) {
return false;
}
// Check the single cycle: was it interrupted? (i.e. a
// boundary). If not interrupted, then deletion of any edge still
// leaves a single cycle. Otherwise: if the edge is the *last*
// edge in the cycle, we still don't need to split the any further
// cycle. Otherwise we must split the cycle, which would result in
// a singular vertex
else if (!incidentEdges[0]->IsBoundary()) {
return false;
} else if (GetNextEdge(edge)) {
return true;
} else {
return false;
}
}
template <class T>
void
HbrVertex<T>::Finish() {
extraordinary = false;
if (HbrMesh<T>* mesh = GetMesh()) {
if (IsSingular()) splitSingular();
assert(!IsSingular());
if (mesh->GetSubdivision()) {
extraordinary = mesh->GetSubdivision()->VertexIsExtraordinary(mesh, this);
}
}
}
template <class T>
int
HbrVertex<T>::GetValence() const {
int valence = 0;
assert(!IsSingular());
HbrHalfedge<T>* start = incidentEdges[0];
HbrHalfedge<T>* edge = start;
if (edge) do {
valence++;
edge = GetNextEdge(edge);
} while (edge && edge != start);
// In boundary cases, we increment the valence count by
// one more
if (!edge) valence++;
return valence;
}
template <class T>
int
HbrVertex<T>::GetCoarseValence() const {
int valence = 0;
assert(!IsSingular());
HbrHalfedge<T>* start = incidentEdges[0];
HbrHalfedge<T>* edge = start;
if (edge) do {
if (edge->IsCoarse()) {
valence++;
}
edge = GetNextEdge(edge);
} while (edge && edge != start);
// In boundary cases, we increment the valence count by one more
// (this assumes the last edge is coarse, which it had better be
// in the boundary case!)
if (!edge) valence++;
return valence;
}
template <class T>
HbrFVarData<T>&
HbrVertex<T>::GetFVarData(const HbrFace<T>* face) {
// See if there are any extra facevarying datum associated with
// this vertex, and whether any of them match the face.
if (nfvardata) {
size_t fvtsize = sizeof(HbrFVarData<T>) + sizeof(float) * GetMesh()->GetTotalFVarWidth();
HbrFVarData<T> *fvt = morefvardata;
for (int i = 0; i < nfvardata; ++i) {
if (fvt->GetFace() == face) {
return *fvt;
}
fvt = (HbrFVarData<T>*)((char*) fvt + fvtsize);
}
}
// Otherwise, return the default facevarying datum, which lives
// in the overallocated space after the end of this object
return *((HbrFVarData<T>*) ((char*) this + sizeof(*this) + sizeof(HbrHalfedge<T>*)));
}
template <class T>
HbrFVarData<T>&
HbrVertex<T>::NewFVarData(const HbrFace<T>* face) {
const int fvarwidth = GetMesh()->GetTotalFVarWidth();
size_t fvtsize = sizeof(HbrFVarData<T>) + fvarwidth * sizeof(float);
if (nfvardata) {
HbrFVarData<T> *newfvardata = (HbrFVarData<T>*) malloc((nfvardata + 1) * fvtsize);
HbrFVarData<T> *newfvt = newfvardata, *oldfvt = morefvardata;
for (int i = 0; i < nfvardata; ++i) {
new (newfvt) HbrFVarData<T>((float*) ((char*) newfvt + sizeof(HbrFVarData<T>)));
newfvt->SetAllData(fvarwidth, oldfvt->GetData(0));
newfvt->SetFace(oldfvt->GetFace());
oldfvt = (HbrFVarData<T>*)((char*) oldfvt + fvtsize);
newfvt = (HbrFVarData<T>*)((char*) newfvt + fvtsize);
}
new (newfvt) HbrFVarData<T>((float*) ((char*) newfvt + sizeof(HbrFVarData<T>)));
newfvt->SetFace(face);
free(morefvardata);
morefvardata = newfvardata;
nfvardata++;
return *newfvt;
} else {
morefvardata = (HbrFVarData<T>*) malloc(fvtsize);
new (morefvardata) HbrFVarData<T>((float*) ((char*) morefvardata + sizeof(HbrFVarData<T>)));
morefvardata->SetFace(face);
nfvardata = 1;
return *morefvardata;
}
}
template <class T>
HbrFace<T>*
HbrVertex<T>::GetFace() const {
return GetIncidentEdge()->GetFace();
}
template <class T>
HbrMesh<T>*
HbrVertex<T>::GetMesh() const {
return GetFace()->GetMesh();
}
template <class T>
HbrHalfedge<T>*
HbrVertex<T>::GetEdge(const HbrVertex<T>* dest) const {
// Here, we generally want to go through all halfedge cycles
for (int i = 0; i < nIncidentEdges; ++i) {
HbrHalfedge<T>* cycle = incidentEdges[i];
HbrHalfedge<T>* edge = cycle;
if (edge) do {
if (edge->GetDestVertex() == dest) {
return edge;
}
edge = GetNextEdge(edge);
} while (edge && edge != cycle);
}
return 0;
}
template <class T>
HbrHalfedge<T>*
HbrVertex<T>::GetNextEdge(const HbrHalfedge<T>* edge) const {
// Paranoia:
// if (edge->GetOrgVertex() != this) return 0;
return edge->GetPrev()->GetOpposite();
}
template <class T>
HbrHalfedge<T>*
HbrVertex<T>::GetPreviousEdge(const HbrHalfedge<T>* edge) const {
// Paranoia:
// if (edge->GetOrgVertex() != this) return 0;
return edge->GetOpposite()->GetNext();
}
template <class T>
HbrVertex<T>*
HbrVertex<T>::GetQEONext(const HbrVertex<T>* dest) const {
HbrHalfedge<T>* edge = GetEdge(dest);
if (edge) {
return edge->GetPrev()->GetOrgVertex();
}
HbrHalfedge<T>* start = GetIncidentEdge(), *next;
edge = start;
while (edge) {
next = GetNextEdge(edge);
if (edge->GetDestVertex() == dest) {
if (!next) {
return edge->GetPrev()->GetOrgVertex();
} else {
return next->GetDestVertex();
}
}
if (next == start) {
return 0;
} else if (!next) {
if (edge->GetPrev()->GetOrgVertex() == dest) {
return start->GetDestVertex();
} else {
return 0;
}
} else {
edge = next;
}
}
// Shouldn't get here
return 0;
}
template <class T>
HbrVertex<T>*
HbrVertex<T>::GetQEONext(const HbrHalfedge<T>* edge) const {
assert(edge->GetOrgVertex() == this);
return edge->GetPrev()->GetOrgVertex();
}
template <class T>
HbrVertex<T>*
HbrVertex<T>::GetQEOPrev(const HbrVertex<T>* dest) const {
HbrHalfedge<T>* edge = GetEdge(dest);
if (edge) {
if (edge->GetOpposite()) {
return edge->GetOpposite()->GetNext()->GetDestVertex();
} else {
HbrHalfedge<T>* start = GetIncidentEdge(), *next;
edge = start;
while (edge) {
next = GetNextEdge(edge);
if (next == start) {
if (next->GetDestVertex() == dest) {
return edge->GetDestVertex();
} else {
return 0;
}
} else if (!next) {
if (edge->GetPrev()->GetOrgVertex() == dest) {
return edge->GetDestVertex();
} else if (start->GetDestVertex() == dest) {
return edge->GetPrev()->GetOrgVertex();
} else {
return 0;
}
} else if (next->GetDestVertex() == dest) {
return edge->GetDestVertex();
} else {
edge = next;
}
}
return 0;
}
}
edge = dest->GetEdge(this);
if (edge) {
return edge->GetNext()->GetDestVertex();
}
return 0;
}
template <class T>
HbrVertex<T>*
HbrVertex<T>::GetQEOPrev(const HbrHalfedge<T>* edge) const {
assert(edge->GetOrgVertex() == this);
if (edge->GetOpposite()) {
return edge->GetOpposite()->GetNext()->GetDestVertex();
} else {
return GetQEOPrev(edge->GetDestVertex());
}
}
template <class T>
HbrVertex<T>*
HbrVertex<T>::GetQELNext(const HbrVertex<T>* dest) const {
HbrHalfedge<T>* edge = GetEdge(dest);
if (edge) {
return edge->GetNext()->GetDestVertex();
}
edge = dest->GetEdge(this);
if (edge) {
return edge->GetPrev()->GetOrgVertex();
}
return 0;
}
template <class T>
bool
HbrVertex<T>::OnBoundary() const {
// We really only need to check the first incident edge, since
// singular vertices by definition are on the boundary
return incidentEdges[0]->IsBoundary();
}
template <class T>
bool
HbrVertex<T>::IsFVarSmooth(int datum) {
return (GetFVarMask(datum) == k_Smooth);
}
template <class T>
bool
HbrVertex<T>::IsFVarAllSmooth() {
for (int i = 0; i < GetMesh()->GetFVarCount(); ++i) {
if (!IsFVarSmooth(i)) return false;
}
return true;
}
template <class T>
bool
HbrVertex<T>::IsFVarDart(int datum) {
return (GetFVarMask(datum) == k_Dart);
}
template <class T>
bool
HbrVertex<T>::IsFVarCorner(int datum) {
// If it's a dart, it's a corner
if (IsFVarDart(datum)) return true;
// Run through surrounding edges, looking for two adjacent
// facevarying boundary edges
HbrHalfedge<T>* start = GetIncidentEdge(), *edge, *nextedge;
edge = start;
bool lastedgewassharp = false;
while (edge) {
if (edge->GetFVarSharpness(datum)) {
if (lastedgewassharp) {
return true;
} else {
lastedgewassharp = true;
}
} else {
lastedgewassharp = false;
}
nextedge = GetNextEdge(edge);
if (nextedge == start) {
return start->GetFVarSharpness(datum) && lastedgewassharp;
} else if (!nextedge) {
// Special case for the last edge in a cycle.
edge = edge->GetPrev();
return edge->GetFVarSharpness(datum) && lastedgewassharp;
} else {
edge = nextedge;
}
}
return false;
}
template <class T>
unsigned char
HbrVertex<T>::GetMask(bool next) {
if (validmask) {
return (unsigned char)(next ? mask1 : mask0);
}
mask0 = mask1 = 0;
// Mark volatility
if (sharpness > k_Smooth && sharpness < k_InfinitelySharp)
volatil = 1;
// If the vertex is tagged as sharp immediately promote its mask
// to corner
if (IsSharp(false)) {
mask0 += k_Corner;
}
if (IsSharp(true)) {
mask1 += k_Corner;
}
// Count the number of surrounding sharp edges
HbrHalfedge<T>* start = GetIncidentEdge(), *edge, *nextedge;
edge = start;
while (edge) {
float esharp = edge->GetSharpness();
if (edge->IsSharp(false)) {
if (mask0 < k_Corner) {
mask0++;
}
}
if (edge->IsSharp(true)) {
if (mask1 < k_Corner) {
mask1++;
}
}
// If any incident edge is semisharp, mark the vertex as volatile
if (esharp > HbrHalfedge<T>::k_Smooth && esharp < HbrHalfedge<T>::k_InfinitelySharp) {
volatil = 1;
}
nextedge = GetNextEdge(edge);
if (nextedge == start) {
break;
} else if (!nextedge) {
// Special case for the last edge in a cycle.
edge = edge->GetPrev();
esharp = edge->GetSharpness();
if (edge->IsSharp(false)) {
if (mask0 < k_Corner) {
mask0++;
}
}
if (edge->IsSharp(true)) {
if (mask1 < k_Corner) {
mask1++;
}
}
if (esharp > HbrHalfedge<T>::k_Smooth && esharp < HbrHalfedge<T>::k_InfinitelySharp) {
volatil = 1;
}
break;
} else {
edge = nextedge;
}
}
validmask = 1;
return (unsigned char)(next ? mask1 : mask0);
}
template <class T>
unsigned char
HbrVertex<T>::GetFVarMask(int datum) {
unsigned char mask = 0;
// If the vertex is tagged as sharp immediately promote its mask
// to corner
if (IsSharp(false)) {
mask += k_Corner;
}
// Count the number of surrounding facevarying boundary edges
HbrHalfedge<T>* start = GetIncidentEdge(), *edge, *nextedge;
edge = start;
while (edge) {
if (edge->GetFVarSharpness(datum)) {
if (mask < k_Corner) {
mask++;
} else {
// Can't get any sharper, so give up early
break;
}
}
nextedge = GetNextEdge(edge);
if (nextedge == start) {
break;
} else if (!nextedge) {
// Special case for the last edge in a cycle.
edge = edge->GetPrev();
if (edge->GetFVarSharpness(datum)) {
if (mask < k_Corner) {
mask++;
}
}
break;
} else {
edge = nextedge;
}
}
return mask;
}
template <class T>
float
HbrVertex<T>::GetFractionalMask() const {
float mask = 0;
float n = 0;
if (sharpness > k_Smooth && sharpness < k_Dart) {
mask += sharpness; ++n;
}
// Add up the strengths of surrounding fractional sharp edges
HbrHalfedge<T>* start = GetIncidentEdge(), *edge, *next;
edge = start;
while (edge) {
float esharp = edge->GetSharpness();
if (esharp > HbrHalfedge<T>::k_Smooth && esharp < HbrHalfedge<T>::k_Sharp) {
mask += esharp; ++n;
}
next = GetNextEdge(edge);
if (next == start) {
break;
} else if (!next) {
// Special case for the last edge in a cycle.
esharp = edge->GetPrev()->GetSharpness();
if (esharp > HbrHalfedge<T>::k_Smooth && esharp < HbrHalfedge<T>::k_Sharp) {
mask += esharp; ++n;
}
break;
} else {
edge = next;
}
}
assert (n > 0.0f && mask < n);
return (mask / n);
}
template <class T>
template <typename OutputIterator>
void
HbrVertex<T>::GetSurroundingEdges(OutputIterator edges) const {
HbrHalfedge<T>* start = GetIncidentEdge(), *edge, *next;
edge = start;
while (edge) {
*edges++ = edge;
next = GetNextEdge(edge);
if (next == start) {
break;
} else if (!next) {
// Special case for the last edge in a cycle.
*edges++ = edge->GetPrev();
break;
} else {
edge = next;
}
}
}
template <class T>
void
HbrVertex<T>::ApplyOperatorSurroundingEdges(HbrHalfedgeOperator<T> &op) const {
HbrHalfedge<T>* start = GetIncidentEdge(), *edge, *next;
edge = start;
while (edge) {
op(*edge);
next = GetNextEdge(edge);
if (next == start) {
break;
} else if (!next) {
op(*edge->GetPrev());
break;
} else {
edge = next;
}
}
}
template <class T>
template <typename OutputIterator>
void
HbrVertex<T>::GetSurroundingVertices(OutputIterator vertices) const {
HbrHalfedge<T>* start = GetIncidentEdge(), *edge, *next;
edge = start;
while (edge) {
*vertices++ = edge->GetDestVertex();
next = GetNextEdge(edge);
if (next == start) {
break;
} else if (!next) {
// Special case for the last edge in a cycle: the last
// vertex on that cycle is not the destination of an
// outgoing halfedge
*vertices++ = edge->GetPrev()->GetOrgVertex();
break;
} else {
edge = next;
}
}
}
template <class T>
void
HbrVertex<T>::ApplyOperatorSurroundingVertices(HbrVertexOperator<T> &op) const {
HbrHalfedge<T>* start = GetIncidentEdge(), *edge, *next;
edge = start;
while (edge) {
op(*edge->GetDestVertex());
next = GetNextEdge(edge);
if (next == start) return;
else if (!next) {
op(*edge->GetPrev()->GetOrgVertex());
return;
} else {
edge = next;
}
}
}
template <class T>
void
HbrVertex<T>::ApplyOperatorSurroundingFaces(HbrFaceOperator<T> &op) const {
HbrHalfedge<T>* start = GetIncidentEdge(), *edge;
edge = start;
while (edge) {
op(*edge->GetLeftFace());
edge = GetNextEdge(edge);
if (edge == start) break;
}
}
template <class T>
HbrVertex<T>*
HbrVertex<T>::Subdivide() {
if (vchild) return vchild;
HbrMesh<T>* mesh = GetMesh();
vchild = mesh->GetSubdivision()->Subdivide(mesh, this);
vchild->SetParent(this);
return vchild;
}
template <class T>
void
HbrVertex<T>::Refine() {
HbrMesh<T>* mesh = GetMesh();
mesh->GetSubdivision()->RefineAtVertex(mesh, this);
}
template <class T>
void
HbrVertex<T>::GuaranteeNeighbors() {
if (!neighborsguaranteed) {
HbrMesh<T>* mesh = GetMesh();
mesh->GetSubdivision()->GuaranteeNeighbors(mesh, this);
neighborsguaranteed = 1;
// At this point we can apply vertex edits because we have all
// surrounding faces, and know whether any of them has
// necessary edit information (they would have set our
// hasvertexedit bit)
if (hasvertexedit && !editsapplied) {
HbrHalfedge<T>* start = GetIncidentEdge(), *edge;
edge = start;
while (edge) {
HbrFace<T>* face = edge->GetLeftFace();
if (HbrHierarchicalEdit<T>** edits = face->GetHierarchicalEdits()) {
while (HbrHierarchicalEdit<T>* edit = *edits) {
if (!edit->IsRelevantToFace(face)) break;
edit->ApplyEditToVertex(face, this);
edits++;
}
}
edge = GetNextEdge(edge);
if (edge == start) break;
}
editsapplied = 1;
}
}
}
template <class T>
unsigned long
HbrVertex<T>::GetMemStats() const {
return sizeof(HbrVertex<T>);
}
template <class T>
void
HbrVertex<T>::splitSingular() {
HbrMesh<T>* mesh = GetMesh();
HbrHalfedge<T>* e;
// Go through each edge cycle after the first
std::vector<HbrHalfedge<T>*> edges;
for (int i = 1; i < nIncidentEdges; ++i) {
// Create duplicate vertex
HbrVertex<T>* w = mesh->NewVertex();
w->GetData().AddWithWeight(GetData(), 1.0);
w->SetSharpness(GetSharpness());
// Walk all edges in this cycle and reattach them to duplicate
// vertex
HbrHalfedge<T>* start = incidentEdges[i];
e = start;
edges.clear();
do {
edges.push_back(e);
e = GetNextEdge(e);
} while (e && e != start);
for (typename std::vector<HbrHalfedge<T>*>::iterator ei = edges.begin(); ei != edges.end(); ++ei) {
e = *ei;
if (e->GetOpposite()) {
HbrHalfedge<T>* next = e->GetOpposite()->GetNext();
if (next->GetOrgVertex() == this) {
references--;
next->SetOrgVertex(w);
w->AddIncidentEdge(next);
}
}
// Check again, because sometimes it's been relinked by
// previous clause already
if (e->GetOrgVertex() == this) {
references--;
e->SetOrgVertex(w);
w->AddIncidentEdge(e);
}
}
w->Finish();
}
e = incidentEdges[0];
if (nIncidentEdges > 1) {
delete[] incidentEdges;
}
nIncidentEdges = 1;
incidentEdges = (HbrHalfedge<T>**) ((char*) this + sizeof(*this));
incidentEdges[0] = e;
}
template <class T>
std::ostream&
operator<<(std::ostream& out, const HbrVertex<T>& vertex) {
return out << "vertex " << vertex.GetID();
}
template <class T>
class HbrVertexOperator {
public:
virtual void operator() (HbrVertex<T> &vertex) = 0;
virtual ~HbrVertexOperator() {}
};
} // end namespace OPENSUBDIV_VERSION
using namespace OPENSUBDIV_VERSION;
} // end namespace OpenSubdiv
#endif /* HBRVERTEX_H */