From BlenderWiki
Update: Circulators and Iterators
I've written a basic proposed API for iterators and circulators to be used in hemesh. Bascially, circulators seem to be iterators that allow access to the item you started iterating with--not necassarily the first item in a "list," as the list can be circular (e.g. half-edges).
Basically I'd like most of hemesh to use these iterator/circulator functions, including circulating the edges around a vert, circulating any extra solids around a vert (I believe the proper term is inner boundary vertex holes, if I'm not mistaken, though I may be), iterating through all edge-info structs (or half-edge pairs if we decide to kill the HE_EdgeInfo struct), etc.
typedef struct HE_Circulator { void *beginElem; void *data; /*->next returns the next element, plus increments the circulator to the next element too, same for ->prev*/ void *(*next)(struct HE_Circulator *self); void *(*prev)(struct HE_Circulator *self); void (*dealloc)(struct HE_Circulator *self); } HE_Circulator; typedef struct HE_Iterator { void *start; void *data; void *(*next)(struct HE_Iterator *self); void *(*prev)(struct HE_Iterator *self); void (*dealloc)(struct HE_Iterator *self); } HE_Iterator;
Proposed API for modifying the internal HE mesh
This is my new proposed API for handling mesh operations, HE_Operations. It has it's own module prefix, HEOP, for HE Operations.
Here is the code:
/****************HALF-Edge Mesh Modifyer API*********** * * * * * --Rules of using hemesh operations API: * * NEVER CHANGE A THING about the data except for * * flags and vertex coordinates. ESPECIALLY the * * pointers! * * * * Theres no point in creating a wrapper structure if * * it can be at all avoided. BUT this means no * * modifying the mesh outside these functions! That's * * why TryMerge is in this API, just in case I'm * * forced to use the hackish method of merging * * *shudder*. * ******************************************************/ /**************************************************** * Query Operations * ****************************************************/ /*the all-important euler validation function, throws HE_NON_MANIFOLD if the mesh doesn't pass.*/ void HE_CheckEuler(HE_EditMesh *em) /*returns the first edge info in the mesh*/ HE_EditEdgeInfo *HEOP_getFirstEditEdgeInfo(HE_EditMesh *em) /*returns the first face in the mesh*/ HE_EditFace *HEOP_getFirstFace(HE_EditMesh *em) /*Note: all these vert-query functions return NULL-stopped arrays.*/ /*returns a null-stopped list of the solids around a vert, using nice circular-vert system. the list is populated with half-edges, one for each incident disc.*/ HE_EditEdge **HEOP_getSolidsAroundVerts(HE_EditMesh *em, HE_EditVert *eve) { } /*returns a null-stopped list of the edges around a vert*/ HE_EditEdge **HEOP_getHalfEdgesAroundVert(HE_EditMesh *em, HE_EditVert *eve); /*returns a null-stopped list of the faces around a vert*/ HE_EditFace **HEOP_getFacesAroundVert(HE_EditMesh *em, HE_EditVert *eve); /*returns a null-stopped list of the vertices around a vert*/ HE_EditVert **HEOP_getVertsAroundVerts(HE_EditMesh *em, HE_EditVert *eve); /*sets the variables pointer by the pointers to various mesh info, such as number of vert, number of edges (not counting half-edge duplicates), number of faces and the number of materials associated with the mesh.*/ void HEOP_getMeshInfo(HE_EditMesh *em, int *totface, int *totinfoedge, int *totvert, int *totmat); /**************************************************** * Additive Operations * ****************************************************/ /*creates a vert inside of a face, triangulating? that face. retains the origional face as one of the new quads?.*/ HE_EditVert *HEOP_makeVertInFace(HE_EditMesh *em, HE_EditFace *efa, float co[3]); HE_EditVert *HEOP_makeVertInEdge(HE_EditMesh *em, HE_EditFace *efa, float co[3]); /*Slices a face between two edges. Raises HE_INVALID_ARGUMENT if the edges are not on the same face.*/ HE_EditFace *HEOP_splitFaceBetweenTwoEdges(HE_EditMesh *em, HE_EditFace *efa, HE_EditEdge *e1, HE_EditEdge *e2) /*Splits a series of connected edges off of a face, and forms a new one. returns the newly formed face. Raises HE_INVALID_ARGUMENT if the edges are not adjacent and on the same face.*/ HE_EditFace *HEOP_splitEdgesOffFace(HE_EditMesh *em, HE_EditFace *efa, HE_EditEdge **elist); /**************************************************** * Subtractive Operations * ****************************************************/ /*Returns the newly formed face, which will likely simply be f1.*/ HE_EditFace *HEOP_joinAdjacentFaces(HE_EditMesh *em, HE_EditFace *f1, HE_EditMest *f2); /*This returns the new face created when the vert was removed*/ HE_EditFace *HEOP_deleteVert(HE_EditMesh *em, HE_EditFace *f1); /*This returns the new vert formed by the collapsed edge, which is really just edge->v1*/ HE_EditVert *HEOP_collapseEdge(HE_EditMesh *em, HE_EditEdge *e1); /*Collapse a face*/ HE_EditVert *HEOP_collapseFace(HE_EditMesh *em, HE_EditEdge *e1); /*this attempts to merge geomerty with the flag "flag" set in the flag variable at index "flagvar", and raises a NON_MANIFOLD_ERROR if unsuccessful. it works on a copy of HE_EditMesh, so it won't corrupt anything. This operation is to faciliate a generic merge tool, and will likely be written to break down into euler ops (should be possible, although the more hackish way of brute-force merging the verts and then re-creating the editmesh may be faster (but that's a bad way of doing it). */ void HEOP_tryToMerge(HE_EditMesh *em, int flagvar, int flag); /**************************************************** * A Very Simple Error API * ****************************************************/ /* *This (really simple) error system is how hemesh passes *fatal* messages around. *So, if an operation borks and messess up the euler, HEOP_CheckEuler will *set an error. In HEOP_tryToMerge, if it fails merging it will set an error *(which your supposed to catch). In the case of HEOP_tryToMerge, it restores *a damaged mesh, but in most cases after an error you have to clear the error *stack and restore the mesh to a previous state. * *this is why I've left a more intact generic way of calling user tools in place; *it's transparent even to blender (much less a user), and it will allow catching *these errors. */ int HEOP_CheckError(HE_EditMesh *em) static char *he_error_string(HE_EditMesh *em) char *HEOP_ErrorCodeToString(int code, HE_EditMesh *em) int HEOP_CatchError(HE_EditMesh *em, int errorcode) void HEOP_PrintErrorStack(HE_EditMesh *em) void HEOP_RaiseError(HE_EditMesh *em, char *from_name, int errorcode) /*str is NOT mem_freeN'd!*/ void HEOP_RaiseErrorString(HE_EditMesh *em, char *str);