intersect.c 4.8 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194
  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 <math.h>
  11. #include <stdio.h>
  12. #include "simple.h"
  13. #include <stdlib.h>
  14. #include <util/exit.h>
  15. #include <util/unreachable.h>
  16. static int sign(double v) {
  17. if (v < 0)
  18. return -1;
  19. if (v > 0)
  20. return 1;
  21. return 0;
  22. }
  23. /* find the sign of the area of each of the triangles
  24. formed by adding a vertex of m to l
  25. also find the sign of their product */
  26. static void sgnarea(struct vertex *l, struct vertex *m, int i[])
  27. {
  28. float a, b, c, d, e, f, g, h, t;
  29. a = l->pos.x;
  30. b = l->pos.y;
  31. c = after(l)->pos.x - a;
  32. d = after(l)->pos.y - b;
  33. e = m->pos.x - a;
  34. f = m->pos.y - b;
  35. g = after(m)->pos.x - a;
  36. h = after(m)->pos.y - b;
  37. t = c * f - d * e;
  38. i[0] = sign(t);
  39. t = c * h - d * g;
  40. i[1] = sign(t);
  41. i[2] = i[0] * i[1];
  42. }
  43. /** where is `g` relative to the interval delimited by `f` and `h`?
  44. *
  45. * The order of `f` and `h` is not assumed. That is, the interval defined may be
  46. * `(f, h)` or `(h, f)` depending on whether `f` is less than or greater than
  47. * `h`.
  48. *
  49. * \param f First boundary of the interval
  50. * \param g Value to test
  51. * \param h Second boundary of the interval
  52. * \return -1 if g is not in the interval, 1 if g is in the interval, 0 if g is
  53. * on the boundary (that is, equal to f or equal to h)
  54. */
  55. static int between(double f, double g, double h) {
  56. if (f < g) {
  57. if (g < h) {
  58. return 1;
  59. }
  60. if (g > h) {
  61. return -1;
  62. }
  63. return 0;
  64. }
  65. if (f > g) {
  66. if (g > h) {
  67. return 1;
  68. }
  69. if (g < h) {
  70. return -1;
  71. }
  72. return 0;
  73. }
  74. return 0;
  75. }
  76. /* determine if vertex i of line m is on line l */
  77. static int online(struct vertex *l, struct vertex *m, int i)
  78. {
  79. struct position a, b, c;
  80. a = l->pos;
  81. b = after(l)->pos;
  82. c = i == 0 ? m->pos : after(m)->pos;
  83. return a.x == b.x ? (a.x == c.x && -1 != between(a.y, c.y, b.y))
  84. : between(a.x, c.x, b.x);
  85. }
  86. /* determine point of detected intersections */
  87. static int intpoint(struct vertex *l, struct vertex *m, float *x, float *y, int cond)
  88. {
  89. struct position ls, le, ms, me, pt1, pt2;
  90. float m1, m2, c1, c2;
  91. if (cond <= 0)
  92. return (0);
  93. ls = l->pos;
  94. le = after(l)->pos;
  95. ms = m->pos;
  96. me = after(m)->pos;
  97. switch (cond) {
  98. case 3: /* a simple intersection */
  99. if (ls.x == le.x) {
  100. *x = ls.x;
  101. *y = me.y + SLOPE(ms, me) * (*x - me.x);
  102. } else if (ms.x == me.x) {
  103. *x = ms.x;
  104. *y = le.y + SLOPE(ls, le) * (*x - le.x);
  105. } else {
  106. m1 = SLOPE(ms, me);
  107. m2 = SLOPE(ls, le);
  108. c1 = ms.y - m1 * ms.x;
  109. c2 = ls.y - m2 * ls.x;
  110. *x = (c2 - c1) / (m1 - m2);
  111. *y = (m1 * c2 - c1 * m2) / (m1 - m2);
  112. }
  113. break;
  114. case 2: /* the two lines have a common segment */
  115. if (online(l, m, 0) == -1) { /* ms between ls and le */
  116. pt1 = ms;
  117. pt2 = online(m, l, 1) == -1 ? (online(m, l, 0 == -1) ? le : ls) : me;
  118. } else if (online(l, m, 1) == -1) { /* me between ls and le */
  119. pt1 = me;
  120. pt2 = online(l, m, 0) == -1 ? (online(m, l, 0) == -1 ? le : ls) : ms;
  121. } else {
  122. /* may be degenerate? */
  123. if (online(m, l, 0) != -1)
  124. return 0;
  125. pt1 = ls;
  126. pt2 = le;
  127. }
  128. *x = (pt1.x + pt2.x) / 2;
  129. *y = (pt1.y + pt2.y) / 2;
  130. break;
  131. case 1: /* a vertex of line m is on line l */
  132. if ((ls.x - le.x) * (ms.y - ls.y) == (ls.y - le.y) * (ms.x - ls.x)) {
  133. *x = ms.x;
  134. *y = ms.y;
  135. } else {
  136. *x = me.x;
  137. *y = me.y;
  138. }
  139. break;
  140. default:
  141. UNREACHABLE();
  142. } /* end switch */
  143. return 1;
  144. }
  145. void find_intersection(struct vertex *l,
  146. struct vertex *m,
  147. struct intersection ilist[], struct data *input)
  148. {
  149. float x, y;
  150. int i[3];
  151. sgnarea(l, m, i);
  152. if (i[2] > 0)
  153. return;
  154. if (i[2] < 0) {
  155. sgnarea(m, l, i);
  156. if (i[2] > 0)
  157. return;
  158. if (!intpoint(l, m, &x, &y, i[2] < 0 ? 3 : online(m, l, abs(i[0]))))
  159. return;
  160. }
  161. else if (!intpoint(l, m, &x, &y, i[0] == i[1] ? 2 * MAX(online(l, m, 0),
  162. online(l, m, 1)) : online(l, m, abs(i[0]))))
  163. return;
  164. if (input->ninters >= MAXINTS) {
  165. fprintf(stderr, "\n**ERROR**\n using too many intersections\n");
  166. graphviz_exit(1);
  167. }
  168. ilist[input->ninters].firstv = l;
  169. ilist[input->ninters].secondv = m;
  170. ilist[input->ninters].firstp = l->poly;
  171. ilist[input->ninters].secondp = m->poly;
  172. ilist[input->ninters].x = x;
  173. ilist[input->ninters].y = y;
  174. input->ninters++;
  175. }