/* vertex.c: routines for manipulating BREP_VERTEXes */ #include "brep.h" #include "private.h" #include "pools.h" #ifndef NOPOOLS static POOL *vertexPool = (POOL *)NULL; #define NEWVERTEX() (BREP_VERTEX *)NewPoolCell(sizeof(BREP_VERTEX), 0, "brep vertices", &vertexPool) #define DISPOSEVERTEX(ptr) Dispose((unsigned char *)(ptr), &vertexPool) static POOL *ringelPool = (POOL *)NULL; #define NEWRINGEL() (BREP_WING_RING *)NewPoolCell(sizeof(BREP_WING_RING), 0, "brep vertex wing rings", &ringelPool) #define DISPOSERINGEL(ptr) Dispose((unsigned char *)(ptr), &ringelPool) #else /* NOPOOLS */ #define NEWVERTEX() (BREP_VERTEX *)Alloc(sizeof(BREP_VERTEX)) #define DISPOSEVERTEX(ptr) Free((char *)ptr, sizeof(BREP_VERTEX)) #define NEWRINGEL() (BREP_WING_RING *)Alloc(sizeof(BREP_WING_RING)) #define DISPOSERINGEL(ptr) Free((char *)ptr, sizeof(BREP_WING_RING)) #endif /* NOPOOLS */ /* callback functions for manipulating BREP_VERTEXs. */ static BREP_CALLBACK_FUNC brep_create_vertex_callback = (BREP_CALLBACK_FUNC)NULL, brep_close_vertex_callback = (BREP_CALLBACK_FUNC)NULL, brep_destroy_vertex_callback = (BREP_CALLBACK_FUNC)NULL; /* set the CreateVertex callback routine */ BREP_CALLBACK_FUNC BrepSetCreateVertexCallback(BREP_CALLBACK_FUNC func) { BREP_CALLBACK_FUNC oldfunc = brep_create_vertex_callback; brep_create_vertex_callback = func; return oldfunc; } /* set the CloseVertex callback routine */ BREP_CALLBACK_FUNC BrepSetCloseVertexCallback(BREP_CALLBACK_FUNC func) { BREP_CALLBACK_FUNC oldfunc = brep_close_vertex_callback; brep_close_vertex_callback = func; return oldfunc; } /* set the DestroyVertex callback routine */ BREP_CALLBACK_FUNC BrepSetDestroyVertexCallback(BREP_CALLBACK_FUNC func) { BREP_CALLBACK_FUNC oldfunc = brep_destroy_vertex_callback; brep_destroy_vertex_callback = func; return oldfunc; } /* creates a new vertex - no edges in which the vertex is used are specified, * this is done when creating an edge. */ BREP_VERTEX *BrepCreateVertex(void *client_data) { BREP_VERTEX *vertex; vertex = NEWVERTEX(); vertex->wing_ring = (BREP_WING_RING *)NULL; vertex->client_data = client_data; if (brep_create_vertex_callback) vertex->client_data = brep_create_vertex_callback(vertex); /* a vertex is completely specified by its 3D coordinates */ if (brep_close_vertex_callback) vertex->client_data = brep_close_vertex_callback(vertex); return vertex; } /* connect the wing ring element 'ringel' to the wing ring of the vertex */ static void BrepConnectWingRingToVertex(BREP_WING_RING *ringel, BREP_VERTEX *vertex) { if (!vertex->wing_ring) { /* first wing in contour */ ringel->next = ringel->prev = ringel; vertex->wing_ring = ringel; } else { /* not first wing */ ringel->next = vertex->wing_ring; ringel->prev = vertex->wing_ring->prev; ringel->next->prev = ringel->prev->next = ringel; } } /* Connect the wing to its starting vertex. The wing must have been connected to its * contour before. */ void BrepConnectWingToVertex(BREP_WING *wing) { BREP_VERTEX *vertex = wing->vertex; BREP_WING_RING *ringel; ringel = NEWRINGEL(); ringel->wing = wing; BrepConnectWingRingToVertex(ringel, vertex); } /* 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 */ BREP_WING_RING *BrepFindWingLeavingVertex(BREP_WING *wing) { BREP_VERTEX *vertex = wing->vertex; BREP_WING_RING *ringel, *next; if (vertex->wing_ring) { next = vertex->wing_ring; do { ringel = next; next = ringel->next; if (ringel->wing == wing) return ringel; } while (next && next != vertex->wing_ring); } return (BREP_WING_RING *)NULL; } /* disconnect the wing ring element from the wing ring it belongs to */ static void BrepDisconnectWingRingFromVertex(BREP_WING_RING *ringel) { BREP_VERTEX *vertex = ringel->wing->vertex; if (vertex->wing_ring == ringel) { if (ringel->next == ringel) /* it's the only wing leaving the * vertex */ vertex->wing_ring = (BREP_WING_RING *)NULL; else vertex->wing_ring = ringel->next; } ringel->next->prev = ringel->prev; ringel->prev->next = ringel->next; } /* Disconnect the wing from its starting vertex. The wing must be properly connected to * a contour. */ void BrepDisconnectWingFromVertex(BREP_WING *wing) { BREP_WING_RING *ringel; /* find the wing in the wing ring */ ringel = BrepFindWingLeavingVertex(wing); if (!ringel) { BrepError(wing->edge->client_data, "BrepDisconnectWingFromVertex", "wing not connected to the vertex"); return; } /* disconnect the wing ring element from the vertex */ BrepDisconnectWingRingFromVertex(ringel); /* dispose the wing ring element */ DISPOSERINGEL(ringel); } /* Looks whether an edge connecting the two vertices already * exists, Returns it if it exists. Returns NULL if not. */ BREP_EDGE *BrepFindEdge(BREP_VERTEX *vertex1, BREP_VERTEX *vertex2) { BREP_WING_RING *ringel, *next; /* there is an edge if there is a wing from vertex2 to vertex1 ... */ if (vertex2->wing_ring) { next = vertex2->wing_ring; do { ringel = next; next = ringel->next; if (BrepEdgeOtherWing(ringel->wing)->vertex == vertex1) return ringel->wing->edge; } while (next && next != vertex2->wing_ring); } /* ... or from vertex1 to vertex2 */ if (vertex1->wing_ring) { next = vertex1->wing_ring; do { ringel = next; next = ringel->next; if (BrepEdgeOtherWing(ringel->wing)->vertex == vertex2) return ringel->wing->edge; } while (next && next != vertex1->wing_ring); } /* no edge connecting the two vertices was found */ return (BREP_EDGE *)NULL; } /* Iterator over all wings (included in a contour) connecting the two * given vertices */ void BrepIterateWingsWithVertex(BREP_VERTEX *vertex1, BREP_VERTEX *vertex2, void (*func)(BREP_WING *)) { BREP_WING_RING *ringel, *next; if (vertex2->wing_ring) { next = vertex2->wing_ring; do { ringel = next; next = ringel->next; if (ringel->wing->contour && ringel->wing->next->vertex == vertex1) func(ringel->wing); } while (next && next != vertex2->wing_ring); } if (vertex1->wing_ring) { next = vertex1->wing_ring; do { ringel = next; next = ringel->next; if (ringel->wing->contour && ringel->wing->next->vertex == vertex2) func(ringel->wing); } while (next && next != vertex1->wing_ring); } } /* Iterator over all wings (included in a contour) connecting the two * given vertices */ void BrepIterateWingsWithVertex1A(BREP_VERTEX *vertex1, BREP_VERTEX *vertex2, void (*func)(BREP_WING *, void *parm), void *parm) { BREP_WING_RING *ringel, *next; if (vertex2->wing_ring) { next = vertex2->wing_ring; do { ringel = next; next = ringel->next; if (ringel->wing->contour && ringel->wing->next->vertex == vertex1) func(ringel->wing, parm); } while (next && next != vertex2->wing_ring); } if (vertex1->wing_ring) { next = vertex1->wing_ring; do { ringel = next; next = ringel->next; if (ringel->wing->contour && ringel->wing->next->vertex == vertex2) func(ringel->wing, parm); } while (next && next != vertex1->wing_ring); } } /* 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. */ BREP_WING *BrepNextWingLeavingVertex(BREP_WING *wing) { BREP_WING *next_wing; if (!wing->prev) return (BREP_WING *)NULL; next_wing = BrepEdgeOtherWing(wing->prev); if (next_wing->contour) return next_wing; else return (BREP_WING *)NULL; } /* iterate over the wings leaving at the vertex, in arbitrary order. */ static void do_ringel_wing(BREP_WING_RING *ringel, void (*func)(BREP_WING *)) { func(ringel->wing); } void BrepVertexIterateWings(BREP_VERTEX *vertex, void (*func)(BREP_WING *)) { BrepIterate1A((BREP_RING *)vertex->wing_ring, (void (*)(BREP_RING *, void *))do_ringel_wing, (void *)func); } #ifdef NEVER static void do_ringel_wing_parm(BREP_WING_RING *ringel, void (*func)(BREP_WING *, void *), void *parm) { func(ringel->wing, parm); } #endif void BrepVertexIterateWings1A(BREP_VERTEX *vertex, void (*func)(BREP_WING *, void *), void *parm) { BrepIterate2A((BREP_RING *)vertex->wing_ring, (void (*)(BREP_RING *, void *, void *))do_ringel_wing, (void *)func, parm); } /* release all storage associated with the vertex. The vertex is supposed not * to be used anymore in any edge. Disconnecting vertices and edges happens * automatically when destroying edges. */ void BrepDestroyVertex(BREP_VERTEX *vertex) { /* check whether the vertex is still being used in edges, if so, refuse to * destroy the vertex */ if (vertex->wing_ring) { BrepInfo(vertex->client_data, "BrepDestroyVertex", "vertex still being used in edges, will not be destroyed"); return; } /* notify the user that the vertex is being destroyed */ if (brep_destroy_vertex_callback) brep_destroy_vertex_callback(vertex); /* dispose of the BREP_VERTEX structure itself */ DISPOSEVERTEX(vertex); } /* moves the wing ring element 'ringel' to the wing ring of the * vertex 'newvertex' */ void BrepMoveWingRingToVertex(BREP_WING_RING *ringel, BREP_VERTEX *newvertex) { /* disconnect the wing ring element from its vertex */ BrepDisconnectWingRingFromVertex(ringel); /* connect the wing ring element to the wing ring of the new vertex */ BrepConnectWingRingToVertex(ringel, newvertex); }