diff --git a/src/jc_voronoi.h b/src/jc_voronoi.h index 6ebad48..cc1666e 100644 --- a/src/jc_voronoi.h +++ b/src/jc_voronoi.h @@ -12,157 +12,159 @@ #include #ifdef __cplusplus -extern "C" { +extern "C" +{ #endif #ifndef JCV_REAL_TYPE - #define JCV_REAL_TYPE float +#define JCV_REAL_TYPE double #endif #ifndef JCV_REAL_TYPE_EPSILON - #define JCV_REAL_TYPE_EPSILON FLT_EPSILON +#define JCV_REAL_TYPE_EPSILON FLT_EPSILON #endif #ifndef JCV_ATAN2 - #define JCV_ATAN2(_Y_, _X_) atan2f(_Y_, _X_) +#define JCV_ATAN2(_Y_, _X_) atan2l(_Y_, _X_) #endif #ifndef JCV_SQRT - #define JCV_SQRT(_X_) sqrtf(_X_) +#define JCV_SQRT(_X_) sqrtl(_X_) #endif #ifndef JCV_PI - #define JCV_PI 3.14159265358979323846264338327950288f +#define JCV_PI 3.14159265358979323846264338327950288 #endif #ifndef JCV_FLT_MAX - #define JCV_FLT_MAX 3.402823466e+38F +#define JCV_FLT_MAX 3.402823466e+38 #endif -#ifndef JCV_EDGE_INTERSECT_THRESHOLD - // Fix for Issue #40 - #define JCV_EDGE_INTERSECT_THRESHOLD 1.0e-10F +#ifndef JCV_FLT_EPSILON +#define JCV_FLT_EPSILON 1.0e-15 #endif -typedef JCV_REAL_TYPE jcv_real; - -typedef struct _jcv_point jcv_point; -typedef struct _jcv_rect jcv_rect; -typedef struct _jcv_site jcv_site; -typedef struct _jcv_edge jcv_edge; -typedef struct _jcv_graphedge jcv_graphedge; -typedef struct _jcv_diagram jcv_diagram; -typedef struct _jcv_clipper jcv_clipper; -typedef struct _jcv_context_internal jcv_context_internal; - -/// Tests if a point is inside the final shape -typedef int (*jcv_clip_test_point_fn)(const jcv_clipper* clipper, const jcv_point p); -/** Given an edge, and the clipper, calculates the e->pos[0] and e->pos[1] - * Returns 0 if not successful - */ -typedef int (*jcv_clip_edge_fn)(const jcv_clipper* clipper, jcv_edge* e); -/** Given the clipper, the site and the last edge, - * closes any gaps in the polygon by adding new edges that follow the bounding shape - * The internal context is use when allocating new edges. - */ -typedef void (*jcv_clip_fillgap_fn)(const jcv_clipper* clipper, jcv_context_internal* allocator, jcv_site* s); - - - -/** - * Uses malloc - * If a clipper is not supplied, a default box clipper will be used - * If rect is null, an automatic bounding box is calculated, with an extra padding of 10 units - * All points will be culled against the bounding rect, and all edges will be clipped against it. - */ -extern void jcv_diagram_generate( int num_points, const jcv_point* points, const jcv_rect* rect, const jcv_clipper* clipper, jcv_diagram* diagram ); - -typedef void* (*FJCVAllocFn)(void* userctx, size_t size); -typedef void (*FJCVFreeFn)(void* userctx, void* p); - -// Same as above, but allows the client to use a custom allocator -extern void jcv_diagram_generate_useralloc( int num_points, const jcv_point* points, const jcv_rect* rect, const jcv_clipper* clipper, void* userallocctx, FJCVAllocFn allocfn, FJCVFreeFn freefn, jcv_diagram* diagram ); - -// Uses free (or the registered custom free function) -extern void jcv_diagram_free( 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 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. -extern const jcv_edge* jcv_diagram_get_edges( const jcv_diagram* diagram ); - -// Iterates over a list of edges, skipping invalid edges (where p0==p1) -extern const jcv_edge* jcv_diagram_get_next_edge( const jcv_edge* edge ); - -// For the default clipper -extern int jcv_boxshape_test(const jcv_clipper* clipper, const jcv_point p); -extern int jcv_boxshape_clip(const jcv_clipper* clipper, jcv_edge* e); -extern void jcv_boxshape_fillgaps(const jcv_clipper* clipper, jcv_context_internal* allocator, jcv_site* s); +#ifndef JCV_EDGE_INTERSECT_THRESHOLD +// Fix for Issue #40 +#define JCV_EDGE_INTERSECT_THRESHOLD 1.0e-10F +#endif + typedef JCV_REAL_TYPE jcv_real; + + typedef struct _jcv_point jcv_point; + typedef struct _jcv_rect jcv_rect; + typedef struct _jcv_site jcv_site; + typedef struct _jcv_edge jcv_edge; + typedef struct _jcv_graphedge jcv_graphedge; + typedef struct _jcv_diagram jcv_diagram; + typedef struct _jcv_clipper jcv_clipper; + typedef struct _jcv_context_internal jcv_context_internal; + + /// Tests if a point is inside the final shape + typedef int (*jcv_clip_test_point_fn)(const jcv_clipper *clipper, const jcv_point p); + /** Given an edge, and the clipper, calculates the e->pos[0] and e->pos[1] + * Returns 0 if not successful + */ + typedef int (*jcv_clip_edge_fn)(const jcv_clipper *clipper, jcv_edge *e); + /** Given the clipper, the site and the last edge, + * closes any gaps in the polygon by adding new edges that follow the bounding shape + * The internal context is use when allocating new edges. + */ + typedef void (*jcv_clip_fillgap_fn)(const jcv_clipper *clipper, jcv_context_internal *allocator, jcv_site *s); + + /** + * Uses malloc + * If a clipper is not supplied, a default box clipper will be used + * If rect is null, an automatic bounding box is calculated, with an extra padding of 10 units + * All points will be culled against the bounding rect, and all edges will be clipped against it. + */ + extern void jcv_diagram_generate(int num_points, const jcv_point *points, const jcv_rect *rect, const jcv_clipper *clipper, jcv_diagram *diagram); + + typedef void *(*FJCVAllocFn)(void *userctx, size_t size); + typedef void (*FJCVFreeFn)(void *userctx, void *p); + + // Same as above, but allows the client to use a custom allocator + extern void jcv_diagram_generate_useralloc(int num_points, const jcv_point *points, const jcv_rect *rect, const jcv_clipper *clipper, void *userallocctx, FJCVAllocFn allocfn, FJCVFreeFn freefn, jcv_diagram *diagram); + + // Uses free (or the registered custom free function) + extern void jcv_diagram_free(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 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. + extern const jcv_edge *jcv_diagram_get_edges(const jcv_diagram *diagram); + + // Iterates over a list of edges, skipping invalid edges (where p0==p1) + extern const jcv_edge *jcv_diagram_get_next_edge(const jcv_edge *edge); + + // For the default clipper + extern int jcv_boxshape_test(const jcv_clipper *clipper, const jcv_point p); + extern int jcv_boxshape_clip(const jcv_clipper *clipper, jcv_edge *e); + extern void jcv_boxshape_fillgaps(const jcv_clipper *clipper, jcv_context_internal *allocator, jcv_site *s); #pragma pack(push, 1) -struct _jcv_point -{ - jcv_real x; - jcv_real y; -}; + struct _jcv_point + { + jcv_real x; + jcv_real y; + }; -struct _jcv_graphedge -{ - struct _jcv_graphedge* next; - struct _jcv_edge* edge; - struct _jcv_site* neighbor; - jcv_point pos[2]; - jcv_real angle; -}; + struct _jcv_graphedge + { + struct _jcv_graphedge *next; + struct _jcv_edge *edge; + struct _jcv_site *neighbor; + jcv_point pos[2]; + jcv_real angle; + }; -struct _jcv_site -{ - jcv_point p; - int index; // Index into the original list of points - jcv_graphedge* edges; // The half edges owned by the cell -}; + struct _jcv_site + { + jcv_point p; + int index; // Index into the original list of points + jcv_graphedge *edges; // The half edges owned by the cell + }; -// The coefficients a, b and c are from the general line equation: ax * by + c = 0 -struct _jcv_edge -{ - struct _jcv_edge* next; - jcv_site* sites[2]; - jcv_point pos[2]; - jcv_real a; - jcv_real b; - jcv_real c; -}; + // The coefficients a, b and c are from the general line equation: ax * by + c = 0 + struct _jcv_edge + { + struct _jcv_edge *next; + jcv_site *sites[2]; + jcv_point pos[2]; + jcv_real a; + jcv_real b; + jcv_real c; + }; -struct _jcv_rect -{ - jcv_point min; - jcv_point max; -}; + struct _jcv_rect + { + jcv_point min; + jcv_point max; + }; -struct _jcv_clipper -{ - jcv_clip_test_point_fn test_fn; - jcv_clip_edge_fn clip_fn; - jcv_clip_fillgap_fn fill_fn; - jcv_point min; // The bounding rect min - jcv_point max; // The bounding rect max - void* ctx; // User defined context -}; + struct _jcv_clipper + { + jcv_clip_test_point_fn test_fn; + jcv_clip_edge_fn clip_fn; + jcv_clip_fillgap_fn fill_fn; + jcv_point min; // The bounding rect min + jcv_point max; // The bounding rect max + void *ctx; // User defined context + }; -struct _jcv_diagram -{ - jcv_context_internal* internal; - jcv_edge* edges; - jcv_site* sites; - int numsites; - jcv_point min; - jcv_point max; -}; + struct _jcv_diagram + { + jcv_context_internal *internal; + jcv_edge *edges; + jcv_site *sites; + int numsites; + jcv_point min; + jcv_point max; + }; #pragma pack(pop) @@ -180,41 +182,47 @@ struct _jcv_diagram // INTERNAL FUNCTIONS #if defined(_MSC_VER) && !defined(__cplusplus) - #define inline __inline +#define inline __inline #endif // jcv_point +#include + +static inline bool jcv_iszero(const double x) +{ + return fabs(x) < JCV_FLT_EPSILON; +} -static inline int jcv_point_cmp(const void* p1, const void* p2) +static inline int jcv_point_cmp(const void *p1, const void *p2) { - const jcv_point* s1 = (const jcv_point*) p1; - const jcv_point* s2 = (const jcv_point*) p2; - return (s1->y != s2->y) ? (s1->y < s2->y ? -1 : 1) : (s1->x < s2->x ? -1 : 1); + const jcv_point *s1 = (const jcv_point *)p1; + const jcv_point *s2 = (const jcv_point *)p2; + return !jcv_iszero(s1->y - s2->y) ? (s1->y < s2->y ? -1 : 1) : (s1->x < s2->x ? -1 : 1); } -static inline int jcv_point_less( const jcv_point* pt1, const jcv_point* pt2 ) +static inline int jcv_point_less(const jcv_point *pt1, const jcv_point *pt2) { - return (pt1->y == pt2->y) ? (pt1->x < pt2->x) : pt1->y < pt2->y; + return jcv_iszero(pt1->y - pt2->y) ? (pt1->x < pt2->x) : pt1->y < pt2->y; } -static inline int jcv_point_eq( const jcv_point* pt1, const jcv_point* pt2 ) +static inline int jcv_point_eq(const jcv_point *pt1, const jcv_point *pt2) { return (fabs(pt1->y - pt2->y) < JCV_REAL_TYPE_EPSILON) && (fabs(pt1->x - pt2->x) < JCV_REAL_TYPE_EPSILON); } -static inline int jcv_point_on_box_edge( const jcv_point* pt, const jcv_point* min, const jcv_point* max ) +static inline int jcv_point_on_box_edge(const jcv_point *pt, const jcv_point *min, const jcv_point *max) { - return pt->x == min->x || pt->y == min->y || pt->x == max->x || pt->y == max->y; + return jcv_iszero(pt->x - min->x) || jcv_iszero(pt->y - min->y) || pt->x == max->x || pt->y == max->y; } -static inline jcv_real jcv_point_dist_sq( const jcv_point* pt1, const jcv_point* pt2) +static inline jcv_real jcv_point_dist_sq(const jcv_point *pt1, const jcv_point *pt2) { jcv_real diffx = pt1->x - pt2->x; jcv_real diffy = pt1->y - pt2->y; return diffx * diffx + diffy * diffy; } -static inline jcv_real jcv_point_dist( const jcv_point* pt1, const jcv_point* pt2 ) +static inline jcv_real jcv_point_dist(const jcv_point *pt1, const jcv_point *pt2) { return (jcv_real)(JCV_SQRT(jcv_point_dist_sq(pt1, pt2))); } @@ -225,153 +233,150 @@ static inline jcv_real jcv_point_dist( const jcv_point* pt1, const jcv_point* pt typedef struct _jcv_halfedge { - jcv_edge* edge; - struct _jcv_halfedge* left; - struct _jcv_halfedge* right; - jcv_point vertex; - jcv_real y; - int direction; // 0=left, 1=right - int pqpos; + jcv_edge *edge; + struct _jcv_halfedge *left; + struct _jcv_halfedge *right; + jcv_point vertex; + jcv_real y; + int direction; // 0=left, 1=right + int pqpos; } jcv_halfedge; typedef struct _jcv_memoryblock { size_t sizefree; - struct _jcv_memoryblock* next; - char* memory; + struct _jcv_memoryblock *next; + char *memory; } jcv_memoryblock; - -typedef int (*FJCVPriorityQueuePrint)(const void* node, int pos); +typedef int (*FJCVPriorityQueuePrint)(const void *node, int pos); typedef struct _jcv_priorityqueue { // Implements a binary heap - int maxnumitems; - int numitems; - void** items; + int maxnumitems; + int numitems; + void **items; } jcv_priorityqueue; - struct _jcv_context_internal { - void* mem; - jcv_edge* edges; - jcv_halfedge* beachline_start; - jcv_halfedge* beachline_end; - jcv_halfedge* last_inserted; - jcv_priorityqueue* eventqueue; - - jcv_site* sites; - jcv_site* bottomsite; - int numsites; - int currentsite; - int _padding; - - jcv_memoryblock* memblocks; - jcv_edge* edgepool; - jcv_halfedge* halfedgepool; - void** eventmem; - jcv_clipper clipper; - - void* memctx; // Given by the user - FJCVAllocFn alloc; - FJCVFreeFn free; - - jcv_rect rect; + void *mem; + jcv_edge *edges; + jcv_halfedge *beachline_start; + jcv_halfedge *beachline_end; + jcv_halfedge *last_inserted; + jcv_priorityqueue *eventqueue; + + jcv_site *sites; + jcv_site *bottomsite; + int numsites; + int currentsite; + int _padding; + + jcv_memoryblock *memblocks; + jcv_edge *edgepool; + jcv_halfedge *halfedgepool; + void **eventmem; + jcv_clipper clipper; + + void *memctx; // Given by the user + FJCVAllocFn alloc; + FJCVFreeFn free; + + jcv_rect rect; }; #pragma pack(pop) - -static const int JCV_DIRECTION_LEFT = 0; +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; - -void jcv_diagram_free( jcv_diagram* d ) +void jcv_diagram_free(jcv_diagram *d) { - jcv_context_internal* internal = d->internal; - void* memctx = internal->memctx; + jcv_context_internal *internal = d->internal; + void *memctx = internal->memctx; FJCVFreeFn freefn = internal->free; - while(internal->memblocks) + while (internal->memblocks) { - jcv_memoryblock* p = internal->memblocks; + jcv_memoryblock *p = internal->memblocks; internal->memblocks = internal->memblocks->next; - freefn( memctx, p ); + freefn(memctx, p); } - freefn( memctx, internal->mem ); + freefn(memctx, internal->mem); } -const jcv_site* jcv_diagram_get_sites( const jcv_diagram* diagram ) +const jcv_site *jcv_diagram_get_sites(const jcv_diagram *diagram) { return diagram->internal->sites; } -const jcv_edge* jcv_diagram_get_edges( const jcv_diagram* diagram ) +const jcv_edge *jcv_diagram_get_edges(const jcv_diagram *diagram) { jcv_edge e; e.next = diagram->internal->edges; return jcv_diagram_get_next_edge(&e); } -const jcv_edge* jcv_diagram_get_next_edge( const jcv_edge* edge ) +const jcv_edge *jcv_diagram_get_next_edge(const jcv_edge *edge) { - const jcv_edge* e = edge->next; - while (e != 0 && jcv_point_eq(&e->pos[0], &e->pos[1])) { + const jcv_edge *e = edge->next; + while (e != 0 && jcv_point_eq(&e->pos[0], &e->pos[1])) + { e = e->next; } return e; } -static void* jcv_alloc(jcv_context_internal* internal, size_t size) +static void *jcv_alloc(jcv_context_internal *internal, size_t size) { - if( !internal->memblocks || internal->memblocks->sizefree < size ) + if (!internal->memblocks || internal->memblocks->sizefree < size) { size_t blocksize = 16 * 1024; - jcv_memoryblock* block = (jcv_memoryblock*)internal->alloc( internal->memctx, blocksize ); + jcv_memoryblock *block = (jcv_memoryblock *)internal->alloc(internal->memctx, blocksize); size_t offset = sizeof(jcv_memoryblock); block->sizefree = blocksize - offset; block->next = internal->memblocks; - block->memory = ((char*)block) + offset; + block->memory = ((char *)block) + offset; internal->memblocks = block; } - void* p = internal->memblocks->memory; + void *p = internal->memblocks->memory; internal->memblocks->memory += size; internal->memblocks->sizefree -= size; return p; } -static jcv_edge* jcv_alloc_edge(jcv_context_internal* internal) +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, sizeof(jcv_edge)); } -static jcv_halfedge* jcv_alloc_halfedge(jcv_context_internal* internal) +static jcv_halfedge *jcv_alloc_halfedge(jcv_context_internal *internal) { - if( internal->halfedgepool ) + if (internal->halfedgepool) { - jcv_halfedge* edge = internal->halfedgepool; + jcv_halfedge *edge = internal->halfedgepool; internal->halfedgepool = internal->halfedgepool->right; return edge; } - return (jcv_halfedge*)jcv_alloc(internal, sizeof(jcv_halfedge)); + return (jcv_halfedge *)jcv_alloc(internal, sizeof(jcv_halfedge)); } -static jcv_graphedge* jcv_alloc_graphedge(jcv_context_internal* internal) +static jcv_graphedge *jcv_alloc_graphedge(jcv_context_internal *internal) { - return (jcv_graphedge*)jcv_alloc(internal, sizeof(jcv_graphedge)); + return (jcv_graphedge *)jcv_alloc(internal, sizeof(jcv_graphedge)); } -static void* jcv_alloc_fn(void* memctx, size_t size) +static void *jcv_alloc_fn(void *memctx, size_t size) { (void)memctx; return malloc(size); } -static void jcv_free_fn(void* memctx, void* p) +static void jcv_free_fn(void *memctx, void *p) { (void)memctx; free(p); @@ -379,12 +384,12 @@ static void jcv_free_fn(void* memctx, void* p) // jcv_edge -static inline int jcv_is_valid(const jcv_point* p) +static inline int jcv_is_valid(const jcv_point *p) { return (p->x != JCV_INVALID_VALUE || p->y != JCV_INVALID_VALUE) ? 1 : 0; } -static void jcv_edge_create(jcv_edge* e, jcv_site* s1, jcv_site* s2) +static void jcv_edge_create(jcv_edge *e, jcv_site *s1, jcv_site *s2) { e->next = 0; e->sites[0] = s1; @@ -411,12 +416,12 @@ static void jcv_edge_create(jcv_edge* e, jcv_site* s1, jcv_site* s2) jcv_real dx = s2->p.x - s1->p.x; jcv_real dy = s2->p.y - s1->p.y; - int dx_is_larger = (dx*dx) > (dy*dy); // instead of fabs + int dx_is_larger = (dx * dx) > (dy * dy); // instead of fabs // Simplify it, using dx and dy e->c = dx * (s1->p.x + dx * (jcv_real)0.5) + dy * (s1->p.y + dy * (jcv_real)0.5); - if( dx_is_larger ) + if (dx_is_larger) { e->a = (jcv_real)1; e->b = dy / dx; @@ -431,15 +436,15 @@ static void jcv_edge_create(jcv_edge* e, jcv_site* s1, jcv_site* s2) } // CLIPPING -int jcv_boxshape_test(const jcv_clipper* clipper, const jcv_point p) +int jcv_boxshape_test(const jcv_clipper *clipper, const jcv_point p) { - return p.x >= clipper->min.x && p.x <= clipper->max.x && - p.y >= clipper->min.y && p.y <= clipper->max.y; + return !(p.x < clipper->min.x || p.x > clipper->max.x || + p.y < clipper->min.y || p.y > clipper->max.y); } // The line equation: ax + by + c = 0 // see jcv_edge_create -int jcv_boxshape_clip(const jcv_clipper* clipper, jcv_edge* e) +int jcv_boxshape_clip(const jcv_clipper *clipper, jcv_edge *e) { jcv_real pxmin = clipper->min.x; jcv_real pxmax = clipper->max.x; @@ -447,8 +452,8 @@ int jcv_boxshape_clip(const jcv_clipper* clipper, jcv_edge* e) jcv_real pymax = clipper->max.y; jcv_real x1, y1, x2, y2; - jcv_point* s1; - jcv_point* s2; + jcv_point *s1; + jcv_point *s2; if (e->a == (jcv_real)1 && e->b >= (jcv_real)0) { s1 = jcv_is_valid(&e->pos[1]) ? &e->pos[1] : 0; @@ -467,7 +472,7 @@ int jcv_boxshape_clip(const jcv_clipper* clipper, jcv_edge* e) { y1 = s1->y; } - if( y1 > pymax ) + if (y1 > pymax) { y1 = pymax; } @@ -476,7 +481,7 @@ int jcv_boxshape_clip(const jcv_clipper* clipper, jcv_edge* e) if (s2 != 0 && s2->y < pymax) y2 = s2->y; - if( y2 < pymin ) + if (y2 < pymin) { y2 = pymin; } @@ -510,17 +515,17 @@ int jcv_boxshape_clip(const jcv_clipper* clipper, jcv_edge* e) else // delta y is larger { x1 = pxmin; - if( s1 != 0 && s1->x > pxmin ) + if (s1 != 0 && s1->x > pxmin) x1 = s1->x; - if( x1 > pxmax ) + if (x1 > pxmax) { x1 = pxmax; } y1 = e->c - e->a * x1; x2 = pxmax; - if( s2 != 0 && s2->x < pxmax ) + if (s2 != 0 && s2->x < pxmax) x2 = s2->x; - if( x2 < pxmin ) + if (x2 < pxmin) { x2 = pxmin; } @@ -530,22 +535,22 @@ int jcv_boxshape_clip(const jcv_clipper* clipper, jcv_edge* e) // { // return 0; // } - if( y1 > pymax ) + if (y1 > pymax) { y1 = pymax; x1 = (e->c - y1) / e->a; } - else if( y1 < pymin ) + else if (y1 < pymin) { y1 = pymin; x1 = (e->c - y1) / e->a; } - if( y2 > pymax ) + if (y2 > pymax) { y2 = pymax; x2 = (e->c - y2) / e->a; } - else if( y2 < pymin ) + else if (y2 < pymin) { y2 = pymin; x2 = (e->c - y2) / e->a; @@ -558,27 +563,26 @@ int jcv_boxshape_clip(const jcv_clipper* clipper, jcv_edge* e) e->pos[1].y = y2; // If the two points are equal, the result is invalid - return (x1 == x2 && y1 == y2) ? 0 : 1; + return (jcv_iszero(x1 - x2) && jcv_iszero(y1 - y2)) ? 0 : 1; } // The line equation: ax + by + c = 0 // see jcv_edge_create -static int jcv_edge_clipline(jcv_context_internal* internal, jcv_edge* e) +static int jcv_edge_clipline(jcv_context_internal *internal, jcv_edge *e) { return internal->clipper.clip_fn(&internal->clipper, e); } -static jcv_edge* jcv_edge_new(jcv_context_internal* internal, jcv_site* s1, jcv_site* s2) +static jcv_edge *jcv_edge_new(jcv_context_internal *internal, jcv_site *s1, jcv_site *s2) { - jcv_edge* e = jcv_alloc_edge(internal); + jcv_edge *e = jcv_alloc_edge(internal); jcv_edge_create(e, s1, s2); return e; } - // jcv_halfedge -static void jcv_halfedge_link(jcv_halfedge* edge, jcv_halfedge* newedge) +static void jcv_halfedge_link(jcv_halfedge *edge, jcv_halfedge *newedge) { newedge->left = edge; newedge->right = edge->right; @@ -586,48 +590,48 @@ static void jcv_halfedge_link(jcv_halfedge* edge, jcv_halfedge* newedge) edge->right = newedge; } -static inline void jcv_halfedge_unlink(jcv_halfedge* he) +static inline void jcv_halfedge_unlink(jcv_halfedge *he) { he->left->right = he->right; he->right->left = he->left; - he->left = 0; + he->left = 0; he->right = 0; } -static inline jcv_halfedge* jcv_halfedge_new(jcv_context_internal* internal, jcv_edge* e, int direction) +static inline jcv_halfedge *jcv_halfedge_new(jcv_context_internal *internal, jcv_edge *e, int direction) { - jcv_halfedge* he = jcv_alloc_halfedge(internal); - he->edge = e; - he->left = 0; - he->right = 0; - he->direction = direction; - he->pqpos = 0; + jcv_halfedge *he = jcv_alloc_halfedge(internal); + he->edge = e; + he->left = 0; + he->right = 0; + he->direction = direction; + he->pqpos = 0; // These are set outside - //he->y - //he->vertex + // he->y + // he->vertex return he; } -static void jcv_halfedge_delete(jcv_context_internal* internal, jcv_halfedge* he) +static void jcv_halfedge_delete(jcv_context_internal *internal, jcv_halfedge *he) { he->right = internal->halfedgepool; internal->halfedgepool = he; } -static inline jcv_site* jcv_halfedge_leftsite(const jcv_halfedge* he) +static inline jcv_site *jcv_halfedge_leftsite(const jcv_halfedge *he) { return he->edge->sites[he->direction]; } -static inline jcv_site* jcv_halfedge_rightsite(const jcv_halfedge* he) +static inline jcv_site *jcv_halfedge_rightsite(const jcv_halfedge *he) { return he->edge ? he->edge->sites[1 - he->direction] : 0; } -static int jcv_halfedge_rightof(const jcv_halfedge* he, const jcv_point* p) +static int jcv_halfedge_rightof(const jcv_halfedge *he, const jcv_point *p) { - const jcv_edge* e = he->edge; - const jcv_site* topsite = e->sites[1]; + const jcv_edge *e = he->edge; + const jcv_site *topsite = e->sites[1]; int right_of_site = (p->x > topsite->p.x) ? 1 : 0; if (right_of_site && he->direction == JCV_DIRECTION_LEFT) @@ -643,7 +647,7 @@ static int jcv_halfedge_rightof(const jcv_halfedge* he, const jcv_point* p) dyp = p->y - topsite->p.y; dxp = p->x - topsite->p.x; int fast = 0; - if( (!right_of_site & (e->b < (jcv_real)0)) | (right_of_site & (e->b >= (jcv_real)0)) ) + if ((!right_of_site & (e->b < (jcv_real)0)) | (right_of_site & (e->b >= (jcv_real)0))) { above = dyp >= e->b * dxp; fast = above; @@ -659,8 +663,7 @@ static int jcv_halfedge_rightof(const jcv_halfedge* he, const jcv_point* p) if (!fast) { dxs = topsite->p.x - e->sites[0]->p.x; - above = e->b * (dxp * dxp - dyp * dyp) - < dxs * dyp * ((jcv_real)1 + (jcv_real)2 * dxp / dxs + e->b * e->b); + above = e->b * (dxp * dxp - dyp * dyp) < dxs * dyp * ((jcv_real)1 + (jcv_real)2 * dxp / dxs + e->b * e->b); if (e->b < (jcv_real)0) above = !above; }; @@ -678,27 +681,27 @@ static int jcv_halfedge_rightof(const jcv_halfedge* he, const jcv_point* p) // Keeps the priority queue sorted with events sorted in ascending order // Return 1 if the edges needs to be swapped -static inline int jcv_halfedge_compare( const jcv_halfedge* he1, const jcv_halfedge* he2 ) +static inline int jcv_halfedge_compare(const jcv_halfedge *he1, const jcv_halfedge *he2) { - return (he1->y == he2->y) ? he1->vertex.x > he2->vertex.x : he1->y > he2->y; + return (he1->y == he2->y) ? he1->vertex.x > he2->vertex.x : he1->y > he2->y; } -static int jcv_halfedge_intersect(const jcv_halfedge* he1, const jcv_halfedge* he2, jcv_point* out) +static int jcv_halfedge_intersect(const jcv_halfedge *he1, const jcv_halfedge *he2, jcv_point *out) { - const jcv_edge* e1 = he1->edge; - const jcv_edge* e2 = he2->edge; + const jcv_edge *e1 = he1->edge; + const jcv_edge *e2 = he2->edge; jcv_real d = e1->a * e2->b - e1->b * e2->a; - if( ((jcv_real)-JCV_EDGE_INTERSECT_THRESHOLD < d && d < (jcv_real)JCV_EDGE_INTERSECT_THRESHOLD) ) + if (((jcv_real)-JCV_EDGE_INTERSECT_THRESHOLD < d && d < (jcv_real)JCV_EDGE_INTERSECT_THRESHOLD)) { return 0; } out->x = (e1->c * e2->b - e1->b * e2->c) / d; out->y = (e1->a * e2->c - e1->c * e2->a) / d; - const jcv_edge* e; - const jcv_halfedge* he; - if( jcv_point_less( &e1->sites[1]->p, &e2->sites[1]->p) ) + const jcv_edge *e; + const jcv_halfedge *he; + if (jcv_point_less(&e1->sites[1]->p, &e2->sites[1]->p)) { he = he1; e = e1; @@ -718,15 +721,14 @@ static int jcv_halfedge_intersect(const jcv_halfedge* he1, const jcv_halfedge* h return 1; } - // Priority queue -static int jcv_pq_moveup(jcv_priorityqueue* pq, int pos) +static int jcv_pq_moveup(jcv_priorityqueue *pq, int pos) { - jcv_halfedge** items = (jcv_halfedge**)pq->items; - jcv_halfedge* node = items[pos]; + jcv_halfedge **items = (jcv_halfedge **)pq->items; + jcv_halfedge *node = items[pos]; - for( int parent = (pos >> 1); + for (int parent = (pos >> 1); pos > 1 && jcv_halfedge_compare(items[parent], node); pos = parent, parent = parent >> 1) { @@ -739,24 +741,24 @@ static int jcv_pq_moveup(jcv_priorityqueue* pq, int pos) return pos; } -static int jcv_pq_maxchild(jcv_priorityqueue* pq, int pos) +static int jcv_pq_maxchild(jcv_priorityqueue *pq, int pos) { int child = pos << 1; - if( child >= pq->numitems ) + if (child >= pq->numitems) return 0; - jcv_halfedge** items = (jcv_halfedge**)pq->items; - if( (child + 1) < pq->numitems && jcv_halfedge_compare(items[child], items[child+1]) ) - return child+1; + jcv_halfedge **items = (jcv_halfedge **)pq->items; + if ((child + 1) < pq->numitems && jcv_halfedge_compare(items[child], items[child + 1])) + return child + 1; return child; } -static int jcv_pq_movedown(jcv_priorityqueue* pq, int pos) +static int jcv_pq_movedown(jcv_priorityqueue *pq, int pos) { - jcv_halfedge** items = (jcv_halfedge**)pq->items; - jcv_halfedge* node = items[pos]; + jcv_halfedge **items = (jcv_halfedge **)pq->items; + jcv_halfedge *node = items[pos]; int child = jcv_pq_maxchild(pq, pos); - while( child && jcv_halfedge_compare(node, items[child]) ) + while (child && jcv_halfedge_compare(node, items[child])) { items[pos] = items[child]; items[pos]->pqpos = pos; @@ -769,19 +771,19 @@ static int jcv_pq_movedown(jcv_priorityqueue* pq, int pos) return pos; } -static void jcv_pq_create(jcv_priorityqueue* pq, int capacity, void** buffer) +static void jcv_pq_create(jcv_priorityqueue *pq, int capacity, void **buffer) { pq->maxnumitems = capacity; - pq->numitems = 1; - pq->items = buffer; + pq->numitems = 1; + pq->items = buffer; } -static int jcv_pq_empty(jcv_priorityqueue* pq) +static int jcv_pq_empty(jcv_priorityqueue *pq) { return pq->numitems == 1 ? 1 : 0; } -static int jcv_pq_push(jcv_priorityqueue* pq, void* node) +static int jcv_pq_push(jcv_priorityqueue *pq, void *node) { assert(pq->numitems < pq->maxnumitems); int n = pq->numitems++; @@ -789,84 +791,84 @@ static int jcv_pq_push(jcv_priorityqueue* pq, void* node) return jcv_pq_moveup(pq, n); } -static void* jcv_pq_pop(jcv_priorityqueue* pq) +static void *jcv_pq_pop(jcv_priorityqueue *pq) { - void* node = pq->items[1]; + void *node = pq->items[1]; pq->items[1] = pq->items[--pq->numitems]; jcv_pq_movedown(pq, 1); return node; } -static void* jcv_pq_top(jcv_priorityqueue* pq) +static void *jcv_pq_top(jcv_priorityqueue *pq) { return pq->items[1]; } -static void jcv_pq_remove(jcv_priorityqueue* pq, jcv_halfedge* node) +static void jcv_pq_remove(jcv_priorityqueue *pq, jcv_halfedge *node) { - if( pq->numitems == 1 ) + if (pq->numitems == 1) return; int pos = node->pqpos; - if( pos == 0 ) + if (pos == 0) return; - jcv_halfedge** items = (jcv_halfedge**)pq->items; + jcv_halfedge **items = (jcv_halfedge **)pq->items; items[pos] = items[--pq->numitems]; - if( jcv_halfedge_compare( node, items[pos] ) ) - jcv_pq_moveup( pq, pos ); + if (jcv_halfedge_compare(node, items[pos])) + jcv_pq_moveup(pq, pos); else - jcv_pq_movedown( pq, pos ); + jcv_pq_movedown(pq, pos); node->pqpos = pos; } // internal functions -static inline jcv_site* jcv_nextsite(jcv_context_internal* internal) +static inline jcv_site *jcv_nextsite(jcv_context_internal *internal) { return (internal->currentsite < internal->numsites) ? &internal->sites[internal->currentsite++] : 0; } -static jcv_halfedge* jcv_get_edge_above_x(jcv_context_internal* internal, const jcv_point* p) +static jcv_halfedge *jcv_get_edge_above_x(jcv_context_internal *internal, const jcv_point *p) { // Gets the arc on the beach line at the x coordinate (i.e. right above the new site event) // A good guess it's close by (Can be optimized) - jcv_halfedge* he = internal->last_inserted; - if( !he ) + jcv_halfedge *he = internal->last_inserted; + if (!he) { - if( p->x < (internal->rect.max.x - internal->rect.min.x) / 2 ) + if (p->x < (internal->rect.max.x - internal->rect.min.x) / 2) he = internal->beachline_start; else he = internal->beachline_end; } // - if( he == internal->beachline_start || (he != internal->beachline_end && jcv_halfedge_rightof(he, p)) ) + if (he == internal->beachline_start || (he != internal->beachline_end && jcv_halfedge_rightof(he, p))) { - do { + do + { he = he->right; - } - while( he != internal->beachline_end && jcv_halfedge_rightof(he, p) ); + } while (he != internal->beachline_end && jcv_halfedge_rightof(he, p)); he = he->left; } else { - do { + do + { he = he->left; - } - while( he != internal->beachline_start && !jcv_halfedge_rightof(he, p) ); + } while (he != internal->beachline_start && !jcv_halfedge_rightof(he, p)); } return he; } -static int jcv_check_circle_event(const jcv_halfedge* he1, const jcv_halfedge* he2, jcv_point* vertex) +static int jcv_check_circle_event(const jcv_halfedge *he1, const jcv_halfedge *he2, jcv_point *vertex) { - jcv_edge* e1 = he1->edge; - jcv_edge* e2 = he2->edge; - if( e1 == 0 || e2 == 0 || e1->sites[1] == e2->sites[1] ) + jcv_edge *e1 = he1->edge; + jcv_edge *e2 = he2->edge; + if (e1 == 0 || e2 == 0 || e1->sites[1] == e2->sites[1]) { return 0; } @@ -874,20 +876,20 @@ static int jcv_check_circle_event(const jcv_halfedge* he1, const jcv_halfedge* h return jcv_halfedge_intersect(he1, he2, vertex); } -static void jcv_site_event(jcv_context_internal* internal, jcv_site* site) +static void jcv_site_event(jcv_context_internal *internal, jcv_site *site) { - jcv_halfedge* left = jcv_get_edge_above_x(internal, &site->p); - jcv_halfedge* right = left->right; - jcv_site* bottom = jcv_halfedge_rightsite(left); - if( !bottom ) + jcv_halfedge *left = jcv_get_edge_above_x(internal, &site->p); + jcv_halfedge *right = left->right; + jcv_site *bottom = jcv_halfedge_rightsite(left); + if (!bottom) bottom = internal->bottomsite; - jcv_edge* edge = jcv_edge_new(internal, bottom, site); + jcv_edge *edge = jcv_edge_new(internal, bottom, site); edge->next = internal->edges; internal->edges = edge; - jcv_halfedge* edge1 = jcv_halfedge_new(internal, edge, JCV_DIRECTION_LEFT); - jcv_halfedge* edge2 = jcv_halfedge_new(internal, edge, JCV_DIRECTION_RIGHT); + jcv_halfedge *edge1 = jcv_halfedge_new(internal, edge, JCV_DIRECTION_LEFT); + jcv_halfedge *edge2 = jcv_halfedge_new(internal, edge, JCV_DIRECTION_RIGHT); jcv_halfedge_link(left, edge1); jcv_halfedge_link(edge1, edge2); @@ -895,41 +897,41 @@ static void jcv_site_event(jcv_context_internal* internal, jcv_site* site) internal->last_inserted = right; jcv_point p; - if( jcv_check_circle_event( left, edge1, &p ) ) + if (jcv_check_circle_event(left, edge1, &p)) { jcv_pq_remove(internal->eventqueue, left); - left->vertex = p; - left->y = p.y + jcv_point_dist(&site->p, &p); + left->vertex = p; + left->y = p.y + jcv_point_dist(&site->p, &p); jcv_pq_push(internal->eventqueue, left); } - if( jcv_check_circle_event( edge2, right, &p ) ) + if (jcv_check_circle_event(edge2, right, &p)) { - edge2->vertex = p; - edge2->y = p.y + jcv_point_dist(&site->p, &p); + edge2->vertex = p; + edge2->y = p.y + jcv_point_dist(&site->p, &p); jcv_pq_push(internal->eventqueue, edge2); } } // https://cp-algorithms.com/geometry/oriented-triangle-area.html -static inline jcv_real jcv_determinant(const jcv_point* a, const jcv_point* b, const jcv_point* c) +static inline jcv_real jcv_determinant(const jcv_point *a, const jcv_point *b, const jcv_point *c) { - return (b->x - a->x)*(c->y - a->y) - (b->y - a->y)*(c->x - a->x); + return (b->x - a->x) * (c->y - a->y) - (b->y - a->y) * (c->x - a->x); } -static inline jcv_real jcv_calc_sort_metric(const jcv_site* site, const jcv_graphedge* edge) +static inline jcv_real jcv_calc_sort_metric(const jcv_site *site, const jcv_graphedge *edge) { // We take the average of the two points, since we can better distinguish between very small edges - jcv_real half = 1/(jcv_real)2; + jcv_real half = 1 / (jcv_real)2; jcv_real x = (edge->pos[0].x + edge->pos[1].x) * half; jcv_real y = (edge->pos[0].y + edge->pos[1].y) * half; jcv_real diffy = y - site->p.y; - jcv_real angle = JCV_ATAN2( diffy, x - site->p.x ); - if( diffy < 0 ) + jcv_real angle = JCV_ATAN2(diffy, x - site->p.x); + if (diffy < 0) angle = angle + 2 * JCV_PI; return (jcv_real)angle; } -static void jcv_sortedges_insert(jcv_site* site, jcv_graphedge* edge) +static void jcv_sortedges_insert(jcv_site *site, jcv_graphedge *edge) { // Special case for the head end if (site->edges == 0 || site->edges->angle >= edge->angle) @@ -940,8 +942,8 @@ static void jcv_sortedges_insert(jcv_site* site, jcv_graphedge* edge) else { // Locate the node before the point of insertion - jcv_graphedge* current = site->edges; - while(current->next != 0 && current->next->angle < edge->angle) + jcv_graphedge *current = site->edges; + while (current->next != 0 && current->next->angle < edge->angle) { current = current->next; } @@ -950,32 +952,33 @@ static void jcv_sortedges_insert(jcv_site* site, jcv_graphedge* edge) } } -static void jcv_finishline(jcv_context_internal* internal, jcv_edge* e) +static void jcv_finishline(jcv_context_internal *internal, jcv_edge *e) { - if( !jcv_edge_clipline(internal, e) ) { + if (!jcv_edge_clipline(internal, e)) + { return; } // Make sure the graph edges are CCW int flip = jcv_determinant(&e->sites[0]->p, &e->pos[0], &e->pos[1]) > (jcv_real)0 ? 0 : 1; - for( int i = 0; i < 2; ++i ) + for (int i = 0; i < 2; ++i) { - jcv_graphedge* ge = jcv_alloc_graphedge(internal); + jcv_graphedge *ge = jcv_alloc_graphedge(internal); ge->edge = e; ge->next = 0; - ge->neighbor = e->sites[1-i]; + ge->neighbor = e->sites[1 - i]; ge->pos[flip] = e->pos[i]; - ge->pos[1-flip] = e->pos[1-i]; + ge->pos[1 - flip] = e->pos[1 - i]; ge->angle = jcv_calc_sort_metric(e->sites[i], ge); - jcv_sortedges_insert( e->sites[i], ge ); + jcv_sortedges_insert(e->sites[i], ge); // check that we didn't accidentally add a duplicate (rare), then remove it - if( ge->next && ge->angle == ge->next->angle ) + if (ge->next && ge->angle == ge->next->angle) { - if( jcv_point_eq( &ge->pos[0], &ge->next->pos[0] ) && jcv_point_eq( &ge->pos[1], &ge->next->pos[1] ) ) + if (jcv_point_eq(&ge->pos[0], &ge->next->pos[0]) && jcv_point_eq(&ge->pos[1], &ge->next->pos[1])) { ge->next = ge->next->next; // Throw it away, they're so few anyways } @@ -983,38 +986,37 @@ static void jcv_finishline(jcv_context_internal* internal, jcv_edge* e) } } - -static void jcv_endpos(jcv_context_internal* internal, jcv_edge* e, const jcv_point* p, int direction) +static void jcv_endpos(jcv_context_internal *internal, jcv_edge *e, const jcv_point *p, int direction) { e->pos[direction] = *p; - if( !jcv_is_valid(&e->pos[1 - direction]) ) + if (!jcv_is_valid(&e->pos[1 - direction])) return; jcv_finishline(internal, e); } -static inline void jcv_create_corner_edge(jcv_context_internal* internal, const jcv_site* site, jcv_graphedge* current, jcv_graphedge* gap) +static inline void jcv_create_corner_edge(jcv_context_internal *internal, const jcv_site *site, jcv_graphedge *current, jcv_graphedge *gap) { - gap->neighbor = 0; - gap->pos[0] = current->pos[1]; + gap->neighbor = 0; + gap->pos[0] = current->pos[1]; - if( current->pos[1].x < internal->rect.max.x && current->pos[1].y == internal->rect.min.y ) + if (current->pos[1].x < internal->rect.max.x && current->pos[1].y == internal->rect.min.y) { gap->pos[1].x = internal->rect.max.x; gap->pos[1].y = internal->rect.min.y; } - else if( current->pos[1].x > internal->rect.min.x && current->pos[1].y == internal->rect.max.y ) + else if (current->pos[1].x > internal->rect.min.x && current->pos[1].y == internal->rect.max.y) { gap->pos[1].x = internal->rect.min.x; gap->pos[1].y = internal->rect.max.y; } - else if( current->pos[1].y > internal->rect.min.y && current->pos[1].x == internal->rect.min.x ) + else if (current->pos[1].y > internal->rect.min.y && current->pos[1].x == internal->rect.min.x) { gap->pos[1].x = internal->rect.min.x; gap->pos[1].y = internal->rect.min.y; } - else if( current->pos[1].y < internal->rect.max.y && current->pos[1].x == internal->rect.max.x ) + else if (current->pos[1].y < internal->rect.max.y && current->pos[1].x == internal->rect.max.x) { gap->pos[1].x = internal->rect.max.x; gap->pos[1].y = internal->rect.max.y; @@ -1023,46 +1025,46 @@ static inline void jcv_create_corner_edge(jcv_context_internal* internal, const gap->angle = jcv_calc_sort_metric(site, gap); } -static jcv_edge* jcv_create_gap_edge(jcv_context_internal* internal, jcv_site* site, jcv_graphedge* ge) +static jcv_edge *jcv_create_gap_edge(jcv_context_internal *internal, jcv_site *site, jcv_graphedge *ge) { - jcv_edge* edge = jcv_alloc_edge(internal); - edge->pos[0] = ge->pos[0]; - edge->pos[1] = ge->pos[1]; - edge->sites[0] = site; - edge->sites[1] = 0; + jcv_edge *edge = jcv_alloc_edge(internal); + edge->pos[0] = ge->pos[0]; + edge->pos[1] = ge->pos[1]; + edge->sites[0] = site; + edge->sites[1] = 0; edge->a = edge->b = edge->c = 0; - edge->next = internal->edges; + edge->next = internal->edges; internal->edges = edge; return edge; } -void jcv_boxshape_fillgaps(const jcv_clipper* clipper, jcv_context_internal* allocator, jcv_site* site) +void jcv_boxshape_fillgaps(const jcv_clipper *clipper, jcv_context_internal *allocator, jcv_site *site) { // They're sorted CCW, so if the current->pos[1] != next->pos[0], then we have a gap - jcv_graphedge* current = site->edges; - if( !current ) + jcv_graphedge *current = site->edges; + if (!current) { // No edges, then it should be a single cell - assert( allocator->numsites == 1 ); - - jcv_graphedge* gap = jcv_alloc_graphedge(allocator); - gap->neighbor = 0; - gap->pos[0] = clipper->min; - gap->pos[1].x = clipper->max.x; - gap->pos[1].y = clipper->min.y; - gap->angle = jcv_calc_sort_metric(site, gap); - gap->next = 0; - gap->edge = jcv_create_gap_edge(allocator, site, gap); + assert(allocator->numsites == 1); + + jcv_graphedge *gap = jcv_alloc_graphedge(allocator); + gap->neighbor = 0; + gap->pos[0] = clipper->min; + gap->pos[1].x = clipper->max.x; + gap->pos[1].y = clipper->min.y; + gap->angle = jcv_calc_sort_metric(site, gap); + gap->next = 0; + gap->edge = jcv_create_gap_edge(allocator, site, gap); current = gap; site->edges = gap; } - jcv_graphedge* next = current->next; - if( !next ) + jcv_graphedge *next = current->next; + if (!next) { // Only one edge, then we assume it's a corner gap - jcv_graphedge* gap = jcv_alloc_graphedge(allocator); + jcv_graphedge *gap = jcv_alloc_graphedge(allocator); jcv_create_corner_edge(allocator, site, current, gap); gap->edge = jcv_create_gap_edge(allocator, site, gap); @@ -1072,27 +1074,27 @@ void jcv_boxshape_fillgaps(const jcv_clipper* clipper, jcv_context_internal* all next = site->edges; } - while( current && next ) + while (current && next) { - if( jcv_point_on_box_edge(¤t->pos[1], &clipper->min, &clipper->max) && !jcv_point_eq(¤t->pos[1], &next->pos[0]) ) + if (jcv_point_on_box_edge(¤t->pos[1], &clipper->min, &clipper->max) && !jcv_point_eq(¤t->pos[1], &next->pos[0])) { // Border gap - if( current->pos[1].x == next->pos[0].x || current->pos[1].y == next->pos[0].y) + if (current->pos[1].x == next->pos[0].x || current->pos[1].y == next->pos[0].y) { - jcv_graphedge* gap = jcv_alloc_graphedge(allocator); - gap->neighbor = 0; - gap->pos[0] = current->pos[1]; - gap->pos[1] = next->pos[0]; - gap->angle = jcv_calc_sort_metric(site, gap); - gap->edge = jcv_create_gap_edge(allocator, site, gap); + jcv_graphedge *gap = jcv_alloc_graphedge(allocator); + gap->neighbor = 0; + gap->pos[0] = current->pos[1]; + gap->pos[1] = next->pos[0]; + gap->angle = jcv_calc_sort_metric(site, gap); + gap->edge = jcv_create_gap_edge(allocator, site, gap); gap->next = current->next; current->next = gap; } - else if( jcv_point_on_box_edge(¤t->pos[1], &clipper->min, &clipper->max) && - jcv_point_on_box_edge(&next->pos[0], &clipper->min, &clipper->max) ) + else if (jcv_point_on_box_edge(¤t->pos[1], &clipper->min, &clipper->max) && + jcv_point_on_box_edge(&next->pos[0], &clipper->min, &clipper->max)) { - jcv_graphedge* gap = jcv_alloc_graphedge(allocator); + jcv_graphedge *gap = jcv_alloc_graphedge(allocator); jcv_create_corner_edge(allocator, site, current, gap); gap->edge = jcv_create_gap_edge(allocator, site, gap); gap->next = current->next; @@ -1106,39 +1108,38 @@ void jcv_boxshape_fillgaps(const jcv_clipper* clipper, jcv_context_internal* all } current = current->next; - if( current ) + if (current) { next = current->next; - if( !next ) + if (!next) next = site->edges; } } } // Since the algorithm leaves gaps at the borders/corner, we want to fill them -static void jcv_fillgaps(jcv_diagram* diagram) +static void jcv_fillgaps(jcv_diagram *diagram) { - jcv_context_internal* internal = diagram->internal; + jcv_context_internal *internal = diagram->internal; if (!internal->clipper.fill_fn) return; - for( int i = 0; i < internal->numsites; ++i ) + for (int i = 0; i < internal->numsites; ++i) { - jcv_site* site = &internal->sites[i]; + jcv_site *site = &internal->sites[i]; internal->clipper.fill_fn(&internal->clipper, internal, site); } } - -static void jcv_circle_event(jcv_context_internal* internal) +static void jcv_circle_event(jcv_context_internal *internal) { - jcv_halfedge* left = (jcv_halfedge*)jcv_pq_pop(internal->eventqueue); + jcv_halfedge *left = (jcv_halfedge *)jcv_pq_pop(internal->eventqueue); - jcv_halfedge* leftleft = left->left; - jcv_halfedge* right = left->right; - jcv_halfedge* rightright= right->right; - jcv_site* bottom = jcv_halfedge_leftsite(left); - jcv_site* top = jcv_halfedge_rightsite(right); + jcv_halfedge *leftleft = left->left; + jcv_halfedge *right = left->right; + jcv_halfedge *rightright = right->right; + jcv_site *bottom = jcv_halfedge_leftsite(left); + jcv_site *top = jcv_halfedge_rightsite(right); jcv_point vertex = left->vertex; jcv_endpos(internal, left->edge, &vertex, left->direction); @@ -1153,68 +1154,72 @@ static void jcv_circle_event(jcv_context_internal* internal) jcv_halfedge_delete(internal, right); int direction = JCV_DIRECTION_LEFT; - if( bottom->p.y > top->p.y ) + if (bottom->p.y > top->p.y) { - jcv_site* temp = bottom; + jcv_site *temp = bottom; bottom = top; top = temp; direction = JCV_DIRECTION_RIGHT; } - jcv_edge* edge = jcv_edge_new(internal, bottom, top); + jcv_edge *edge = jcv_edge_new(internal, bottom, top); edge->next = internal->edges; internal->edges = edge; - jcv_halfedge* he = jcv_halfedge_new(internal, edge, direction); + jcv_halfedge *he = jcv_halfedge_new(internal, edge, direction); jcv_halfedge_link(leftleft, he); jcv_endpos(internal, edge, &vertex, JCV_DIRECTION_RIGHT - direction); jcv_point p; - if( jcv_check_circle_event( leftleft, he, &p ) ) + if (jcv_check_circle_event(leftleft, he, &p)) { jcv_pq_remove(internal->eventqueue, leftleft); - leftleft->vertex = p; - leftleft->y = p.y + jcv_point_dist(&bottom->p, &p); + leftleft->vertex = p; + leftleft->y = p.y + jcv_point_dist(&bottom->p, &p); jcv_pq_push(internal->eventqueue, leftleft); } - if( jcv_check_circle_event( he, rightright, &p ) ) + if (jcv_check_circle_event(he, rightright, &p)) { - he->vertex = p; - he->y = p.y + jcv_point_dist(&bottom->p, &p); + he->vertex = p; + he->y = p.y + jcv_point_dist(&bottom->p, &p); jcv_pq_push(internal->eventqueue, he); } } -static inline jcv_real jcv_floor(jcv_real v) { +static inline jcv_real jcv_floor(jcv_real v) +{ jcv_real i = (jcv_real)(int)v; return (v < i) ? i - 1 : i; } -static inline jcv_real jcv_ceil(jcv_real v) { +static inline jcv_real jcv_ceil(jcv_real v) +{ jcv_real i = (jcv_real)(int)v; return (v > i) ? i + 1 : i; } -static inline jcv_real jcv_min(jcv_real a, jcv_real b) { +static inline jcv_real jcv_min(jcv_real a, jcv_real b) +{ return a < b ? a : b; } -static inline jcv_real jcv_max(jcv_real a, jcv_real b) { +static inline jcv_real jcv_max(jcv_real a, jcv_real b) +{ return a > b ? a : b; } -void jcv_diagram_generate( int num_points, const jcv_point* points, const jcv_rect* rect, const jcv_clipper* clipper, jcv_diagram* d ) +void jcv_diagram_generate(int num_points, const jcv_point *points, const jcv_rect *rect, const jcv_clipper *clipper, jcv_diagram *d) { jcv_diagram_generate_useralloc(num_points, points, rect, clipper, 0, jcv_alloc_fn, jcv_free_fn, d); } typedef union _jcv_cast_align_struct { - char* charp; - void** voidpp; + char *charp; + void **voidpp; } jcv_cast_align_struct; -static inline void jcv_rect_union(jcv_rect* rect, const jcv_point* p) +static inline void jcv_rect_union(jcv_rect *rect, const jcv_point *p) { rect->min.x = jcv_min(rect->min.x, p->x); rect->min.y = jcv_min(rect->min.y, p->y); @@ -1222,7 +1227,7 @@ static inline void jcv_rect_union(jcv_rect* rect, const jcv_point* p) rect->max.y = jcv_max(rect->max.y, p->y); } -static inline void jcv_rect_round(jcv_rect* rect) +static inline void jcv_rect_round(jcv_rect *rect) { rect->min.x = jcv_floor(rect->min.x); rect->min.y = jcv_floor(rect->min.y); @@ -1230,7 +1235,7 @@ static inline void jcv_rect_round(jcv_rect* rect) rect->max.y = jcv_ceil(rect->max.y); } -static inline void jcv_rect_inflate(jcv_rect* rect, jcv_real amount) +static inline void jcv_rect_inflate(jcv_rect *rect, jcv_real amount) { rect->min.x -= amount; rect->min.y -= amount; @@ -1238,10 +1243,10 @@ static inline void jcv_rect_inflate(jcv_rect* rect, jcv_real amount) rect->max.y += amount; } -static int jcv_prune_duplicates(jcv_context_internal* internal, jcv_rect* rect) +static int jcv_prune_duplicates(jcv_context_internal *internal, jcv_rect *rect) { int num_sites = internal->numsites; - jcv_site* sites = internal->sites; + jcv_site *sites = internal->sites; jcv_rect r; r.min.x = r.min.y = JCV_FLT_MAX; @@ -1251,9 +1256,9 @@ static int jcv_prune_duplicates(jcv_context_internal* internal, jcv_rect* rect) // Prune duplicates first for (int i = 0; i < num_sites; i++) { - const jcv_site* s = &sites[i]; + const jcv_site *s = &sites[i]; // Remove duplicates, to avoid anomalies - if( i > 0 && jcv_point_eq(&s->p, &sites[i - 1].p) ) + if (i > 0 && jcv_point_eq(&s->p, &sites[i - 1].p)) { offset++; continue; @@ -1264,16 +1269,17 @@ static int jcv_prune_duplicates(jcv_context_internal* internal, jcv_rect* rect) jcv_rect_union(&r, &s->p); } internal->numsites -= offset; - if (rect) { + if (rect) + { *rect = r; } return offset; } -static int jcv_prune_not_in_shape(jcv_context_internal* internal, jcv_rect* rect) +static int jcv_prune_not_in_shape(jcv_context_internal *internal, jcv_rect *rect) { int num_sites = internal->numsites; - jcv_site* sites = internal->sites; + jcv_site *sites = internal->sites; jcv_rect r; r.min.x = r.min.y = JCV_FLT_MAX; @@ -1282,7 +1288,7 @@ static int jcv_prune_not_in_shape(jcv_context_internal* internal, jcv_rect* rect int offset = 0; for (int i = 0; i < num_sites; i++) { - const jcv_site* s = &sites[i]; + const jcv_site *s = &sites[i]; if (!internal->clipper.test_fn(&internal->clipper, s->p)) { @@ -1295,39 +1301,40 @@ static int jcv_prune_not_in_shape(jcv_context_internal* internal, jcv_rect* rect jcv_rect_union(&r, &s->p); } internal->numsites -= offset; - if (rect) { + if (rect) + { *rect = r; } return offset; } -static jcv_context_internal* jcv_alloc_internal(int num_points, void* userallocctx, FJCVAllocFn allocfn, FJCVFreeFn freefn) +static jcv_context_internal *jcv_alloc_internal(int num_points, void *userallocctx, FJCVAllocFn allocfn, FJCVFreeFn freefn) { // Interesting limits from Euler's equation // Slide 81: https://courses.cs.washington.edu/courses/csep521/01au/lectures/lecture10slides.pdf // Page 3: https://sites.cs.ucsb.edu/~suri/cs235/Voronoi.pdf - int max_num_events = num_points*2; // beachline can have max 2*n-5 parabolas + int max_num_events = num_points * 2; // beachline can have max 2*n-5 parabolas size_t sitessize = (size_t)num_points * sizeof(jcv_site); - size_t memsize = 8u + (size_t)max_num_events * sizeof(void*) + sizeof(jcv_priorityqueue) + sitessize + sizeof(jcv_context_internal); + size_t memsize = 8u + (size_t)max_num_events * sizeof(void *) + sizeof(jcv_priorityqueue) + sitessize + sizeof(jcv_context_internal); - char* originalmem = (char*)allocfn(userallocctx, memsize); + char *originalmem = (char *)allocfn(userallocctx, memsize); memset(originalmem, 0, memsize); // align memory - char* mem = originalmem + 8 - ( (size_t)(originalmem) & 0x7); + char *mem = originalmem + 8 - ((size_t)(originalmem)&0x7); - jcv_context_internal* internal = (jcv_context_internal*)mem; + jcv_context_internal *internal = (jcv_context_internal *)mem; mem += sizeof(jcv_context_internal); - internal->mem = originalmem; + internal->mem = originalmem; internal->memctx = userallocctx; - internal->alloc = allocfn; - internal->free = freefn; + internal->alloc = allocfn; + internal->free = freefn; - internal->sites = (jcv_site*) mem; + internal->sites = (jcv_site *)mem; mem += sitessize; - internal->eventqueue = (jcv_priorityqueue*)mem; + internal->eventqueue = (jcv_priorityqueue *)mem; mem += sizeof(jcv_priorityqueue); jcv_cast_align_struct tmp; @@ -1337,40 +1344,41 @@ static jcv_context_internal* jcv_alloc_internal(int num_points, void* userallocc return internal; } -void jcv_diagram_generate_useralloc(int num_points, const jcv_point* points, const jcv_rect* rect, const jcv_clipper* clipper, void* userallocctx, FJCVAllocFn allocfn, FJCVFreeFn freefn, jcv_diagram* d) +void jcv_diagram_generate_useralloc(int num_points, const jcv_point *points, const jcv_rect *rect, const jcv_clipper *clipper, void *userallocctx, FJCVAllocFn allocfn, FJCVFreeFn freefn, jcv_diagram *d) { - if( d->internal ) - jcv_diagram_free( d ); + if (d->internal) + jcv_diagram_free(d); - jcv_context_internal* internal = jcv_alloc_internal(num_points, userallocctx, allocfn, freefn); + jcv_context_internal *internal = jcv_alloc_internal(num_points, userallocctx, allocfn, freefn); internal->beachline_start = jcv_halfedge_new(internal, 0, 0); internal->beachline_end = jcv_halfedge_new(internal, 0, 0); - internal->beachline_start->left = 0; - internal->beachline_start->right = internal->beachline_end; - internal->beachline_end->left = internal->beachline_start; - internal->beachline_end->right = 0; + internal->beachline_start->left = 0; + internal->beachline_start->right = internal->beachline_end; + internal->beachline_end->left = internal->beachline_start; + internal->beachline_end->right = 0; internal->last_inserted = 0; - int max_num_events = num_points*2; // beachline can have max 2*n-5 parabolas - jcv_pq_create(internal->eventqueue, max_num_events, (void**)internal->eventmem); + int max_num_events = num_points * 2; // beachline can have max 2*n-5 parabolas + jcv_pq_create(internal->eventqueue, max_num_events, (void **)internal->eventmem); internal->numsites = num_points; - jcv_site* sites = internal->sites; + jcv_site *sites = internal->sites; - for( int i = 0; i < num_points; ++i ) + for (int i = 0; i < num_points; ++i) { - sites[i].p = points[i]; - sites[i].edges = 0; - sites[i].index = i; + sites[i].p = points[i]; + sites[i].edges = 0; + sites[i].index = i; } qsort(sites, (size_t)num_points, sizeof(jcv_site), jcv_point_cmp); jcv_clipper box_clipper; - if (clipper == 0) { + if (clipper == 0) + { box_clipper.test_fn = jcv_boxshape_test; box_clipper.clip_fn = jcv_boxshape_clip; box_clipper.fill_fn = jcv_boxshape_fillgaps; @@ -1393,7 +1401,8 @@ void jcv_diagram_generate_useralloc(int num_points, const jcv_point* points, con jcv_prune_not_in_shape(internal, &tmp_rect); // The pruning might have made the bounding box smaller - if (!rect) { + if (!rect) + { // In the case of all sites being all on a horizontal or vertical line, the // rect area will be zero, and the diagram generation will most likely fail jcv_rect_round(&tmp_rect); @@ -1406,33 +1415,33 @@ void jcv_diagram_generate_useralloc(int num_points, const jcv_point* points, con internal->rect = rect ? *rect : tmp_rect; - d->min = internal->rect.min; - d->max = internal->rect.max; + d->min = internal->rect.min; + d->max = internal->rect.max; d->numsites = internal->numsites; d->internal = internal; internal->bottomsite = jcv_nextsite(internal); - jcv_priorityqueue* pq = internal->eventqueue; - jcv_site* site = jcv_nextsite(internal); + jcv_priorityqueue *pq = internal->eventqueue; + jcv_site *site = jcv_nextsite(internal); int finished = 0; - while( !finished ) + while (!finished) { jcv_point lowest_pq_point; - if( !jcv_pq_empty(pq) ) + if (!jcv_pq_empty(pq)) { - jcv_halfedge* he = (jcv_halfedge*)jcv_pq_top(pq); + jcv_halfedge *he = (jcv_halfedge *)jcv_pq_top(pq); lowest_pq_point.x = he->vertex.x; lowest_pq_point.y = he->y; } - if( site != 0 && (jcv_pq_empty(pq) || jcv_point_less(&site->p, &lowest_pq_point) ) ) + if (site != 0 && (jcv_pq_empty(pq) || jcv_point_less(&site->p, &lowest_pq_point))) { jcv_site_event(internal, site); site = jcv_nextsite(internal); } - else if( !jcv_pq_empty(pq) ) + else if (!jcv_pq_empty(pq)) { jcv_circle_event(internal); } @@ -1442,7 +1451,7 @@ void jcv_diagram_generate_useralloc(int num_points, const jcv_point* points, con } } - for( jcv_halfedge* he = internal->beachline_start->right; he != internal->beachline_end; he = he->right ) + for (jcv_halfedge *he = internal->beachline_start->right; he != internal->beachline_end; he = he->right) { jcv_finishline(internal, he->edge); }