voronoi.c 3.0 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103
  1. /*************************************************************************
  2. * Copyright (c) 2011 AT&T Intellectual Property
  3. * All rights reserved. This program and the accompanying materials
  4. * are made available under the terms of the Eclipse Public License v1.0
  5. * which accompanies this distribution, and is available at
  6. * https://www.eclipse.org/legal/epl-v10.html
  7. *
  8. * Contributors: Details at https://graphviz.org
  9. *************************************************************************/
  10. #include <neatogen/mem.h>
  11. #include <neatogen/geometry.h>
  12. #include <neatogen/edges.h>
  13. #include <neatogen/hedges.h>
  14. #include <neatogen/heap.h>
  15. #include <neatogen/voronoi.h>
  16. void voronoi(Site *(*nextsite)(void *context), void *context) {
  17. Site *newsite, *bot, *top, *temp, *p;
  18. Site *v;
  19. Point newintstar = {0};
  20. char pm;
  21. Halfedge *lbnd, *rbnd, *llbnd, *rrbnd, *bisector;
  22. Edge *e;
  23. edgeinit();
  24. siteinit();
  25. pq_t *pq = PQinitialize();
  26. bottomsite = nextsite(context);
  27. ELinitialize();
  28. newsite = nextsite(context);
  29. while (1) {
  30. if (!PQempty(pq))
  31. newintstar = PQ_min(pq);
  32. if (newsite != NULL &&
  33. (PQempty(pq) || newsite->coord.y < newintstar.y ||
  34. (newsite->coord.y ==newintstar.y && newsite->coord.x < newintstar.x))) {
  35. /* new site is smallest */
  36. lbnd = ELleftbnd(&newsite->coord);
  37. rbnd = ELright(lbnd);
  38. bot = rightreg(lbnd);
  39. e = gvbisect(bot, newsite);
  40. bisector = HEcreate(e, le);
  41. ELinsert(lbnd, bisector);
  42. if ((p = hintersect(lbnd, bisector)) != NULL) {
  43. PQdelete(pq, lbnd);
  44. PQinsert(pq, lbnd, p, dist(p, newsite));
  45. }
  46. lbnd = bisector;
  47. bisector = HEcreate(e, re);
  48. ELinsert(lbnd, bisector);
  49. if ((p = hintersect(bisector, rbnd)) != NULL)
  50. PQinsert(pq, bisector, p, dist(p, newsite));
  51. newsite = nextsite(context);
  52. } else if (!PQempty(pq)) {
  53. /* intersection is smallest */
  54. lbnd = PQextractmin(pq);
  55. llbnd = ELleft(lbnd);
  56. rbnd = ELright(lbnd);
  57. rrbnd = ELright(rbnd);
  58. bot = leftreg(lbnd);
  59. top = rightreg(rbnd);
  60. v = lbnd->vertex;
  61. makevertex(v);
  62. endpoint(lbnd->ELedge, lbnd->ELpm, v);
  63. endpoint(rbnd->ELedge, rbnd->ELpm, v);
  64. ELdelete(lbnd);
  65. PQdelete(pq, rbnd);
  66. ELdelete(rbnd);
  67. pm = le;
  68. if (bot->coord.y > top->coord.y) {
  69. temp = bot;
  70. bot = top;
  71. top = temp;
  72. pm = re;
  73. }
  74. e = gvbisect(bot, top);
  75. bisector = HEcreate(e, pm);
  76. ELinsert(llbnd, bisector);
  77. endpoint(e, re - pm, v);
  78. deref(v);
  79. if ((p = hintersect(llbnd, bisector)) != NULL) {
  80. PQdelete(pq, llbnd);
  81. PQinsert(pq, llbnd, p, dist(p, bot));
  82. }
  83. if ((p = hintersect(bisector, rrbnd)) != NULL) {
  84. PQinsert(pq, bisector, p, dist(p, bot));
  85. }
  86. } else
  87. break;
  88. }
  89. for (lbnd = ELright(ELleftend); lbnd != ELrightend; lbnd = ELright(lbnd)) {
  90. e = lbnd->ELedge;
  91. clip_line(e);
  92. }
  93. // `PQcleanup` relies on the number of sites, so should be discarded and
  94. // at least every time we use `vAdjust`. See note in adjust.c:cleanup().
  95. PQcleanup(pq);
  96. }