OpenSubdiv/opensubdiv/hbr/vertex.h
manuelk c3cb17fa99 Modify Far remapping of singular vertices to point to their source vertex.
- Add a vector of index pairs to HbrMesh to track the index of a split
  vertex and its origin vertex
- Correct the Far remap tables in FarSubdivisionTablesFactory to point split
  vertices to their origin instead of themselves
- Fix regression/common/shape_utils.h to use the new HbrMesh::GetSplitVertices()
  method.
- Fix the osdPolySmooth example to use the new HbrMesh::GetSplitVertices()
  method.
- Add a paragraph to the documentation

fixes #241
2013-11-21 16:05:31 -08:00

1559 lines
49 KiB
C++

//
// Copyright 2013 Pixar
//
// Licensed under the Apache License, Version 2.0 (the "Apache License")
// with the following modification; you may not use this file except in
// compliance with the Apache License and the following modification to it:
// Section 6. Trademarks. is deleted and replaced with:
//
// 6. Trademarks. This License does not grant permission to use the trade
// names, trademarks, service marks, or product names of the Licensor
// and its affiliates, except as required to comply with Section 4(c) of
// the License and to reproduce the content of the NOTICE file.
//
// You may obtain a copy of the Apache License at
//
// http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the Apache License with the above modification is
// distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
// KIND, either express or implied. See the Apache License for the specific
// language governing permissions and limitations under the Apache License.
//
#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(HbrMesh<T> *mesh = 0);
// 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;
// Return an edge connected to vertex with id dest
HbrHalfedge<T>* GetEdge(int 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;
}
// True if the edge has a subdivided child vertex
bool HasChild() const { return vchild!=-1; }
// Remove the reference to subdivided vertex
void RemoveChild() { vchild = -1; }
// 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 {
if (nIncidentEdges > 1) {
return incident.edges[0];
} else if (nIncidentEdges == 1) {
return incident.edge;
} else {
return 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 != -1); }
// Used by block allocator
HbrVertex<T>*& GetNext() { return parent.vertex; }
// Returns the blind pointer to client data
void *GetClientData(HbrMesh<T>* mesh) const {
return mesh->GetVertexClientData(id);
}
// Sets the blind pointer to client data
void SetClientData(HbrMesh<T> *mesh, void *data) {
mesh->SetVertexClientData(id, 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. This struct is actually overpadded.
struct morefvardata {
int count;
} *morefvar;
// Unique ID of this vertex
int id;
// 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;
// Sharpness
float sharpness;
// Index of child vertex
int vchild;
// Size of incident array
unsigned short nIncidentEdges;
// 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, the edge field of the union points
// directly at the edge which starts the only incident cycle. If
// nIncidnetEdges is 2 or more, the edges field of the union is a
// separate allocated array and edge member of the array points at
// separate cycles.
union {
HbrHalfedge<T>* edge;
HbrHalfedge<T>** edges;
} incident;
union {
HbrFace<T>* face;
HbrHalfedge<T>* edge;
HbrVertex<T>* vertex;
} parent;
#ifdef HBR_ADAPTIVE
public:
struct adaptiveFlags {
unsigned isTagged:1;
unsigned wasTagged:1;
adaptiveFlags() : isTagged(0), wasTagged(0) { }
};
adaptiveFlags _adaptiveFlags;
#endif
};
template <class T>
HbrVertex<T>::HbrVertex() :
morefvar(0), id(-1), references(0), used(0),
sharpness(0.0f), vchild(-1), nIncidentEdges(0), extraordinary(0), validmask(0),
volatil(0), neighborsguaranteed(0), collected(0), hasvertexedit(0),
editsapplied(0), destroyed(0), parentType(k_ParentNone) {
ClearMask();
parent.vertex = 0;
incident.edge = 0;
}
template <class T>
void
HbrVertex<T>::Initialize(int vid, const T &vdata, int fvarwidth) {
data = vdata;
morefvar = 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 = -1;
assert(!parent.vertex);
parentType = k_ParentVertex;
parent.vertex = 0;
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
char *buffer = ((char*) this + sizeof(*this));
new (buffer) HbrFVarData<T>();
}
}
template <class T>
HbrVertex<T>::~HbrVertex() {
Destroy();
}
template <class T>
void
HbrVertex<T>::Destroy(HbrMesh<T> *mesh) {
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 != -1) {
if (mesh) {
HbrVertex<T> *vchildVert = mesh->GetVertex(vchild);
vchildVert->SetParent(static_cast<HbrVertex*>(0));
}
vchild = -1;
}
// We're skipping the placement destructors here, in the
// assumption that HbrFVarData's destructor doesn't actually do
// anything much
if (morefvar) {
free(morefvar);
}
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;
unsigned short newEdgeCount = 0;
bool edgeFound = false;
HbrHalfedge<T>** incidentEdges =
(nIncidentEdges > 1) ? incident.edges : &incident.edge;
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 = &incident.edge;
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 = &incident.edge;
}
for (i = 0; i < newEdgeCount; ++i) {
newIncidentEdges[i] = incidentEdges[i];
}
if (nIncidentEdges > 1) {
delete[] incidentEdges;
}
nIncidentEdges = newEdgeCount + 1;
incidentEdges = newIncidentEdges;
if (nIncidentEdges > 1) {
incident.edges = 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 = &incident.edge;
}
for (i = 0; i < newEdgeCount; ++i) {
newIncidentEdges[i] = incidentEdges[i];
}
if (nIncidentEdges > 1) {
delete[] incidentEdges;
}
nIncidentEdges = newEdgeCount;
incidentEdges = newIncidentEdges;
if (nIncidentEdges > 1) {
incident.edges = 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 = &incident.edge;
}
for (i = 0; i < newEdgeCount; ++i) {
newIncidentEdges[i] = incidentEdges[i];
}
if (nIncidentEdges > 1) {
delete[] incidentEdges;
}
nIncidentEdges = newEdgeCount;
incidentEdges = newIncidentEdges;
if (nIncidentEdges > 1) {
incident.edges = 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;
HbrHalfedge<T>** incidentEdges =
(nIncidentEdges > 1) ? incident.edges : &incident.edge;
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 = &incident.edge;
}
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--;
if (nIncidentEdges > 1) {
incident.edges = 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 = &incident.edge;
}
for (i = 0; i < nIncidentEdges; ++i) {
newIncidentEdges[i] = incidentEdges[i];
}
newIncidentEdges[nIncidentEdges] = next;
if (nIncidentEdges > 1) {
delete[] incidentEdges;
}
nIncidentEdges++;
if (nIncidentEdges > 1) {
incident.edges = newIncidentEdges;
}
}
} else {
// No references left, we can just clear all the cycles
if (nIncidentEdges > 1) {
delete[] incidentEdges;
}
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 && incident.edge == 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 (!GetIncidentEdge()->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 =
(nIncidentEdges > 1) ? incident.edges[0] : incident.edge;
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 =
(nIncidentEdges > 1) ? incident.edges[0] : incident.edge;
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 (morefvar) {
size_t fvtsize = sizeof(HbrFVarData<T>) + sizeof(float) * (GetMesh()->GetTotalFVarWidth() - 1);
HbrFVarData<T> *fvt = (HbrFVarData<T> *)((char *) morefvar + sizeof(int));
for (int i = 0; i < morefvar->count; ++i) {
if (fvt->GetFaceID() == face->GetID()) {
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)));
}
template <class T>
HbrFVarData<T>&
HbrVertex<T>::NewFVarData(const HbrFace<T>* face) {
const int fvarwidth = GetMesh()->GetTotalFVarWidth();
size_t fvtsize = sizeof(HbrFVarData<T>) + (fvarwidth - 1) * sizeof(float);
if (morefvar) {
struct morefvardata *newmorefvar =
(struct morefvardata *) malloc(sizeof(int) + (morefvar->count + 1) * fvtsize);
HbrFVarData<T> *newfvt = (HbrFVarData<T> *)((char *) newmorefvar + sizeof(int));
HbrFVarData<T> *oldfvt = (HbrFVarData<T> *)((char *) morefvar + sizeof(int));
for (int i = 0; i < morefvar->count; ++i) {
new (newfvt) HbrFVarData<T>();
newfvt->SetAllData(fvarwidth, oldfvt->GetData(0));
newfvt->SetFaceID(oldfvt->GetFaceID());
oldfvt = (HbrFVarData<T>*)((char*) oldfvt + fvtsize);
newfvt = (HbrFVarData<T>*)((char*) newfvt + fvtsize);
}
new (newfvt) HbrFVarData<T>();
newfvt->SetFaceID(face->GetID());
newmorefvar->count = morefvar->count + 1;
free(morefvar);
morefvar = newmorefvar;
return *newfvt;
} else {
morefvar = (struct morefvardata *) malloc(sizeof(int) + fvtsize);
HbrFVarData<T> *newfvt = (HbrFVarData<T> *)((char *) morefvar + sizeof(int));
new (newfvt) HbrFVarData<T>();
newfvt->SetFaceID(face->GetID());
morefvar->count = 1;
return *newfvt;
}
}
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 =
(nIncidentEdges > 1) ? incident.edges[i] : incident.edge;
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>::GetEdge(int dest) const {
// Here, we generally want to go through all halfedge cycles
for (int i = 0; i < nIncidentEdges; ++i) {
HbrHalfedge<T>* cycle =
(nIncidentEdges > 1) ? incident.edges[i] : incident.edge;
HbrHalfedge<T>* edge = cycle;
if (edge) do {
if (edge->GetDestVertexID() == 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 GetIncidentEdge()->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 {
HbrMesh<T>* mesh = GetMesh();
HbrHalfedge<T>* start = GetIncidentEdge(), *edge, *next;
edge = start;
while (edge) {
*vertices++ = edge->GetDestVertex(mesh);
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(mesh);
break;
} else {
edge = next;
}
}
}
template <class T>
void
HbrVertex<T>::ApplyOperatorSurroundingVertices(HbrVertexOperator<T> &op) const {
HbrMesh<T>* mesh = GetMesh();
HbrHalfedge<T>* start = GetIncidentEdge(), *edge, *next;
edge = start;
while (edge) {
op(*edge->GetDestVertex(mesh));
next = GetNextEdge(edge);
if (next == start) return;
else if (!next) {
op(*edge->GetPrev()->GetOrgVertex(mesh));
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() {
HbrMesh<T>* mesh = GetMesh();
if (vchild != -1) return mesh->GetVertex(vchild);
HbrVertex<T>* vchildVert = mesh->GetSubdivision()->Subdivide(mesh, this);
vchild = vchildVert->GetID();
vchildVert->SetParent(this);
return vchildVert;
}
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;
HbrHalfedge<T>** incidentEdges =
(nIncidentEdges > 1) ? incident.edges : &incident.edge;
// 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();
#ifdef HBR_ADAPTIVE
mesh->addSplitVertex(w->GetID(), this->GetID());
#endif
}
e = incidentEdges[0];
if (nIncidentEdges > 1) {
delete[] incidentEdges;
}
nIncidentEdges = 1;
incident.edge = 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 */