/* brep.h: An edge-based Boundary Representation of solids, similar
 *         to the winged-edge data structure. */

#ifndef _BREP_H_
#define _BREP_H_

#ifdef __cplusplus
extern "C" {
#endif

/* ******************* The Topological Data Structure *********************/
/*
 * References:
 *
 * - Kevin Weiler, "Edge-based Data Structures for Solid Modeling in 
 *   Curved-Surface Environments", IEEE Computer graphics and Applications,
 *   January, 1985.
 * - Martti Mantyla and Reijo Sulonen, "GWB: A Solid Modeler with Euler
 *   Operators", IEEE Computer graphics and Applications, September 1982.
 * - Tony C. Woo, "A Combinatorial Analysis of Boundary Data Structure
 *   Schemata", IEEE Computer graphics and Applications, March 1985.
 * - Andrew S. Glassner, "Maintaining Winged-Edge Models", Graphics Gems II,
 *   James Arvo (editor), Academic Press, 1991
 * - Mark Segal and Carlo H. Sequin, "Partitioning Polyhedral Objects into
 *   Nonintersecting Parts", IEEE Computer graphics and Applications, January,
 *   1988.
 */

/* the boundary of a solid consists of one or more SHELLs.
 * User-supplied geometric and other data for the solid is pointed to 
 * by 'client_data' */
typedef struct BREP_SOLID {
  void *client_data;			/* pointer to whatever data the user 
					 * wants to keep with the solid */
  struct BREP_SHELL *shells;
  struct BREP_VERTEX_OCTREE *vertices;	/* vertices, sorted in an octree 
					 * for fast lookup. */
} BREP_SOLID;

/* A shell is basically a collection of connected faces representing an
 * orientable two-manifold. This means: a two-dimensional surface (in 3D 
 * space here), where each point on the surface has a neighbourhood 
 * topologically equivalent to an open disk. The surface must be orientable
 * and closed. Orientable means that it is two-sided. There must be a clear
 * distinction between its inside and its outside. The data structure
 * here only represent the (adjacency) topology of a surface. It is up
 * to the user of this data structure and library funtions to fill in
 * the geometry information and make sure that it is geometrically 
 * consistent. That means that the assigned shape should be consistent with
 * the topology. */
typedef struct BREP_SHELL {
  void *client_data;
  struct BREP_SHELL *prev, *next;	/* doubly linked ring to make
					 * insertions and removals easy */
  struct BREP_FACE *faces;
  struct BREP_SOLID *solid;		/* backpointer to the containing 
					 * solid */
} BREP_SHELL;

/* A face is a bounded open subset of a plane, bounded by one or more 
 * contours. One contour defines the outside of the face. Other contours
 * describe its cavities. The contours describing cavities are called
 * rings. The orientation of the outer contour must be counterclockwise as
 * seen from the direction of the normal to the containing plane. Rings
 * must be oriented clockwise. The cross product of a contour edge direction
 * and the plane normal is always a vector that points to the outside of
 * a face. Or in other words, the inside of a face is always on the left side
 * of a contour. The geometric data supplied by the user must conform with 
 * this rule. The rings, if any, are pointed to by the outer contour. 
 * When building a face, the first contour being specified must be the 
 * outer contour (at least if your application relies on this 
 * interpretation). */
typedef struct BREP_FACE {
  void *client_data;
  struct BREP_FACE *prev, *next;	/* faces form a doubly linked ring */
  struct BREP_CONTOUR *outer_contour;
  struct BREP_SHELL *shell;		/* backpointer to the containing 
					 * shell */
} BREP_FACE;

/* A contour represents a single closed planar polygonal curve (a loop).
 * Self-intersecting contours are not allowed. Different contours may only
 * intersect at common vertices or edges if at all. Here, we provide pointers
 * to WINGs instead of EDGEs in order to have implicit information about
 * the orientation of an edge as used in a contour. This facilitates 
 * iterating over the edges or vertices in a contour in a consistent manner. 
 * When building a contour, the edges must be specified in the right order:
 * the inside of the face is always to the left of an edge. In a two-manifold,
 * outer contours do not touch inner contours (they don't intersect 
 * and do not share vertices or edges). However, a vertex may be
 * used several times in a contour and two outer or inner contours
 * can share an edge, but only in opposite direction. If you need multiple
 * pairs of contours sharing the same vertex, you probably want 
 * topologically different vertices at the same place in 3D space. Same if
 * you believe you need inner and outer contours sharing a vertex. */
typedef struct BREP_CONTOUR {
  void *client_data;
  struct BREP_CONTOUR *prev, *next;	/* contours form a doubly linked ring 
					 * in order to facilitate the splitting
					 * and merging of contours. There is 
					 * one ring per face, containing the 
					 * outer contour as well as the 
					 * rings. */
  struct BREP_WING *wings;
  struct BREP_FACE *face;		/* backpointer to the containing 
					 * face */
} BREP_CONTOUR;

/* An edge is a unique connection between two vertices. There can be no more
 * than one edge between two given vertices in a valid model. An edge  can be 
 * used in two contours. The use of an edge in a contour is called a 
 * wing. A wing contains the starting vertex of the edge in the contour. The
 * other vertex is the starting vertex in the other wing, since the edge should
 * be used in opposite sense by the other contour sharing the edge. 
 * The invariant is: wing->vertex == OtherWingInEdge(wing->prev)->vertex:
 * the starting point in a wing is the endpoint of the edge specified in 
 * wing->prev. 
 * The data structure contains two more pointers than a winged edge data 
 * structure, but the code to operate on it is significantly simpler, cfr. 
 * [Weiler 1985]. The data structure is more compact than in [Glassner 1991]. */
typedef struct BREP_WING {
  struct BREP_VERTEX *vertex;		/* startvertex */
  struct BREP_WING *prev, *next;	/* ClockWise and CounterClockWise
					 * next wing within outer contours */
  struct BREP_EDGE *edge;		/* pointer to the containing edge */
  struct BREP_CONTOUR *contour;		/* backpointer to the containing 
					 * contour */
} BREP_WING;

typedef struct BREP_EDGE {
  void *client_data;
  struct BREP_WING wing[2];		/* two wings */
} BREP_EDGE;

/* A doubly linked ring of wings indicates in what wings a vertex is being used. 
 * The code becomes a lot simpler and more efficient when explicitely remembering
 * with each vertex what wings leave at the vertex. It also allows to deal
 * easier with partial shells: shells not enclosing a region into space, such
 * as a collection of coplanar faces, which is often used in synthetic
 * environments. */
typedef struct BREP_WING_RING {
  BREP_WING *wing;
  struct BREP_WING_RING *prev, *next;
} BREP_WING_RING;

/* A vertex is basically a point in 3D space. */
typedef struct BREP_VERTEX {
  void *client_data;
  BREP_WING_RING *wing_ring;		 /* ring of wings leaving at the vertex */
} BREP_VERTEX;


/* *********************** Callback Functions ************************** */
/* In order to maintain other than topological data with the entities,
 * e.g. geometrical data such as coordinates of a vertex, plane equation
 * of a face etc ..., three callback functions are associated with
 * each entity:
 *
 * - a Create callback: called when the topological entity is created
 *	this is the moment to duplicate the client data passed with
 *	an entity in order to make a private copy for that entity;
 *
 * - a Close callback: called when the topological entity is
 *	completely specified. A vertex is completely specified when it
 *	is created, an edge is completely specified each time it is
 *	included in a contour. Contours, faces, shells and solids
 *	are considered completely specified only when the user
 *	lets it know to the library by calling BrepCloseSolid().
 *	A Close callback is a good moment to compute plane equations
 *	for faces, to compute bounding boxes, to verify etc...
 *
 * - a Destroy callback: when the topological entity is being destroyed.
 *	A Destroy callback is the place to dispose of the client data
 *	for an entity.
 *
 * argument: a pointer to the topological entity being created,
 *	     closed or destroyed.
 *
 * return value: for a Create or Close callback, a pointer to the new 
 *	     client data to be kept with the topological entity. 
 *	     for a Destroy callback: none 
 *
 * Default callback functions: none. If a callback function is not set,
 *	no action is taken and nothing is changed to the client data
 *	of an entity.
 */

typedef void *(*BREP_CALLBACK_FUNC)(void *);

extern BREP_CALLBACK_FUNC BrepSetCreateSolidCallback(BREP_CALLBACK_FUNC func);
extern BREP_CALLBACK_FUNC BrepSetCreateShellCallback(BREP_CALLBACK_FUNC func);
extern BREP_CALLBACK_FUNC BrepSetCreateFaceCallback(BREP_CALLBACK_FUNC func);
extern BREP_CALLBACK_FUNC BrepSetCreateContourCallback(BREP_CALLBACK_FUNC func);
extern BREP_CALLBACK_FUNC BrepSetCreateEdgeCallback(BREP_CALLBACK_FUNC func);
extern BREP_CALLBACK_FUNC BrepSetCreateVertexCallback(BREP_CALLBACK_FUNC func);

extern BREP_CALLBACK_FUNC BrepSetCloseSolidCallback(BREP_CALLBACK_FUNC func);
extern BREP_CALLBACK_FUNC BrepSetCloseShellCallback(BREP_CALLBACK_FUNC func);
extern BREP_CALLBACK_FUNC BrepSetCloseFaceCallback(BREP_CALLBACK_FUNC func);
extern BREP_CALLBACK_FUNC BrepSetCloseContourCallback(BREP_CALLBACK_FUNC func);
extern BREP_CALLBACK_FUNC BrepSetCloseEdgeCallback(BREP_CALLBACK_FUNC func);
extern BREP_CALLBACK_FUNC BrepSetCloseVertexCallback(BREP_CALLBACK_FUNC func);

extern BREP_CALLBACK_FUNC BrepSetDestroySolidCallback(BREP_CALLBACK_FUNC func);
extern BREP_CALLBACK_FUNC BrepSetDestroyShellCallback(BREP_CALLBACK_FUNC func);
extern BREP_CALLBACK_FUNC BrepSetDestroyFaceCallback(BREP_CALLBACK_FUNC func);
extern BREP_CALLBACK_FUNC BrepSetDestroyContourCallback(BREP_CALLBACK_FUNC func);
extern BREP_CALLBACK_FUNC BrepSetDestroyEdgeCallback(BREP_CALLBACK_FUNC func);
extern BREP_CALLBACK_FUNC BrepSetDestroyVertexCallback(BREP_CALLBACK_FUNC func);


/* callback routines for communicating informational, warning, error and
 * fatal error messages. First parameter (if non-null) is a pointer
 * to the client data of the topological entity that caused the 
 * error (use and identification of this info is left to the user of
 * this library). The second argument is the message itself. */
typedef void (*BREP_MSG_CALLBACK_FUNC)(void *client_data, char *message);

/* No error message from the library is longer than this */
#define BREP_MAX_MESSAGE_LENGTH 200

/* The SetCallback functions return the previously set callback function */
extern BREP_MSG_CALLBACK_FUNC BrepSetInfoCallback(BREP_MSG_CALLBACK_FUNC f);
extern BREP_MSG_CALLBACK_FUNC BrepSetWarningCallback(BREP_MSG_CALLBACK_FUNC f);
extern BREP_MSG_CALLBACK_FUNC BrepSetErrorCallback(BREP_MSG_CALLBACK_FUNC f);
extern BREP_MSG_CALLBACK_FUNC BrepSetFatalCallback(BREP_MSG_CALLBACK_FUNC f);


/* *********************** Contructors ***************************** */
/* creates an empty solid, client_data supplied */
extern BREP_SOLID *BrepCreateSolid(void *client_data);

/* creates a new empty shell within the solid if solid is not a NULL
 * pointer. You will need to call BrepCloseShell() yourself to
 * close the shell and/or BrepConnectShellToSolid() to connect it
 * to a solid if you don't specify a solid to contain the shell with
 * this function. */
extern BREP_SHELL *BrepCreateShell(BREP_SOLID *solid, void *client_data);

/* creates a new empty face within the shell if shell is not a NULL
 * pointer. */
extern BREP_FACE *BrepCreateFace(BREP_SHELL *shell, void *client_data);

/* creates a new empty contour within the face. 'face' cannot be a NULL
 * pointer. */
extern BREP_CONTOUR *BrepCreateContour(BREP_FACE *face, void *client_data);

/* creates a new vertex. The new vertex is not installed it in a vertex 
 * octree as vertices do not have to be sorted in an octree, see below. */
extern BREP_VERTEX *BrepCreateVertex(void *client_data);

/* Creates a wing into the contour from vertex1 to vertex2. The 
 * inside of the face bounded by the contour is supposed to be on the 
 * left side. The wing being created is supposed to be the new last
 * one in a contour, i.e. its starting vertex 'vertex1' must be the 
 * endvertex of the most recently created wing in the contour (if 
 * non-empty). It is the responsibility of the user to close the
 * contour, i.e., the last edge in a contour should connect to the 
 * first one. */
extern BREP_WING *BrepCreateWing(BREP_VERTEX *vertex1, BREP_VERTEX *vertex2, BREP_CONTOUR *contour, void *client_data);

/* performs various actions to be done when the boundary representation of
 * the solid has been completely specified. Automatically calls 
 * BrepCloseShell() for its contained shells and so on ... */
extern void BrepCloseSolid(BREP_SOLID *solid);

/* The following functions are only needed when creating "orphan"
 * shells and faces (= without specifying the parent solid/shell
 * when creating them). */

/* same for a shell. Only needed for shells that were created without
 * specifying the enclosing solid. */
extern void BrepCloseShell(BREP_SHELL *shell);

/* same for a face. Note that contours and wings/edges cannot be created
 * without a containing face, ... */
extern void BrepCloseFace(BREP_FACE *face);

/* connects the shell to the solid */
extern void BrepConnectShellToSolid(BREP_SHELL *shell, BREP_SOLID *solid);

/* disconnect the shell from the solid */
extern void BrepDisconnectShellFromSolid(BREP_SHELL *shell);

/* connects the face to the shell */
extern void BrepConnectFaceToShell(BREP_FACE *face, BREP_SHELL *shell);

/* disconnect the face from its containing shell */
extern void BrepDisconnectFaceFromShell(BREP_FACE *face);


/* ************************ Modifiers ******************************* */

/* Splits an edge in two at the specified vertex (at least: 
 * topologically; the new vertex doesn't have to be collinear
 * with the endpoints of the edge to be split, but you should make
 * sure that no contours are created that intersect in other
 * places than at vertices and along edges. The contours
 * to which the edge belongs are assumed to be closed loops. */
extern void BrepSplitEdge(BREP_EDGE *edge, BREP_VERTEX *vertex);

/* Splits only one wing. If a full edge is to be split, also its
 * wing in the other contour (if any) needs to be split at the same vertex.
 * (BrepSplitEdge does this).
 * Returns the wing leaving at the inserted vertex. */
extern BREP_WING *BrepSplitWing(BREP_WING *wing, BREP_VERTEX *vertex);

/* Join two edges at their common endpoint. The edges must be used
 * in the same contours and must share an endpoint. */
extern void BrepJoinEdges(BREP_EDGE *edge1, BREP_EDGE *edge2);

/* Joins two wings at there common endpoint. The wings are supposed to 
 * be consecutive wings, i.e. wing1->next = wing2 (and wing2->prev = wing1)
 * in a closed contour. The common vertex is wing2->vertex,
 * the start vertex of the second wing (which is supposed to be
 * the endpoint of the first wing as well). Returns the newly
 * created wing. */
extern BREP_WING *BrepJoinWings(BREP_WING *wing1, BREP_WING *wing2);

/* wing1 and wing2 should be two wings belonging to the same contour.
 * This routine creates a new edge connecting the start vertex of wing1 
 * and wing2, splitting the contour in two. A pointer to the newly created 
 * wing, connecting the start vertex of wing1 to the start vertex of wing2, 
 * is returned. */
extern BREP_WING *BrepMakeEdgeSplitContour(BREP_WING *wing1, BREP_WING *wing2,
					   void *edge_data, void *contour_data);

/* Wing1 and wing2 are two wings belonging to a different contour. This
 * routine creates a new edge connecting the starting vertices of 
 * wing1 and wing2 and merges to two contours to one. A pointer to
 * the newly created wing, connecting the start vertex of wing1 to the
 * start vertex of wing2, is returned. */
extern BREP_WING *BrepMakeEdgeJoinContours(BREP_WING *wing1, BREP_WING *wing2, 
					   void *edge_data);

/* wing is a wing of an edge that is used in two different contours. This 
 * routine deletes the edge to which the wing belongs, inserting the reaminder
 * of the "other" contour sharing the edge into the contour to which the wing 
 * belongs. The other contour is destroyed and the first is "closed" again 
 * in order to notify that it changed. Returns the wing from the first contour 
 * that comes before the first wing moved from the second to the first, or
 * NULL if the first contour was a selfloop. In that case, the empty contour 
 * is deleted. In case of errors, wing is returned. Warning: if the face to which
 * the other contour belongs, contains holes, these holes should probably be moved
 * to the face to which 'wing' belongs.   */
extern BREP_WING *BrepDeleteEdgeJoinContours(BREP_WING *wing);

/* 'wing' is a wing of an edge that is used two times (in opposite direction) 
 * in the same contour, i.o.w. a seam. This routine deletes this edge.
 * If the wings happen to be consequtive wings, the wings are just deleted.
 * If these are the only two wings in the contour, the contour is deleted as 
 * well and a NULL wing pointer is returned. If they are not consequtive, the 
 * contour is split in two contours. The wing before 'wing' will remain in 
 * the original contour and will be returned. */
extern BREP_WING *BrepDeleteEdgeSplitContour(BREP_WING *wing, void *contour_data);

/* Creates a notch, connecting the start vertex of the wing with
 * the specified vertex, ans inserts it into the contour to
 * which the wing belongs. A pointer to the newly created
 * wing, from the start vertex of the specified wing to the
 * specified vertex, is returned. */
extern BREP_WING *BrepMakeNotch(BREP_WING *wing, BREP_VERTEX *vertex, 
				void *edge_data);

/* Creates a slit, connecting the two specified vertices, 
 * in the given face. A slit is a new contour containing
 * two wings: one from v1 to v2 and the second
 * from v2 back to v1. A pointer to the newly created
 * wing, connecting v1 to v2, is returned. */
extern BREP_WING *BrepMakeSlit(BREP_FACE *face, BREP_VERTEX *v1, BREP_VERTEX *v2,
			       void *edge_data, void *contour_data);

/* Replace the starting vertex of 'wing' by 'newvertex'. Assumes
 * that 'wing' is correctly connected in a contour and it is not
 * the only wing (that means: the contour is not a selfloop).
 * Returns a pointer to the new wing, which is leaving at 'newvertex'. */
extern BREP_WING *BrepWingReplaceVertex(BREP_WING *wing, BREP_VERTEX *newvertex);


/* ******************** Selectors and Iterators ************************* */
/* adding and removing elements in the ring being iterated over is restricted
 * to certain conditions: the first element being iterated over must remain 
 * in the ring and the next element of an element being passed must remain
 * the same as well. */

/* iterate over the shells in the solid: 1A = 1 extra argument, passed after the 
 * BREP_SHELL *, 2A = two extra arguments, passed in order after the BREP_SHELL * */
extern void BrepSolidIterateShells(BREP_SOLID *solid, void (*func)(BREP_SHELL *));
extern void BrepSolidIterateShells1A(BREP_SOLID *solid, void (*func)(BREP_SHELL *, void *), void *parm);
extern void BrepSolidIterateShells2A(BREP_SOLID *solid, void (*func)(BREP_SHELL *, void *, void *), void *parm1, void *parm2);

/* execute func for every face in the shell */
extern void BrepShellIterateFaces(BREP_SHELL *shell, void (*func)(BREP_FACE *));
extern void BrepShellIterateFaces1A(BREP_SHELL *shell, void (*func)(BREP_FACE *, void *), void *parm);
extern void BrepShellIterateFaces2A(BREP_SHELL *shell, void (*func)(BREP_FACE *, void *, void *), void *parm1, void *parm2);

/* iterate over the contours of the face */
extern void BrepFaceIterateContours(BREP_FACE *face, void (*func)(BREP_CONTOUR *));
extern void BrepFaceIterateContours1A(BREP_FACE *face, void (*func)(BREP_CONTOUR *, void *), void *parm);
extern void BrepFaceIterateContours2A(BREP_FACE *face, void (*func)(BREP_CONTOUR *, void *, void *), void *parm1, void *parm2);

/* Iterate over the wings in the contour. When properly built, the inside of 
 * the face containing the contour is always on the left side of an edge. */
extern void BrepContourIterateWings(BREP_CONTOUR *contour, void (*func)(BREP_WING *));
extern void BrepContourIterateWings1A(BREP_CONTOUR *contour, void (*func)(BREP_WING *, void *), void *parm);
extern void BrepContourIterateWings2A(BREP_CONTOUR *contour, void (*func)(BREP_WING *, void *, void *), void *parm1, void *parm2);

/* Iterates over the vertices in a contour. Same order as when iterating 
 * over the edges. */
extern void BrepContourIterateVertices(BREP_CONTOUR *contour, void (*func)(BREP_VERTEX *));
extern void BrepContourIterateVertices1A(BREP_CONTOUR *contour, void (*func)(BREP_VERTEX *, void *), void *parm);

/* Iterate over the wings leaving the vertex, in arbitrary order. */
extern void BrepVertexIterateWings(BREP_VERTEX *vertex, void (*func)(BREP_WING *));
extern void BrepVertexIterateWings1A(BREP_VERTEX *vertex, void (*func)(BREP_WING *, void *), void *parm);

/* Iterator over all wings (included in a contour) connecting the two 
 * given vertices. */
extern void BrepIterateWingsWithVertex(BREP_VERTEX *vertex1, BREP_VERTEX *vertex2, 
				       void (*func)(BREP_WING *));

extern void BrepIterateWingsWithVertex1A(BREP_VERTEX *vertex1, BREP_VERTEX *vertex2, 
					 void (*func)(BREP_WING *, void *parm), 
					 void *parm);

/* You might prefer the following, more flexibale iterators however ... */
#define ForAllInRing(TYPE, elem, first, nextel) \
  TYPE *elem, *nextel; \
  for (elem=(first), nextel=elem->next; elem; elem = nextel==(first) ? (TYPE *)NULL : nextel, nextel=nextel->next)

#define ForAllShellsInSolid(shell, solid) { \
  if ((solid) && (solid)->shells) { \
    ForAllInRing(BREP_SHELL, shell, (solid)->shells, next_shell) {

#define ForAllFacesInShell(face, shell) { \
  if ((shell) && (shell)->faces) { \
    ForAllInRing(BREP_FACE, face, (shell)->faces, next_face) {

#define ForAllContoursInFace(contour, face) { \
  if ((face) && (face)->outer_contour) { \
    ForAllInRing(BREP_CONTOUR, contour, (face)->outer_contour, next_contour) {

#define ForAllWingsInContour(wing, contour) { \
  if ((contour) && (contour)->wings) { \
    ForAllInRing(BREP_WING, wing, (contour)->wings, next_wing) {

#define ForAllWingsLeavingVertex(_wing, vertex) { \
  if ((vertex) && (vertex)->wing_ring) { \
    ForAllInRing(BREP_WING_RING, _r_, (vertex)->wing_ring, next_wingel) { \
      BREP_WING *_wing = _r_->wing;

#ifndef EndForAll
#define EndForAll }}}
#endif

/* returns the other wing in the edge */
extern BREP_WING *BrepEdgeOtherWing(BREP_WING *wing);

/* returns the next wing with same starting vertex as wing. The order is 
 * counterclockwise if the vertex is used in outer contours only and 
 * clockwise if used in inner contours only. Returns a null pointer
 * if the current wing is not properly connected to possible
 * other wings sharing the vertex, or the boundary of a partial
 * shell was reached. */
extern BREP_WING *BrepNextWingLeavingVertex(BREP_WING *wing);

/* looks whether the wing is referenced in the wing ring of its
 * starting vertex. Returns a pointer to the BREP_WING_RING element if
 * it is found and NULL if not */
extern BREP_WING_RING *BrepFindWingLeavingVertex(BREP_WING *wing);

/* Looks whether an edge connecting the two vertices already
 * exists, Returns it if it exists. Returns NULL if not. */
extern BREP_EDGE *BrepFindEdge(BREP_VERTEX *vertex1, BREP_VERTEX *vertex2);


/* ************************ Destructors **************************** */
/* releases all memory associated with the solid, also its vertices if not used
 * in other solids as well. */
extern void BrepDestroySolid(BREP_SOLID *solid);

/* release all memory associated to a shell and its contained faces */
extern void BrepDestroyShell(BREP_SHELL *shell);

/* release all storage associated with a face and its contours, including
 * edges if not used in other faces as well */
extern void BrepDestroyFace(BREP_FACE *face);

/* release all storage associated with a contour and its wing/edges
 * if not used in other contours as well */
extern void BrepDestroyContour(BREP_CONTOUR *contour);

/* remove a wing from a contour, release the storage associated with the
 * edge if it is not used in other contours as well. This routine will 
 * in general create a hole in a contour: the endpoint of a previous edge
 * might not be the starting point of the next one where an edge has been
 * deleted. The vertices are not deleted. */
extern void BrepDestroyWing(BREP_WING *wing);

/* Remove a vertex from a (closed) contour, the wings containing the vertex are
 * removed as well (and their edges if not used in other contours as
 * well). If it is not the only vertex in the contour, a new wing connecting
 * the neighbooring vertices is created, so the contour remains
 * a loop. The vertex is not deleted. */
extern void BrepContourRemoveVertex(BREP_CONTOUR *contour, BREP_VERTEX *vertex);

/* release all storage associated with the vertex if it is not used 
 * anymore in any edge. */
extern void BrepDestroyVertex(BREP_VERTEX *vertex);


/* ********************** vertex octrees *************************** */
/* vertices can also be sorted and stored into an octree in order to make 
 * searching for a vertex significantly faster. */
/* this struct must have the same layout as OCTREE in Octree.h */
typedef struct BREP_VERTEX_OCTREE {
  BREP_VERTEX *vertex;
  struct BREP_VERTEX_OCTREE *child[8];
} BREP_VERTEX_OCTREE;

/* Before trying to store vertices in an octree, first a routine should
 * be speciied to compare the client data of two vertices.
 * The routine specified should return a code with the following meaning:
 *
 * 	0:  x1 <= x2 , y1 <= y2, z1 <= z2 but not all are equal
 * 	1:  x1 >  x2 , y1 <= y2, z1 <= z2 
 * 	2:  x1 <= x2 , y1 >  y2, z1 <= z2 
 * 	3:  x1 >  x2 , y1 >  y2, z1 <= z2 
 * 	4:  x1 <= x2 , y1 <= y2, z1 >  z2 
 * 	5:  x1 >  x2 , y1 <= y2, z1 >  z2 
 * 	6:  x1 <= x2 , y1 >  y2, z1 >  z2 
 * 	7:  x1 >  x2 , y1 >  y2, z1 >  z2 
 * 	8:  x1 == x2 , y1 == y2, z1 == z2 
 *
 * in other words: 
 *
 *	code&1 == 1 if x1 > x2 and 0 otherwise
 *	code&2 == 1 if y1 > y2 and 0 otherwise
 *	code&4 == 1 if z1 > z2 and 0 otherwise
 *	code&8 == 1 if x1 == x2 and y1 == y2 and z1 == z2
 *
 * BrepSetVertexCompareRoutine() returns the previously installed compare 
 * routine so it can be restored when necessary. */
typedef int (*BREP_COMPARE_FUNC)(void *, void *);

extern BREP_COMPARE_FUNC BrepSetVertexCompareRoutine(BREP_COMPARE_FUNC routine);

/* Set a routine to compare only the the location of two BREP_VERTEXes. There
 * may be multiple vertices at the same location, e.g. having a different
 * normal and/or name. These vertices are considered different vertices
 * by the vertex compare routine which is set with BrepSetVertexCompareRoutine(),
 * but they are considered the same vertices by the routine which is set with
 * BrepSetVertexCompareLocationRoutine(). The previously installed compare 
 * routine is returned, so it can be restored when necessary. This compare
 * routine is used by BrepFindVertexAtLocation(), BrepIterateVerticesAtLocation(),
 * BrepIterateWingsBetweenLocations() ... */
extern BREP_COMPARE_FUNC BrepSetVertexCompareLocationRoutine(BREP_COMPARE_FUNC routine);

/* Looks up a vertex in the vertex octree, return NULL if not found */
extern BREP_VERTEX *BrepFindVertex(void *vertex_data, BREP_VERTEX_OCTREE *vertices);

/* attaches a  BREP_VERTEX to the vertex octree */
extern void BrepAttachVertex(BREP_VERTEX *vertex, BREP_VERTEX_OCTREE **vertices);

/* removes a BREP_VERTEX from the vertex octree */
extern void BrepReleaseVertex(BREP_VERTEX *vertex, BREP_VERTEX_OCTREE **vertices);

/* Creates a vertex and installs it in the vertex octree, same as
 * BrepCreateVertex() followed by BrepAttachVertex() */
extern BREP_VERTEX *BrepInstallVertex(void *vertex_data, BREP_VERTEX_OCTREE **vertices);

/* calls func for each BREP_VERTEX in the octree */
extern void BrepIterateVertices(BREP_VERTEX_OCTREE *vertices, void (*func)(BREP_VERTEX *));

/* For convenience, a vertex octree is created with each BREP_SOLID.
 * The vertex octree bound to a BREP_SOLID is also destroyed when
 * destroying the BREP_SOLID. 
 * The routines below allow to create and destroy vertex octrees not
 * bound to a solid. */

/* creates a new vertex octree: currently only returns a NULL pointer */
extern BREP_VERTEX_OCTREE *BrepCreateVertexOctree(void);

/* Destroys a vertex octree, does not destroy the vertices referenced in
 * the octree. */
extern void BrepDestroyVertexOctree(BREP_VERTEX_OCTREE *vertices);

/* destroys all the vertices and the vertex octree, same as
 * BrepIterateVertices(vertices, BrepDestroyVertex) followed by
 * BrepDestroyvertexOctree(). */
extern void BrepDestroyVertices(BREP_VERTEX_OCTREE *vertices);

/* Looks up the first vertex in the vertex octree at the location as specified in the 
 * given vertex data. There may be multiple vertices at the same location (e.g. having 
 * a different normal and/or a different name). These vertices should normally be
 * stored as a suboctree of the octree containing all vertices. A pointer to the
 * top of this suboctree is returned if there are vertices at the given location.
 * NULL is returned if there are no vertices at the given location. */
extern BREP_VERTEX_OCTREE *BrepFindVertexAtLocation(void *vertex_data, BREP_VERTEX_OCTREE *vertices);

/* Iterators over all vertices in the given vertex octree that are at the same
 * location as specified in the vertex data. */
extern void BrepIterateVerticesAtLocation(void *vertex_data, BREP_VERTEX_OCTREE *vertices,
					  void (*routine)(BREP_VERTEX *vertex));

/* 1 extra parameter */
extern void BrepIterateVerticesAtLocation1A(void *vertex_data, BREP_VERTEX_OCTREE *vertices,
					    void (*routine)(BREP_VERTEX *vertex, void *parm), 
					    void *parm);

/* 2 extra parameters */
extern void BrepIterateVerticesAtLocation2A(void *vertex_data, BREP_VERTEX_OCTREE *vertices,
					    void (*routine)(BREP_VERTEX *vertex, void *parm1, void *parm2),
					    void *parm1, void *parm2);

/* Iterator over all edge-wings between vertices at the locations specified by 
 * v1data and v2data. */
extern void BrepIterateWingsBetweenLocations(void *v1data, void *v2data,
					     BREP_VERTEX_OCTREE *vertices,
					     void (*func)(BREP_WING *));

/* Iterator over all edge-wings between vertices at the locations specified by 
 * v1data and v2data. */
extern void BrepIterateWingsBetweenLocations1A(void *v1data, void *v2data,
					       BREP_VERTEX_OCTREE *vertices,
					       void (*func)(BREP_WING *),
					       void *parm);

#ifdef __cplusplus
}
#endif

#endif /* _BREP_H_ */
