21# define JCV_REAL_TYPE float
24# ifndef JCV_REAL_TYPE_EPSILON
25# define JCV_REAL_TYPE_EPSILON FLT_EPSILON
29# define JCV_ATAN2(_Y_, _X_) atan2f(_Y_, _X_)
33# define JCV_SQRT(_X_) sqrtf(_X_)
37# define JCV_PI 3.14159265358979323846264338327950288f
41# define JCV_FLT_MAX 3.402823466e+38F
44# ifndef JCV_EDGE_INTERSECT_THRESHOLD
46# define JCV_EDGE_INTERSECT_THRESHOLD 1.0e-10F
51 typedef JCV_REAL_TYPE jcv_real;
62 typedef struct jcv_context_internal_ jcv_context_internal;
74 typedef void (*jcv_clip_fillgap_fn)(
const jcv_clipper* clipper, jcv_context_internal* allocator,
jcv_site* s);
86 typedef void* (*FJCVAllocFn)(
void* userctx,
size_t size);
87 typedef void (*FJCVFreeFn)(
void* userctx,
void* p);
90 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);
116 extern void jcv_boxshape_fillgaps(
const jcv_clipper* clipper, jcv_context_internal* allocator,
jcv_site* s);
119# ifndef JCV_DISABLE_STRUCT_PACKING
120# pragma pack(push, 1)
177 jcv_clip_test_point_fn test_fn;
178 jcv_clip_edge_fn clip_fn;
179 jcv_clip_fillgap_fn fill_fn;
187 jcv_context_internal* internal;
193# ifndef JCV_DISABLE_STRUCT_PACKING
203#ifdef JC_VORONOI_IMPLEMENTATION
204# undef JC_VORONOI_IMPLEMENTATION
210# if defined(_MSC_VER) && !defined(__cplusplus)
211# define inline __inline
214static const int JCV_DIRECTION_LEFT = 0;
215static const int JCV_DIRECTION_RIGHT = 1;
216static const jcv_real JCV_INVALID_VALUE = (jcv_real)-JCV_FLT_MAX;
220static inline jcv_real jcv_abs(jcv_real v)
222 return (v < 0) ? -v : v;
225static inline int jcv_real_eq(jcv_real a, jcv_real b)
227 return jcv_abs(a - b) < JCV_REAL_TYPE_EPSILON;
230static inline jcv_real jcv_real_to_int(jcv_real v)
232 return (
sizeof(jcv_real) == 4) ? (jcv_real)(
int)v : (jcv_real)(
long long)v;
236static inline jcv_real jcv_floor(jcv_real v)
238 jcv_real i = jcv_real_to_int(v);
239 return (v < i) ? i - 1 : i;
243static inline jcv_real jcv_ceil(jcv_real v)
245 jcv_real i = jcv_real_to_int(v);
246 return (v > i) ? i + 1 : i;
249static inline jcv_real jcv_min(jcv_real a, jcv_real b)
251 return a < b ? a : b;
254static inline jcv_real jcv_max(jcv_real a, jcv_real b)
256 return a > b ? a : b;
261static inline int jcv_point_cmp(
const void* p1,
const void* p2)
265 return (s1->y != s2->y) ? (s1->y < s2->y ? -1 : 1) : (s1->x < s2->x ? -1 : 1);
270 return (pt1->y == pt2->y) ? (pt1->x < pt2->x) : pt1->y < pt2->y;
275 return jcv_real_eq(pt1->y, pt2->y) && jcv_real_eq(pt1->x, pt2->x);
280 return pt->x == min->x || pt->y == min->y || pt->x == max->x || pt->y == max->y;
285static const int JCV_EDGE_LEFT = 1;
286static const int JCV_EDGE_RIGHT = 2;
287static const int JCV_EDGE_BOTTOM = 4;
288static const int JCV_EDGE_TOP = 8;
290static const int JCV_CORNER_NONE = 0;
291static const int JCV_CORNER_TOP_LEFT = 1;
292static const int JCV_CORNER_BOTTOM_LEFT = 2;
293static const int JCV_CORNER_BOTTOM_RIGHT = 3;
294static const int JCV_CORNER_TOP_RIGHT = 4;
300 flags |= JCV_EDGE_LEFT;
301 else if (pt->x == max->x)
302 flags |= JCV_EDGE_RIGHT;
304 flags |= JCV_EDGE_BOTTOM;
305 else if (pt->y == max->y)
306 flags |= JCV_EDGE_TOP;
310static inline int jcv_edge_flags_to_corner(
int edge_flags)
312# define TEST_FLAGS(_FLAGS, _RETVAL) \
313 if ((_FLAGS) == edge_flags) \
315 TEST_FLAGS(JCV_EDGE_TOP | JCV_EDGE_LEFT, JCV_CORNER_TOP_LEFT);
316 TEST_FLAGS(JCV_EDGE_TOP | JCV_EDGE_RIGHT, JCV_CORNER_TOP_RIGHT);
317 TEST_FLAGS(JCV_EDGE_BOTTOM | JCV_EDGE_LEFT, JCV_CORNER_BOTTOM_LEFT);
318 TEST_FLAGS(JCV_EDGE_BOTTOM | JCV_EDGE_RIGHT, JCV_CORNER_BOTTOM_RIGHT);
323static inline int jcv_is_corner(
int corner)
328static inline int jcv_corner_rotate_90(
int corner)
331 corner = (corner + 1) % 4;
337 if (corner == JCV_CORNER_TOP_LEFT)
342 else if (corner == JCV_CORNER_TOP_RIGHT)
347 else if (corner == JCV_CORNER_BOTTOM_LEFT)
352 else if (corner == JCV_CORNER_BOTTOM_RIGHT)
359 p.x = JCV_INVALID_VALUE;
360 p.y = JCV_INVALID_VALUE;
367 jcv_real diffx = pt1->x - pt2->x;
368 jcv_real diffy = pt1->y - pt2->y;
369 return diffx * diffx + diffy * diffy;
374 return (jcv_real)(JCV_SQRT(jcv_point_dist_sq(pt1, pt2)));
379# ifndef JCV_DISABLE_STRUCT_PACKING
380# pragma pack(push, 1)
383typedef struct jcv_halfedge_
386 struct jcv_halfedge_* left;
387 struct jcv_halfedge_* right;
394typedef struct jcv_memoryblock_
397 struct jcv_memoryblock_* next;
402typedef int (*FJCVPriorityQueuePrint)(
const void* node,
int pos);
404typedef struct jcv_priorityqueue_
413struct jcv_context_internal_
417 jcv_halfedge* beachline_start;
418 jcv_halfedge* beachline_end;
419 jcv_halfedge* last_inserted;
420 jcv_priorityqueue* eventqueue;
428 jcv_memoryblock* memblocks;
430 jcv_halfedge* halfedgepool;
441# ifndef JCV_DISABLE_STRUCT_PACKING
447 jcv_context_internal* internal = d->internal;
448 void* memctx = internal->memctx;
449 FJCVFreeFn freefn = internal->free;
450 while (internal->memblocks)
452 jcv_memoryblock* p = internal->memblocks;
453 internal->memblocks = internal->memblocks->next;
457 freefn(memctx, internal->mem);
462 return diagram->internal->sites;
468 e.next = diagram->internal->edges;
469 return jcv_diagram_get_next_edge(&e);
475 while (e != 0 && jcv_point_eq(&
e->pos[0], &
e->pos[1]))
485 iter->sentinel = jcv_diagram_get_edges(diagram);
492 iter->current = iter->sentinel;
501 iter->current = jcv_diagram_get_next_edge(iter->current);
504 while (iter->current && (iter->current->sites[0] == 0 || iter->current->sites[1] == 0))
506 iter->current = jcv_diagram_get_next_edge(iter->current);
512 next->edge = iter->current;
513 next->sites[0] = next->edge->sites[0];
514 next->sites[1] = next->edge->sites[1];
515 next->pos[0] = next->sites[0]->p;
516 next->pos[1] = next->sites[1]->p;
520static inline void* jcv_align(
void* value,
size_t alignment)
522 return (
void*)(((uintptr_t)value + (alignment - 1)) & ~(alignment - 1));
525static void* jcv_alloc(jcv_context_internal* internal,
size_t size)
527 if (!internal->memblocks || internal->memblocks->sizefree < (size +
sizeof(
void*)))
529 size_t blocksize = 16 * 1024;
530 jcv_memoryblock* block = (jcv_memoryblock*)internal->alloc(internal->memctx, blocksize);
531 size_t offset =
sizeof(jcv_memoryblock);
532 block->sizefree = blocksize - offset;
533 block->next = internal->memblocks;
534 block->memory = ((
char*)block) + offset;
535 internal->memblocks = block;
537 void* p_raw = internal->memblocks->memory;
538 void* p_aligned = jcv_align(p_raw,
sizeof(
void*));
539 size += (uintptr_t)p_aligned - (uintptr_t)p_raw;
540 internal->memblocks->memory += size;
541 internal->memblocks->sizefree -= size;
545static jcv_edge* jcv_alloc_edge(jcv_context_internal* internal)
550static jcv_halfedge* jcv_alloc_halfedge(jcv_context_internal* internal)
552 if (internal->halfedgepool)
554 jcv_halfedge* edge = internal->halfedgepool;
555 internal->halfedgepool = internal->halfedgepool->right;
559 return (jcv_halfedge*)jcv_alloc(internal,
sizeof(jcv_halfedge));
562static jcv_graphedge* jcv_alloc_graphedge(jcv_context_internal* internal)
567static void* jcv_alloc_fn(
void* memctx,
size_t size)
573static void jcv_free_fn(
void* memctx,
void* p)
581static inline int jcv_is_valid(
const jcv_point* p)
583 return (p->x != JCV_INVALID_VALUE || p->y != JCV_INVALID_VALUE) ? 1 : 0;
591 e->pos[0].x = JCV_INVALID_VALUE;
592 e->pos[0].y = JCV_INVALID_VALUE;
593 e->pos[1].x = JCV_INVALID_VALUE;
594 e->pos[1].y = JCV_INVALID_VALUE;
611 jcv_real dx = s2->p.x - s1->p.x;
612 jcv_real dy = s2->p.y - s1->p.y;
613 int dx_is_larger = (dx * dx) > (dy * dy);
616 e->c = dx * (s1->p.x + dx * (jcv_real)0.5) + dy * (s1->p.y + dy * (jcv_real)0.5);
635 return p.x >= clipper->min.x && p.x <= clipper->max.x &&
636 p.y >= clipper->min.y && p.y <= clipper->max.y;
643 jcv_real pxmin = clipper->min.x;
644 jcv_real pxmax = clipper->max.x;
645 jcv_real pymin = clipper->min.y;
646 jcv_real pymax = clipper->max.y;
648 jcv_real x1, y1, x2, y2;
651 if (
e->a == (jcv_real)1 &&
e->b >= (jcv_real)0)
653 s1 = jcv_is_valid(&
e->pos[1]) ? &
e->pos[1] : 0;
654 s2 = jcv_is_valid(&
e->pos[0]) ? &
e->pos[0] : 0;
658 s1 = jcv_is_valid(&
e->pos[0]) ? &
e->pos[0] : 0;
659 s2 = jcv_is_valid(&
e->pos[1]) ? &
e->pos[1] : 0;
662 if (
e->a == (jcv_real)1)
665 if (s1 != 0 && s1->y > pymin)
673 x1 =
e->c -
e->b * y1;
675 if (s2 != 0 && s2->y < pymax)
682 x2 = (
e->c) - (
e->b) * y2;
691 y1 = (
e->c - x1) /
e->b;
696 y1 = (
e->c - x1) /
e->b;
701 y2 = (
e->c - x2) /
e->b;
706 y2 = (
e->c - x2) /
e->b;
712 if (s1 != 0 && s1->x > pxmin)
718 y1 =
e->c -
e->a * x1;
720 if (s2 != 0 && s2->x < pxmax)
726 y2 =
e->c -
e->a * x2;
735 x1 = (
e->c - y1) /
e->a;
740 x1 = (
e->c - y1) /
e->a;
745 x2 = (
e->c - y2) /
e->a;
750 x2 = (
e->c - y2) /
e->a;
760 return (x1 == x2 && y1 == y2) ? 0 : 1;
765static int jcv_edge_clipline(jcv_context_internal* internal,
jcv_edge* e)
767 return internal->clipper.clip_fn(&internal->clipper, e);
773 jcv_edge_create(e, s1, s2);
780static void jcv_halfedge_link(jcv_halfedge* edge, jcv_halfedge* newedge)
782 newedge->left = edge;
783 newedge->right = edge->right;
784 edge->right->left = newedge;
785 edge->right = newedge;
788static inline void jcv_halfedge_unlink(jcv_halfedge* he)
790 he->left->right = he->right;
791 he->right->left = he->left;
796static inline jcv_halfedge* jcv_halfedge_new(jcv_context_internal* internal,
jcv_edge* e,
int direction)
798 jcv_halfedge* he = jcv_alloc_halfedge(internal);
802 he->direction = direction;
810static void jcv_halfedge_delete(jcv_context_internal* internal, jcv_halfedge* he)
812 he->right = internal->halfedgepool;
813 internal->halfedgepool = he;
816static inline jcv_site* jcv_halfedge_leftsite(
const jcv_halfedge* he)
818 return he->edge->sites[he->direction];
821static inline jcv_site* jcv_halfedge_rightsite(
const jcv_halfedge* he)
823 return he->edge ? he->edge->sites[1 - he->direction] : 0;
826static int jcv_halfedge_rightof(
const jcv_halfedge* he,
const jcv_point* p)
831 int right_of_site = (p->x > topsite->p.x) ? 1 : 0;
832 if (right_of_site && he->direction == JCV_DIRECTION_LEFT)
834 if (!right_of_site && he->direction == JCV_DIRECTION_RIGHT)
837 jcv_real dxp, dyp, dxs, t1, t2, t3, yl;
840 if (
e->a == (jcv_real)1)
842 dyp = p->y - topsite->p.y;
843 dxp = p->x - topsite->p.x;
845 if ((!right_of_site & (
e->b < (jcv_real)0)) | (right_of_site & (
e->b >= (jcv_real)0)))
847 above = dyp >=
e->b * dxp;
852 above = (p->x + p->y *
e->b) >
e->c;
853 if (
e->b < (jcv_real)0)
860 dxs = topsite->p.x -
e->sites[0]->p.x;
861 above =
e->b * (dxp * dxp - dyp * dyp) < dxs * dyp * ((jcv_real)1 + (jcv_real)2 * dxp / dxs +
e->b *
e->b);
862 if (
e->b < (jcv_real)0)
868 yl =
e->c -
e->a * p->x;
870 t2 = p->x - topsite->p.x;
871 t3 = yl - topsite->p.y;
872 above = t1 * t1 > (t2 * t2 + t3 * t3);
874 return (he->direction == JCV_DIRECTION_LEFT ? above : !above);
879static inline int jcv_halfedge_compare(
const jcv_halfedge* he1,
const jcv_halfedge* he2)
881 return (he1->y == he2->y) ? he1->vertex.x > he2->vertex.x : he1->y > he2->y;
884static int jcv_halfedge_intersect(
const jcv_halfedge* he1,
const jcv_halfedge* he2,
jcv_point* out)
889 jcv_real d = e1->a * e2->b - e1->b * e2->a;
890 if (((jcv_real)-JCV_EDGE_INTERSECT_THRESHOLD < d && d < (jcv_real)JCV_EDGE_INTERSECT_THRESHOLD))
894 out->x = (e1->c * e2->b - e1->b * e2->c) / d;
895 out->y = (e1->a * e2->c - e1->c * e2->a) / d;
898 const jcv_halfedge* he;
899 if (jcv_point_less(&e1->sites[1]->p, &e2->sites[1]->p))
910 int right_of_site = out->x >=
e->sites[1]->p.x;
911 if ((right_of_site && he->direction == JCV_DIRECTION_LEFT) || (!right_of_site && he->direction == JCV_DIRECTION_RIGHT))
922static int jcv_pq_moveup(jcv_priorityqueue* pq,
int pos)
924 jcv_halfedge** items = (jcv_halfedge**)pq->items;
925 jcv_halfedge* node = items[pos];
927 for (
int parent = (pos >> 1);
928 pos > 1 && jcv_halfedge_compare(items[parent], node);
929 pos = parent, parent = parent >> 1)
931 items[pos] = items[parent];
932 items[pos]->pqpos = pos;
940static int jcv_pq_maxchild(jcv_priorityqueue* pq,
int pos)
942 int child = pos << 1;
943 if (child >= pq->numitems)
945 jcv_halfedge** items = (jcv_halfedge**)pq->items;
946 if ((child + 1) < pq->numitems && jcv_halfedge_compare(items[child], items[child + 1]))
951static int jcv_pq_movedown(jcv_priorityqueue* pq,
int pos)
953 jcv_halfedge** items = (jcv_halfedge**)pq->items;
954 jcv_halfedge* node = items[pos];
956 int child = jcv_pq_maxchild(pq, pos);
957 while (child && jcv_halfedge_compare(node, items[child]))
959 items[pos] = items[child];
960 items[pos]->pqpos = pos;
962 child = jcv_pq_maxchild(pq, pos);
966 items[pos]->pqpos = pos;
970static void jcv_pq_create(jcv_priorityqueue* pq,
int capacity,
void** buffer)
972 pq->maxnumitems = capacity;
977static int jcv_pq_empty(jcv_priorityqueue* pq)
979 return pq->numitems == 1 ? 1 : 0;
982static int jcv_pq_push(jcv_priorityqueue* pq,
void* node)
984 assert(pq->numitems < pq->maxnumitems);
985 int n = pq->numitems++;
987 return jcv_pq_moveup(pq, n);
990static void* jcv_pq_pop(jcv_priorityqueue* pq)
992 void* node = pq->items[1];
993 pq->items[1] = pq->items[--pq->numitems];
994 jcv_pq_movedown(pq, 1);
998static void* jcv_pq_top(jcv_priorityqueue* pq)
1000 return pq->items[1];
1003static void jcv_pq_remove(jcv_priorityqueue* pq, jcv_halfedge* node)
1005 if (pq->numitems == 1)
1007 int pos = node->pqpos;
1011 jcv_halfedge** items = (jcv_halfedge**)pq->items;
1013 items[pos] = items[--pq->numitems];
1014 if (jcv_halfedge_compare(node, items[pos]))
1015 jcv_pq_moveup(pq, pos);
1017 jcv_pq_movedown(pq, pos);
1023static inline jcv_site* jcv_nextsite(jcv_context_internal* internal)
1025 return (internal->currentsite < internal->numsites) ? &internal->sites[internal->currentsite++] : 0;
1028static jcv_halfedge* jcv_get_edge_above_x(jcv_context_internal* internal,
const jcv_point* p)
1033 jcv_halfedge* he = internal->last_inserted;
1036 if (p->x < (internal->rect.max.x - internal->rect.min.x) / 2)
1037 he = internal->beachline_start;
1039 he = internal->beachline_end;
1043 if (he == internal->beachline_start || (he != internal->beachline_end && jcv_halfedge_rightof(he, p)))
1048 }
while (he != internal->beachline_end && jcv_halfedge_rightof(he, p));
1057 }
while (he != internal->beachline_start && !jcv_halfedge_rightof(he, p));
1063static int jcv_check_circle_event(
const jcv_halfedge* he1,
const jcv_halfedge* he2,
jcv_point* vertex)
1067 if (e1 == 0 || e2 == 0 || e1->sites[1] == e2->sites[1])
1072 return jcv_halfedge_intersect(he1, he2, vertex);
1075static void jcv_site_event(jcv_context_internal* internal,
jcv_site* site)
1077 jcv_halfedge* left = jcv_get_edge_above_x(internal, &site->p);
1078 jcv_halfedge* right = left->right;
1079 jcv_site* bottom = jcv_halfedge_rightsite(left);
1081 bottom = internal->bottomsite;
1083 jcv_edge* edge = jcv_edge_new(internal, bottom, site);
1084 edge->next = internal->edges;
1085 internal->edges = edge;
1087 jcv_halfedge* edge1 = jcv_halfedge_new(internal, edge, JCV_DIRECTION_LEFT);
1088 jcv_halfedge* edge2 = jcv_halfedge_new(internal, edge, JCV_DIRECTION_RIGHT);
1090 jcv_halfedge_link(left, edge1);
1091 jcv_halfedge_link(edge1, edge2);
1093 internal->last_inserted = right;
1096 if (jcv_check_circle_event(left, edge1, &p))
1098 jcv_pq_remove(internal->eventqueue, left);
1100 left->y = p.y + jcv_point_dist(&site->p, &p);
1101 jcv_pq_push(internal->eventqueue, left);
1103 if (jcv_check_circle_event(edge2, right, &p))
1106 edge2->y = p.y + jcv_point_dist(&site->p, &p);
1107 jcv_pq_push(internal->eventqueue, edge2);
1114 return (b->x - a->x) * (c->y - a->y) - (b->y - a->y) * (c->x - a->x);
1120 jcv_real half = 1 / (jcv_real)2;
1121 jcv_real x = (edge->pos[0].x + edge->pos[1].x) * half;
1122 jcv_real y = (edge->pos[0].y + edge->pos[1].y) * half;
1123 jcv_real diffy = y - site->p.y;
1124 jcv_real angle = JCV_ATAN2(diffy, x - site->p.x);
1126 angle = angle + 2 * JCV_PI;
1127 return (jcv_real)angle;
1132 return jcv_real_eq(a->angle, b->angle) && jcv_point_eq(&a->pos[0], &b->pos[0]) && jcv_point_eq(&a->pos[1], &b->pos[1]);
1139 if (site->edges == 0 || site->edges->angle >= edge->angle)
1141 edge->next = site->edges;
1148 while (current->next != 0 && current->next->angle < edge->angle)
1150 current = current->next;
1153 edge->next = current->next;
1154 current->next = edge;
1158 if (prev && jcv_graphedge_eq(prev, edge))
1160 prev->next = edge->next;
1162 else if (edge->next && jcv_graphedge_eq(edge, edge->next))
1164 edge->next = edge->next->next;
1168static void jcv_finishline(jcv_context_internal* internal,
jcv_edge* e)
1170 if (!jcv_edge_clipline(internal, e))
1176 int flip = jcv_determinant(&
e->sites[0]->p, &
e->pos[0], &
e->pos[1]) > (jcv_real)0 ? 0 : 1;
1178 for (
int i = 0; i < 2; ++i)
1184 ge->neighbor =
e->sites[1 - i];
1185 ge->pos[flip] =
e->pos[i];
1186 ge->pos[1 - flip] =
e->pos[1 - i];
1187 ge->angle = jcv_calc_sort_metric(
e->sites[i], ge);
1189 jcv_sortedges_insert(
e->sites[i], ge);
1194static void jcv_endpos(jcv_context_internal* internal,
jcv_edge* e,
const jcv_point* p,
int direction)
1196 e->pos[direction] = *p;
1198 if (!jcv_is_valid(&
e->pos[1 - direction]))
1201 jcv_finishline(internal, e);
1207 gap->pos[0] = current->pos[1];
1209 if (current->pos[1].x < internal->rect.max.x && current->pos[1].y == internal->rect.min.y)
1211 gap->pos[1].x = internal->rect.max.x;
1212 gap->pos[1].y = internal->rect.min.y;
1214 else if (current->pos[1].x > internal->rect.min.x && current->pos[1].y == internal->rect.max.y)
1216 gap->pos[1].x = internal->rect.min.x;
1217 gap->pos[1].y = internal->rect.max.y;
1219 else if (current->pos[1].y > internal->rect.min.y && current->pos[1].x == internal->rect.min.x)
1221 gap->pos[1].x = internal->rect.min.x;
1222 gap->pos[1].y = internal->rect.min.y;
1224 else if (current->pos[1].y < internal->rect.max.y && current->pos[1].x == internal->rect.max.x)
1226 gap->pos[1].x = internal->rect.max.x;
1227 gap->pos[1].y = internal->rect.max.y;
1230 gap->angle = jcv_calc_sort_metric(site, gap);
1235 jcv_edge* edge = jcv_alloc_edge(internal);
1236 edge->pos[0] = ge->pos[0];
1237 edge->pos[1] = ge->pos[1];
1238 edge->sites[0] = site;
1240 edge->a = edge->b = edge->c = 0;
1241 edge->next = internal->edges;
1242 internal->edges = edge;
1246void jcv_boxshape_fillgaps(
const jcv_clipper* clipper, jcv_context_internal* allocator,
jcv_site* site)
1253 assert(allocator->numsites == 1);
1257 gap->pos[0] = clipper->min;
1258 gap->pos[1].x = clipper->max.x;
1259 gap->pos[1].y = clipper->min.y;
1260 gap->angle = jcv_calc_sort_metric(site, gap);
1262 gap->edge = jcv_create_gap_edge(allocator, site, gap);
1272 jcv_create_corner_edge(allocator, site, current, gap);
1273 gap->edge = jcv_create_gap_edge(allocator, site, gap);
1275 gap->next = current->next;
1276 current->next = gap;
1281 while (current && next)
1283 int current_edge_flags = jcv_get_edge_flags(¤t->pos[1], &clipper->min, &clipper->max);
1284 if (current_edge_flags && !jcv_point_eq(¤t->pos[1], &next->pos[0]))
1292 int next_edge_flags = jcv_get_edge_flags(&next->pos[0], &clipper->min, &clipper->max);
1293 if (current_edge_flags & next_edge_flags)
1298 gap->pos[0] = current->pos[1];
1299 gap->pos[1] = next->pos[0];
1300 gap->angle = jcv_calc_sort_metric(site, gap);
1301 gap->edge = jcv_create_gap_edge(allocator, site, gap);
1303 gap->next = current->next;
1304 current->next = gap;
1309 int corner_flag = jcv_edge_flags_to_corner(current_edge_flags);
1313 corner_flag = jcv_corner_rotate_90(corner_flag);
1319 if (current_edge_flags == JCV_EDGE_TOP)
1321 corner_flag = JCV_CORNER_TOP_LEFT;
1323 else if (current_edge_flags == JCV_EDGE_LEFT)
1325 corner_flag = JCV_CORNER_BOTTOM_LEFT;
1327 else if (current_edge_flags == JCV_EDGE_BOTTOM)
1329 corner_flag = JCV_CORNER_BOTTOM_RIGHT;
1331 else if (current_edge_flags == JCV_EDGE_RIGHT)
1333 corner_flag = JCV_CORNER_TOP_RIGHT;
1336 jcv_point corner = jcv_corner_to_point(corner_flag, &clipper->min, &clipper->max);
1340 gap->pos[0] = current->pos[1];
1341 gap->pos[1] = corner;
1342 gap->angle = jcv_calc_sort_metric(site, gap);
1343 gap->edge = jcv_create_gap_edge(allocator, site, gap);
1345 gap->next = current->next;
1346 current->next = gap;
1350 current = current->next;
1353 next = current->next;
1364 jcv_context_internal* internal = diagram->internal;
1365 if (!internal->clipper.fill_fn)
1368 for (
int i = 0; i < internal->numsites; ++i)
1370 jcv_site* site = &internal->sites[i];
1371 internal->clipper.fill_fn(&internal->clipper, internal, site);
1376static void jcv_circle_event(jcv_context_internal* internal)
1378 jcv_halfedge* left = (jcv_halfedge*)jcv_pq_pop(internal->eventqueue);
1380 jcv_halfedge* leftleft = left->left;
1381 jcv_halfedge* right = left->right;
1382 jcv_halfedge* rightright = right->right;
1383 jcv_site* bottom = jcv_halfedge_leftsite(left);
1384 jcv_site* top = jcv_halfedge_rightsite(right);
1387 jcv_endpos(internal, left->edge, &vertex, left->direction);
1388 jcv_endpos(internal, right->edge, &vertex, right->direction);
1390 internal->last_inserted = rightright;
1392 jcv_pq_remove(internal->eventqueue, right);
1393 jcv_halfedge_unlink(left);
1394 jcv_halfedge_unlink(right);
1395 jcv_halfedge_delete(internal, left);
1396 jcv_halfedge_delete(internal, right);
1398 int direction = JCV_DIRECTION_LEFT;
1399 if (bottom->p.y > top->p.y)
1404 direction = JCV_DIRECTION_RIGHT;
1407 jcv_edge* edge = jcv_edge_new(internal, bottom, top);
1408 edge->next = internal->edges;
1409 internal->edges = edge;
1411 jcv_halfedge* he = jcv_halfedge_new(internal, edge, direction);
1412 jcv_halfedge_link(leftleft, he);
1413 jcv_endpos(internal, edge, &vertex, JCV_DIRECTION_RIGHT - direction);
1416 if (jcv_check_circle_event(leftleft, he, &p))
1418 jcv_pq_remove(internal->eventqueue, leftleft);
1419 leftleft->vertex = p;
1420 leftleft->y = p.y + jcv_point_dist(&bottom->p, &p);
1421 jcv_pq_push(internal->eventqueue, leftleft);
1423 if (jcv_check_circle_event(he, rightright, &p))
1426 he->y = p.y + jcv_point_dist(&bottom->p, &p);
1427 jcv_pq_push(internal->eventqueue, he);
1433 jcv_diagram_generate_useralloc(num_points, points, rect, clipper, 0, jcv_alloc_fn, jcv_free_fn, d);
1436typedef union jcv_cast_align_struct_
1440} jcv_cast_align_struct;
1444 rect->min.x = jcv_min(rect->min.x, p->x);
1445 rect->min.y = jcv_min(rect->min.y, p->y);
1446 rect->max.x = jcv_max(rect->max.x, p->x);
1447 rect->max.y = jcv_max(rect->max.y, p->y);
1450static inline void jcv_rect_round(
jcv_rect* rect)
1452 rect->min.x = jcv_floor(rect->min.x);
1453 rect->min.y = jcv_floor(rect->min.y);
1454 rect->max.x = jcv_ceil(rect->max.x);
1455 rect->max.y = jcv_ceil(rect->max.y);
1458static inline void jcv_rect_inflate(
jcv_rect* rect, jcv_real amount)
1460 rect->min.x -= amount;
1461 rect->min.y -= amount;
1462 rect->max.x += amount;
1463 rect->max.y += amount;
1466static int jcv_prune_duplicates(jcv_context_internal* internal,
jcv_rect* rect)
1468 int num_sites = internal->numsites;
1472 r.min.x = r.min.y = JCV_FLT_MAX;
1473 r.max.x = r.max.y = -JCV_FLT_MAX;
1477 for (
int i = 0; i < num_sites; i++)
1481 if (i > 0 && jcv_point_eq(&s->p, &sites[i - 1].p))
1487 sites[i - offset] = sites[i];
1489 jcv_rect_union(&r, &s->p);
1491 internal->numsites -= offset;
1499static int jcv_prune_not_in_shape(jcv_context_internal* internal,
jcv_rect* rect)
1501 int num_sites = internal->numsites;
1505 r.min.x = r.min.y = JCV_FLT_MAX;
1506 r.max.x = r.max.y = -JCV_FLT_MAX;
1509 for (
int i = 0; i < num_sites; i++)
1513 if (!internal->clipper.test_fn(&internal->clipper, s->p))
1519 sites[i - offset] = sites[i];
1521 jcv_rect_union(&r, &s->p);
1523 internal->numsites -= offset;
1531static jcv_context_internal* jcv_alloc_internal(
int num_points,
void* userallocctx, FJCVAllocFn allocfn, FJCVFreeFn freefn)
1536 size_t eventssize = (size_t)(num_points * 2) *
sizeof(
void*);
1537 size_t sitessize = (size_t)num_points *
sizeof(
jcv_site);
1538 size_t memsize =
sizeof(jcv_priorityqueue) + eventssize + sitessize +
sizeof(jcv_context_internal) + 16u;
1540 char* originalmem = (
char*)allocfn(userallocctx, memsize);
1541 memset(originalmem, 0, memsize);
1544 char* mem = (
char*)jcv_align(originalmem,
sizeof(
void*));
1546 jcv_context_internal* internal = (jcv_context_internal*)mem;
1547 mem +=
sizeof(jcv_context_internal);
1548 internal->mem = originalmem;
1549 internal->memctx = userallocctx;
1550 internal->alloc = allocfn;
1551 internal->free = freefn;
1553 mem = (
char*)jcv_align(mem,
sizeof(
void*));
1557 mem = (
char*)jcv_align(mem,
sizeof(
void*));
1558 internal->eventqueue = (jcv_priorityqueue*)mem;
1559 mem +=
sizeof(jcv_priorityqueue);
1560 assert(((uintptr_t)mem & (
sizeof(
void*) - 1)) == 0);
1562 jcv_cast_align_struct tmp;
1564 internal->eventmem = tmp.voidpp;
1566 assert((mem + eventssize) <= (originalmem + memsize));
1571void 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)
1574 jcv_diagram_free(d);
1576 jcv_context_internal* internal = jcv_alloc_internal(num_points, userallocctx, allocfn, freefn);
1578 internal->beachline_start = jcv_halfedge_new(internal, 0, 0);
1579 internal->beachline_end = jcv_halfedge_new(internal, 0, 0);
1581 internal->beachline_start->left = 0;
1582 internal->beachline_start->right = internal->beachline_end;
1583 internal->beachline_end->left = internal->beachline_start;
1584 internal->beachline_end->right = 0;
1586 internal->last_inserted = 0;
1588 int max_num_events = num_points * 2;
1589 jcv_pq_create(internal->eventqueue, max_num_events, (
void**)internal->eventmem);
1591 internal->numsites = num_points;
1594 for (
int i = 0; i < num_points; ++i)
1596 sites[i].p = points[i];
1601 qsort(sites, (
size_t)num_points,
sizeof(
jcv_site), jcv_point_cmp);
1606 box_clipper.test_fn = jcv_boxshape_test;
1607 box_clipper.clip_fn = jcv_boxshape_clip;
1608 box_clipper.fill_fn = jcv_boxshape_fillgaps;
1609 clipper = &box_clipper;
1611 internal->clipper = *clipper;
1614 tmp_rect.min.x = tmp_rect.min.y = JCV_FLT_MAX;
1615 tmp_rect.max.x = tmp_rect.max.y = -JCV_FLT_MAX;
1616 jcv_prune_duplicates(internal, &tmp_rect);
1619 if (internal->clipper.test_fn)
1622 internal->clipper.min = rect ? rect->min : tmp_rect.min;
1623 internal->clipper.max = rect ? rect->max : tmp_rect.max;
1625 jcv_prune_not_in_shape(internal, &tmp_rect);
1632 jcv_rect_round(&tmp_rect);
1633 jcv_rect_inflate(&tmp_rect, 10);
1635 internal->clipper.min = tmp_rect.min;
1636 internal->clipper.max = tmp_rect.max;
1640 internal->rect = rect ? *rect : tmp_rect;
1642 d->min = internal->rect.min;
1643 d->max = internal->rect.max;
1644 d->numsites = internal->numsites;
1645 d->internal = internal;
1647 internal->bottomsite = jcv_nextsite(internal);
1649 jcv_priorityqueue* pq = internal->eventqueue;
1650 jcv_site* site = jcv_nextsite(internal);
1656 if (!jcv_pq_empty(pq))
1658 jcv_halfedge* he = (jcv_halfedge*)jcv_pq_top(pq);
1659 lowest_pq_point.x = he->vertex.x;
1660 lowest_pq_point.y = he->y;
1663 if (site != 0 && (jcv_pq_empty(pq) || jcv_point_less(&site->p, &lowest_pq_point)))
1665 jcv_site_event(internal, site);
1666 site = jcv_nextsite(internal);
1668 else if (!jcv_pq_empty(pq))
1670 jcv_circle_event(internal);
1678 for (jcv_halfedge* he = internal->beachline_start->right; he != internal->beachline_end; he = he->right)
1680 jcv_finishline(internal, he->edge);
constexpr TYPE e()
Returns the natural constant e.
Definition jc_voronoi.h:176
Definition jc_voronoi.h:163
Definition jc_voronoi.h:157
Definition jc_voronoi.h:186
Definition jc_voronoi.h:147
Definition jc_voronoi.h:130
Definition jc_voronoi.h:124
Definition jc_voronoi.h:170
Definition jc_voronoi.h:139