geom.c 5.5 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249
  1. /// @file
  2. /// API geomprocs.h
  3. /// @ingroup common_utils
  4. /*************************************************************************
  5. * Copyright (c) 2011 AT&T Intellectual Property
  6. * All rights reserved. This program and the accompanying materials
  7. * are made available under the terms of the Eclipse Public License v1.0
  8. * which accompanies this distribution, and is available at
  9. * https://www.eclipse.org/legal/epl-v10.html
  10. *
  11. * Contributors: Details at https://graphviz.org
  12. *************************************************************************/
  13. /* geometric functions (e.g. on points and boxes) with application to, but
  14. * no specific dependence on graphs */
  15. #include "config.h"
  16. #include <assert.h>
  17. #include <common/geom.h>
  18. #include <common/geomprocs.h>
  19. #include <math.h>
  20. #include <stdbool.h>
  21. #include <util/unreachable.h>
  22. /*
  23. *--------------------------------------------------------------
  24. *
  25. * lineToBox --
  26. *
  27. * Determine whether a line lies entirely inside, entirely
  28. * outside, or overlapping a given rectangular area.
  29. *
  30. * Results:
  31. * -1 is returned if the line given by p and q
  32. * is entirely outside the rectangle given by b.
  33. * 0 is returned if the polygon overlaps the rectangle, and
  34. * 1 is returned if the polygon is entirely inside the rectangle.
  35. *
  36. * Side effects:
  37. * None.
  38. *
  39. *--------------------------------------------------------------
  40. */
  41. /* This code steals liberally from algorithms in tk/generic/tkTrig.c -- jce */
  42. int lineToBox(pointf p, pointf q, boxf b)
  43. {
  44. /*
  45. * First check the two points individually to see whether they
  46. * are inside the rectangle or not.
  47. */
  48. bool inside1 = INSIDE(p, b);
  49. bool inside2 = INSIDE(q, b);
  50. if (inside1 != inside2) {
  51. return 0;
  52. }
  53. if (inside1 && inside2) {
  54. return 1;
  55. }
  56. /*
  57. * Both points are outside the rectangle, but still need to check
  58. * for intersections between the line and the rectangle. Horizontal
  59. * and vertical lines are particularly easy, so handle them
  60. * separately.
  61. */
  62. if (p.x == q.x) {
  63. /*
  64. * Vertical line.
  65. */
  66. if (((p.y >= b.LL.y) ^ (q.y >= b.LL.y)) && BETWEEN(b.LL.x, p.x, b.UR.x)) {
  67. return 0;
  68. }
  69. } else if (p.y == q.y) {
  70. /*
  71. * Horizontal line.
  72. */
  73. if (((p.x >= b.LL.x) ^ (q.x >= b.LL.x)) && BETWEEN(b.LL.y, p.y, b.UR.y)) {
  74. return 0;
  75. }
  76. } else {
  77. double m, x, y;
  78. /*
  79. * Diagonal line. Compute slope of line and use
  80. * for intersection checks against each of the
  81. * sides of the rectangle: left, right, bottom, top.
  82. */
  83. m = (q.y - p.y)/(q.x - p.x);
  84. double low = fmin(p.x, q.x);
  85. double high = fmax(p.x, q.x);
  86. /*
  87. * Left edge.
  88. */
  89. y = p.y + (b.LL.x - p.x)*m;
  90. if (BETWEEN(low, b.LL.x, high) && BETWEEN(b.LL.y, y, b.UR.y)) {
  91. return 0;
  92. }
  93. /*
  94. * Right edge.
  95. */
  96. y += (b.UR.x - b.LL.x)*m;
  97. if (BETWEEN(b.LL.y, y, b.UR.y) && BETWEEN(low, b.UR.x, high)) {
  98. return 0;
  99. }
  100. /*
  101. * Bottom edge.
  102. */
  103. low = fmin(p.y, q.y);
  104. high = fmax(p.y, q.y);
  105. x = p.x + (b.LL.y - p.y)/m;
  106. if (BETWEEN(b.LL.x, x, b.UR.x) && BETWEEN(low, b.LL.y, high)) {
  107. return 0;
  108. }
  109. /*
  110. * Top edge.
  111. */
  112. x += (b.UR.y - b.LL.y)/m;
  113. if (BETWEEN(b.LL.x, x, b.UR.x) && BETWEEN(low, b.UR.y, high)) {
  114. return 0;
  115. }
  116. }
  117. return -1;
  118. }
  119. void rect2poly(pointf *p)
  120. {
  121. p[3].x = p[2].x = p[1].x;
  122. p[2].y = p[1].y;
  123. p[3].y = p[0].y;
  124. p[1].x = p[0].x;
  125. }
  126. pointf cwrotatepf(pointf p, int cwrot)
  127. {
  128. assert(cwrot == 0 || cwrot == 90 || cwrot == 180 || cwrot == 270);
  129. double x = p.x, y = p.y;
  130. switch (cwrot) {
  131. case 0:
  132. break;
  133. case 90:
  134. p.x = y;
  135. p.y = -x;
  136. break;
  137. case 180:
  138. p.x = x;
  139. p.y = -y;
  140. break;
  141. case 270:
  142. p.x = y;
  143. p.y = x;
  144. break;
  145. default:
  146. UNREACHABLE();
  147. }
  148. return p;
  149. }
  150. pointf ccwrotatepf(pointf p, int ccwrot)
  151. {
  152. assert(ccwrot == 0 || ccwrot == 90 || ccwrot == 180 || ccwrot == 270);
  153. double x = p.x, y = p.y;
  154. switch (ccwrot) {
  155. case 0:
  156. break;
  157. case 90:
  158. p.x = -y;
  159. p.y = x;
  160. break;
  161. case 180:
  162. p.x = x;
  163. p.y = -y;
  164. break;
  165. case 270:
  166. p.x = y;
  167. p.y = x;
  168. break;
  169. default:
  170. UNREACHABLE();
  171. }
  172. return p;
  173. }
  174. boxf flip_rec_boxf(boxf b, pointf p)
  175. {
  176. boxf r;
  177. /* flip box */
  178. r.UR.x = b.UR.y;
  179. r.UR.y = b.UR.x;
  180. r.LL.x = b.LL.y;
  181. r.LL.y = b.LL.x;
  182. /* move box */
  183. r.LL.x += p.x;
  184. r.LL.y += p.y;
  185. r.UR.x += p.x;
  186. r.UR.y += p.y;
  187. return r;
  188. }
  189. #define SMALL 0.0000000001
  190. /* ptToLine2:
  191. * Return distance from point p to line a-b squared.
  192. */
  193. double ptToLine2 (pointf a, pointf b, pointf p)
  194. {
  195. double dx = b.x-a.x;
  196. double dy = b.y-a.y;
  197. double a2 = (p.y-a.y)*dx - (p.x-a.x)*dy;
  198. a2 *= a2; /* square - ensures that it is positive */
  199. if (a2 < SMALL) return 0.; /* avoid 0/0 problems */
  200. return a2 / (dx*dx + dy*dy);
  201. }
  202. #define dot(v,w) (v.x*w.x+v.y*w.y)
  203. /* line_intersect:
  204. * Computes intersection of lines a-b and c-d, returning intersection
  205. * point in *p.
  206. * Returns 0 if no intersection (lines parallel), 1 otherwise.
  207. */
  208. int line_intersect (pointf a, pointf b, pointf c, pointf d, pointf* p)
  209. {
  210. pointf mv = sub_pointf(b,a);
  211. pointf lv = sub_pointf(d,c);
  212. pointf ln = perp (lv);
  213. double lc = -dot(ln,c);
  214. double dt = dot(ln,mv);
  215. if (fabs(dt) < SMALL) return 0;
  216. *p = sub_pointf(a,scale((dot(ln,a)+lc)/dt,mv));
  217. return 1;
  218. }