triang.c 4.3 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146
  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 <assert.h>
  11. #include <stdbool.h>
  12. #include <stdio.h>
  13. #include <math.h>
  14. #include <stdlib.h>
  15. #include <pathplan/pathutil.h>
  16. #include <pathplan/tri.h>
  17. #include <util/alloc.h>
  18. static int triangulate(Ppoint_t **pointp, size_t pointn,
  19. void (*fn)(void *, const Ppoint_t *), void *vc);
  20. int ccw(Ppoint_t p1, Ppoint_t p2, Ppoint_t p3) {
  21. double d = (p1.y - p2.y) * (p3.x - p2.x) - (p3.y - p2.y) * (p1.x - p2.x);
  22. return d > 0 ? ISCW : (d < 0 ? ISCCW : ISON);
  23. }
  24. static Ppoint_t point_indexer(void *base, size_t index) {
  25. Ppoint_t **b = base;
  26. return *b[index];
  27. }
  28. /* Ptriangulate:
  29. * Return 0 on success; non-zero on error.
  30. */
  31. int Ptriangulate(Ppoly_t *polygon, void (*fn)(void *, const Ppoint_t *),
  32. void *vc) {
  33. Ppoint_t **pointp;
  34. const size_t pointn = polygon->pn;
  35. pointp = gv_calloc(pointn, sizeof(Ppoint_t*));
  36. for (size_t i = 0; i < pointn; i++)
  37. pointp[i] = &(polygon->ps[i]);
  38. assert(pointn >= 3);
  39. if (triangulate(pointp, pointn, fn, vc) != 0) {
  40. free(pointp);
  41. return 1;
  42. }
  43. free(pointp);
  44. return 0;
  45. }
  46. /* triangulate:
  47. * Triangulates the given polygon.
  48. * Returns non-zero if no diagonal exists.
  49. */
  50. static int triangulate(Ppoint_t **pointp, size_t pointn,
  51. void (*fn)(void *, const Ppoint_t *), void *vc) {
  52. assert(pointn >= 3);
  53. Ppoint_t A[3];
  54. if (pointn > 3) {
  55. for (size_t i = 0; i < pointn; i++) {
  56. const size_t ip1 = (i + 1) % pointn;
  57. const size_t ip2 = (i + 2) % pointn;
  58. if (isdiagonal(i, ip2, pointp, pointn, point_indexer)) {
  59. A[0] = *pointp[i];
  60. A[1] = *pointp[ip1];
  61. A[2] = *pointp[ip2];
  62. fn(vc, A);
  63. size_t j = 0;
  64. for (i = 0; i < pointn; i++)
  65. if (i != ip1)
  66. pointp[j++] = pointp[i];
  67. return triangulate(pointp, pointn - 1, fn, vc);
  68. }
  69. }
  70. return -1;
  71. } else {
  72. A[0] = *pointp[0];
  73. A[1] = *pointp[1];
  74. A[2] = *pointp[2];
  75. fn(vc, A);
  76. }
  77. return 0;
  78. }
  79. bool isdiagonal(size_t i, size_t ip2, void *pointp, size_t pointn,
  80. indexer_t indexer) {
  81. int res;
  82. /* neighborhood test */
  83. const size_t ip1 = (i + 1) % pointn;
  84. const size_t im1 = (i + pointn - 1) % pointn;
  85. /* If P[i] is a convex vertex [ i+1 left of (i-1,i) ]. */
  86. if (ccw(indexer(pointp, im1), indexer(pointp, i), indexer(pointp, ip1)) == ISCCW)
  87. res = ccw(indexer(pointp, i), indexer(pointp, ip2), indexer(pointp, im1)) == ISCCW &&
  88. ccw(indexer(pointp, ip2), indexer(pointp, i), indexer(pointp, ip1)) == ISCCW;
  89. /* Assume (i - 1, i, i + 1) not collinear. */
  90. else
  91. res = ccw(indexer(pointp, i), indexer(pointp, ip2), indexer(pointp, ip1)) == ISCW;
  92. if (!res) {
  93. return false;
  94. }
  95. /* check against all other edges */
  96. for (size_t j = 0; j < pointn; j++) {
  97. const size_t jp1 = (j + 1) % pointn;
  98. if (!(j == i || jp1 == i || j == ip2 || jp1 == ip2))
  99. if (intersects
  100. (indexer(pointp, i), indexer(pointp, ip2), indexer(pointp, j), indexer(pointp, jp1))) {
  101. return false;
  102. }
  103. }
  104. return true;
  105. }
  106. bool intersects(Ppoint_t pa, Ppoint_t pb, Ppoint_t pc, Ppoint_t pd) {
  107. int ccw1, ccw2, ccw3, ccw4;
  108. if (ccw(pa, pb, pc) == ISON || ccw(pa, pb, pd) == ISON ||
  109. ccw(pc, pd, pa) == ISON || ccw(pc, pd, pb) == ISON) {
  110. if (between(pa, pb, pc) || between(pa, pb, pd) ||
  111. between(pc, pd, pa) || between(pc, pd, pb))
  112. return true;
  113. } else {
  114. ccw1 = ccw(pa, pb, pc) == ISCCW ? 1 : 0;
  115. ccw2 = ccw(pa, pb, pd) == ISCCW ? 1 : 0;
  116. ccw3 = ccw(pc, pd, pa) == ISCCW ? 1 : 0;
  117. ccw4 = ccw(pc, pd, pb) == ISCCW ? 1 : 0;
  118. return (ccw1 ^ ccw2) && (ccw3 ^ ccw4);
  119. }
  120. return false;
  121. }
  122. bool between(Ppoint_t pa, Ppoint_t pb, Ppoint_t pc) {
  123. const Ppoint_t pba = {.x = pb.x - pa.x, .y = pb.y - pa.y};
  124. const Ppoint_t pca = {.x = pc.x - pa.x, .y = pc.y - pa.y};
  125. if (ccw(pa, pb, pc) != ISON)
  126. return false;
  127. return pca.x * pba.x + pca.y * pba.y >= 0 &&
  128. pca.x * pca.x + pca.y * pca.y <= pba.x * pba.x + pba.y * pba.y;
  129. }