From 6974c39e51ddc7246b29527c3d849d501f3961f7 Mon Sep 17 00:00:00 2001 From: mew Date: Sun, 18 Nov 2018 01:22:43 +0800 Subject: [PATCH 1/3] Addd jcv_diagram_generate_vertices to generate a list of unique vertices of the edges and their corresponding edge. --- src/jc_voronoi.h | 148 ++++++++++++++++++++++++++++++++++++++++++++++- 1 file changed, 147 insertions(+), 1 deletion(-) diff --git a/src/jc_voronoi.h b/src/jc_voronoi.h index fb6172f..d678c02 100644 --- a/src/jc_voronoi.h +++ b/src/jc_voronoi.h @@ -221,6 +221,27 @@ typedef struct _jcv_edge jcv_real c; } jcv_edge; +typedef struct _jcv_vertex +{ + struct _jcv_vertex* next; + jcv_point pos; + struct _jcv_vertex_edge* edges; // The half edges owned by the vertex +} jcv_vertex; + +typedef struct _jcv_altered_edge +{ + struct _jcv_altered_edge* next; + jcv_site* sites[2]; + jcv_point pos[2]; + jcv_vertex* vertices[2]; +} jcv_altered_edge; + +typedef struct _jcv_vertex_edge { + struct _jcv_vertex_edge* next; + jcv_altered_edge* edge; + jcv_vertex* neighbor; +} jcv_vertex_edge; + typedef struct _jcv_rect { jcv_point min; @@ -256,9 +277,15 @@ extern void jcv_diagram_generate_useralloc( int num_points, const jcv_point* poi // Uses free (or the registered custom free function) extern void jcv_diagram_free( jcv_diagram* diagram ); +// generate the vertices and vertex_edges +extern void jcv_diagram_generate_vertices( jcv_diagram* diagram ); + // Returns an array of sites, where each index is the same as the original input point array. extern const jcv_site* jcv_diagram_get_sites( const jcv_diagram* diagram ); +// Returns a linked list of all the voronoi vertices +extern const jcv_vertex* jcv_diagram_get_vertices( const jcv_diagram* diagram ); + // Returns a linked list of all the voronoi edges // excluding the ones that lie on the borders of the bounding box. // For a full list of edges, you need to iterate over the sites, and their graph edges. @@ -368,6 +395,7 @@ typedef struct _jcv_context_internal int numsites_sqrt; int currentsite; int _padding; + jcv_vertex* vertices; jcv_memoryblock* memblocks; jcv_edge* edgepool; @@ -388,7 +416,12 @@ typedef struct _jcv_context_internal static const int JCV_DIRECTION_LEFT = 0; static const int JCV_DIRECTION_RIGHT = 1; static const jcv_real JCV_INVALID_VALUE = (jcv_real)-JCV_FLT_MAX; +static const int JCV_EDGE_SIZE = (sizeof(jcv_edge) > sizeof(jcv_altered_edge)) ? sizeof(jcv_edge) : sizeof(jcv_altered_edge); +static inline jcv_altered_edge* get_altered_edge( const jcv_graphedge* ge) +{ + return (jcv_altered_edge*)ge->edge; +} void jcv_diagram_free( jcv_diagram* d ) { @@ -410,6 +443,11 @@ const jcv_site* jcv_diagram_get_sites( const jcv_diagram* diagram ) return diagram->internal->sites; } +const jcv_vertex* jcv_diagram_get_vertices( const jcv_diagram* diagram ) +{ + return diagram->internal->vertices; +} + const jcv_edge* jcv_diagram_get_edges( const jcv_diagram* diagram ) { return diagram->internal->edges; @@ -444,7 +482,17 @@ static void* jcv_alloc(jcv_context_internal* internal, size_t size) static jcv_edge* jcv_alloc_edge(jcv_context_internal* internal) { - return (jcv_edge*)jcv_alloc(internal, sizeof(jcv_edge)); + return (jcv_edge*)jcv_alloc(internal, JCV_EDGE_SIZE); +} + +static jcv_vertex* jcv_alloc_vertex(jcv_context_internal* internal) +{ + return (jcv_vertex*)jcv_alloc(internal, sizeof(jcv_vertex)); +} + +static jcv_vertex_edge* jcv_alloc_vertex_edge(jcv_context_internal* internal) +{ + return (jcv_vertex_edge*)jcv_alloc(internal, sizeof(jcv_vertex_edge)); } static jcv_halfedge* jcv_alloc_halfedge(jcv_context_internal* internal) @@ -658,6 +706,18 @@ static jcv_edge* jcv_edge_new(jcv_context_internal* internal, jcv_site* s1, jcv_ return e; } +// jcv_vertex + +static jcv_vertex* jcv_vertex_new(jcv_context_internal* internal, const jcv_point* pos) +{ + jcv_vertex* e = jcv_alloc_vertex(internal); + e->pos = *pos; + e->edges = 0; + e->next = internal->vertices; + internal->vertices = e; + return e; +} + // jcv_halfedge @@ -1446,6 +1506,92 @@ void jcv_diagram_generate_useralloc( int num_points, const jcv_point* points, co jcv_fillgaps(d); } +static inline void jcv_create_vertex_edge(jcv_context_internal* internal, jcv_altered_edge* edge, jcv_vertex* vertex, jcv_vertex* neighbor) +{ + jcv_vertex_edge* vertex_edge = jcv_alloc_vertex_edge(internal); + vertex_edge->edge = edge; + vertex_edge->neighbor = neighbor; + vertex_edge->next = vertex->edges; + vertex->edges = vertex_edge; +} + +static inline void jcv_create_vertex_edges(jcv_context_internal* internal, const jcv_graphedge* ge, jcv_vertex* v1, jcv_vertex* v2) +{ + jcv_altered_edge* edge = get_altered_edge(ge); + jcv_create_vertex_edge(internal, edge, v1, v2); + jcv_create_vertex_edge(internal, edge, v2, v1); + edge->vertices[0] = v1; + edge->vertices[1] = v2; +} + +static inline jcv_vertex* jcv_get_or_create_vertex(jcv_context_internal* internal, jcv_vertex* last_vertex, const jcv_graphedge* current, const jcv_altered_edge* current_altered_edge, const jcv_altered_edge* next_altered_edge) { + jcv_vertex* vertex; + if( !current_altered_edge ) { + if( next_altered_edge) { + vertex = next_altered_edge->vertices[1]; + } else { + vertex = jcv_vertex_new(internal, ¤t->pos[1]); + } + jcv_create_vertex_edges(internal, current, last_vertex, vertex); + } else { + vertex = current_altered_edge->vertices[0]; + } + return vertex; +} + +void jcv_diagram_generate_vertices( jcv_diagram* d ) +{ + jcv_context_internal* internal = d->internal; + const jcv_site* sites = jcv_diagram_get_sites(d); + for( int i = 0; i < d->numsites; ++i ) + { + const jcv_site* site = &sites[i]; + const jcv_graphedge* first = site->edges; + const jcv_graphedge* current = first->next; + + jcv_vertex* start_vertex = 0; + const jcv_altered_edge* first_altered_edge = 0; + + if( first->neighbor && first->neighbor < site) { + first_altered_edge = get_altered_edge(first); + } + + jcv_vertex* last_vertex = 0; + const jcv_altered_edge* current_altered_edge = 0; + + if( current->neighbor && current->neighbor < site) { + current_altered_edge = get_altered_edge(current); + last_vertex = current_altered_edge->vertices[1]; + } else if( first_altered_edge ) { + last_vertex = first_altered_edge->vertices[0]; + } else { + last_vertex = jcv_vertex_new(internal, ¤t->pos[0]); + } + start_vertex = last_vertex; + + const jcv_graphedge* next = current->next; + + while( next ) { + const jcv_altered_edge* next_altered_edge = 0; + if( next->neighbor && next->neighbor < site) { + next_altered_edge = get_altered_edge(next); + } + jcv_vertex* vertex = jcv_get_or_create_vertex(internal, last_vertex, current, current_altered_edge, next_altered_edge); + last_vertex = vertex; + current_altered_edge = next_altered_edge; + current = next; + next = next->next; + } + + jcv_vertex* end_vertex = jcv_get_or_create_vertex(internal, last_vertex, current, current_altered_edge, first_altered_edge); + + //handle the head + if( !first_altered_edge ) { + jcv_create_vertex_edges(internal, first, end_vertex, start_vertex); + } + } +} + #endif // JC_VORONOI_IMPLEMENTATION From f8f0f170cd2ac4a33feef3314ed263b1e9926cc8 Mon Sep 17 00:00:00 2001 From: mew Date: Sun, 18 Nov 2018 02:22:57 +0800 Subject: [PATCH 2/3] guard duplicate vertex on a case which could happen on vertex with 4+ edge depending on site iteration order --- src/jc_voronoi.h | 50 +++++++++++++++++++++++++++++++++++++++++++++++- 1 file changed, 49 insertions(+), 1 deletion(-) diff --git a/src/jc_voronoi.h b/src/jc_voronoi.h index d678c02..6cd69f9 100644 --- a/src/jc_voronoi.h +++ b/src/jc_voronoi.h @@ -286,6 +286,9 @@ extern const jcv_site* jcv_diagram_get_sites( const jcv_diagram* diagram ); // Returns a linked list of all the voronoi vertices extern const jcv_vertex* jcv_diagram_get_vertices( const jcv_diagram* diagram ); +// Iterates over a list of vertices, skipping invalid vertices (where vertex has no edges) +extern const jcv_vertex* jcv_diagram_get_next_vertex( const jcv_vertex* vertex ); + // Returns a linked list of all the voronoi edges // excluding the ones that lie on the borders of the bounding box. // For a full list of edges, you need to iterate over the sites, and their graph edges. @@ -448,6 +451,15 @@ const jcv_vertex* jcv_diagram_get_vertices( const jcv_diagram* diagram ) return diagram->internal->vertices; } +const jcv_vertex* jcv_diagram_get_next_vertex( const jcv_vertex* vertex ) +{ + const jcv_vertex* v = vertex->next; + while (v != 0 && v->edges == 0) { + v = v->next; + } + return v; +} + const jcv_edge* jcv_diagram_get_edges( const jcv_diagram* diagram ) { return diagram->internal->edges; @@ -1524,10 +1536,37 @@ static inline void jcv_create_vertex_edges(jcv_context_internal* internal, const edge->vertices[1] = v2; } +static inline void jcv_merge_vertices(jcv_vertex* target, jcv_vertex* duplicate) { + jcv_vertex_edge* vertex_edge = duplicate->edges; + while( vertex_edge ) { + jcv_vertex* neighbor = vertex_edge->neighbor; + jcv_vertex_edge* temp = neighbor->edges; + while( temp ) { + if( temp->neighbor == duplicate ) { + temp->neighbor = target; + break; + } + temp = temp->next; + } + jcv_altered_edge* edge = vertex_edge->edge; + if( edge->vertices[0] == duplicate ) { + edge->vertices[0] = target; + } else { //edge->vertices[1] == duplicate + edge->vertices[1] = target; + } + if( !vertex_edge->next ) { + vertex_edge->next = target->edges; + } + vertex_edge = vertex_edge->next; + } + target->edges = duplicate->edges; + duplicate->edges = 0; +} + static inline jcv_vertex* jcv_get_or_create_vertex(jcv_context_internal* internal, jcv_vertex* last_vertex, const jcv_graphedge* current, const jcv_altered_edge* current_altered_edge, const jcv_altered_edge* next_altered_edge) { jcv_vertex* vertex; if( !current_altered_edge ) { - if( next_altered_edge) { + if( next_altered_edge ) { vertex = next_altered_edge->vertices[1]; } else { vertex = jcv_vertex_new(internal, ¤t->pos[1]); @@ -1535,6 +1574,15 @@ static inline jcv_vertex* jcv_get_or_create_vertex(jcv_context_internal* interna jcv_create_vertex_edges(internal, current, last_vertex, vertex); } else { vertex = current_altered_edge->vertices[0]; + if( next_altered_edge ) { + jcv_vertex* vertex2 = next_altered_edge->vertices[1]; + // check if the vertex is duplicated + // only possible to happen if the vertex has 4+ edges + // and depends on the site iteration order + if (vertex2 != vertex) { + jcv_merge_vertices(vertex, vertex2); + } + } } return vertex; } From 0efd411d2911bb40b2e1cc6022e24a400800a5c4 Mon Sep 17 00:00:00 2001 From: Derek Fung Date: Wed, 5 Dec 2018 12:19:55 +0800 Subject: [PATCH 3/3] fix dead loop in merge vertices --- src/jc_voronoi.h | 1 + 1 file changed, 1 insertion(+) diff --git a/src/jc_voronoi.h b/src/jc_voronoi.h index 6cd69f9..58f1089 100644 --- a/src/jc_voronoi.h +++ b/src/jc_voronoi.h @@ -1556,6 +1556,7 @@ static inline void jcv_merge_vertices(jcv_vertex* target, jcv_vertex* duplicate) } if( !vertex_edge->next ) { vertex_edge->next = target->edges; + break; } vertex_edge = vertex_edge->next; }