Geometry.cc 9.7 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301
  1. // C++ routines for computational geometry.
  2. #include <iostream>
  3. #include <vector>
  4. #include <cmath>
  5. #include <cassert>
  6. using namespace std;
  7. double INF = 1e100;
  8. double EPS = 1e-12;
  9. struct PT {
  10. double x, y;
  11. PT() {}
  12. PT(double x, double y) : x(x), y(y) {}
  13. PT(const PT &p) : x(p.x), y(p.y) {}
  14. PT operator + (const PT &p) const { return PT(x+p.x, y+p.y); }
  15. PT operator - (const PT &p) const { return PT(x-p.x, y-p.y); }
  16. PT operator * (double c) const { return PT(x*c, y*c ); }
  17. PT operator / (double c) const { return PT(x/c, y/c ); }
  18. };
  19. double dot(PT p, PT q) { return p.x*q.x+p.y*q.y; }
  20. double dist2(PT p, PT q) { return dot(p-q,p-q); }
  21. double cross(PT p, PT q) { return p.x*q.y-p.y*q.x; }
  22. ostream &operator<<(ostream &os, const PT &p) {
  23. os << "(" << p.x << "," << p.y << ")";
  24. }
  25. // rotate a point CCW or CW around the origin
  26. PT RotateCCW90(PT p) { return PT(-p.y,p.x); }
  27. PT RotateCW90(PT p) { return PT(p.y,-p.x); }
  28. PT RotateCCW(PT p, double t) {
  29. return PT(p.x*cos(t)-p.y*sin(t), p.x*sin(t)+p.y*cos(t));
  30. }
  31. // project point c onto line through a and b
  32. // assuming a != b
  33. PT ProjectPointLine(PT a, PT b, PT c) {
  34. return a + (b-a)*dot(c-a, b-a)/dot(b-a, b-a);
  35. }
  36. // project point c onto line segment through a and b
  37. PT ProjectPointSegment(PT a, PT b, PT c) {
  38. double r = dot(b-a,b-a);
  39. if (fabs(r) < EPS) return a;
  40. r = dot(c-a, b-a)/r;
  41. if (r < 0) return a;
  42. if (r > 1) return b;
  43. return a + (b-a)*r;
  44. }
  45. // compute distance from c to segment between a and b
  46. double DistancePointSegment(PT a, PT b, PT c) {
  47. return sqrt(dist2(c, ProjectPointSegment(a, b, c)));
  48. }
  49. // compute distance between point (x,y,z) and plane ax+by+cz=d
  50. double DistancePointPlane(double x, double y, double z,
  51. double a, double b, double c, double d)
  52. {
  53. return fabs(a*x+b*y+c*z-d)/sqrt(a*a+b*b+c*c);
  54. }
  55. // determine if lines from a to b and c to d are parallel or collinear
  56. bool LinesParallel(PT a, PT b, PT c, PT d) {
  57. return fabs(cross(b-a, c-d)) < EPS;
  58. }
  59. bool LinesCollinear(PT a, PT b, PT c, PT d) {
  60. return LinesParallel(a, b, c, d)
  61. && fabs(cross(a-b, a-c)) < EPS
  62. && fabs(cross(c-d, c-a)) < EPS;
  63. }
  64. // determine if line segment from a to b intersects with
  65. // line segment from c to d
  66. bool SegmentsIntersect(PT a, PT b, PT c, PT d) {
  67. if (LinesCollinear(a, b, c, d)) {
  68. if (dist2(a, c) < EPS || dist2(a, d) < EPS ||
  69. dist2(b, c) < EPS || dist2(b, d) < EPS) return true;
  70. if (dot(c-a, c-b) > 0 && dot(d-a, d-b) > 0 && dot(c-b, d-b) > 0)
  71. return false;
  72. return true;
  73. }
  74. if (cross(d-a, b-a) * cross(c-a, b-a) > 0) return false;
  75. if (cross(a-c, d-c) * cross(b-c, d-c) > 0) return false;
  76. return true;
  77. }
  78. // compute intersection of line passing through a and b
  79. // with line passing through c and d, assuming that unique
  80. // intersection exists; for segment intersection, check if
  81. // segments intersect first
  82. PT ComputeLineIntersection(PT a, PT b, PT c, PT d) {
  83. b=b-a; d=c-d; c=c-a;
  84. assert(dot(b, b) > EPS && dot(d, d) > EPS);
  85. return a + b*cross(c, d)/cross(b, d);
  86. }
  87. // compute center of circle given three points
  88. PT ComputeCircleCenter(PT a, PT b, PT c) {
  89. b=(a+b)/2;
  90. c=(a+c)/2;
  91. return ComputeLineIntersection(b, b+RotateCW90(a-b), c, c+RotateCW90(a-c));
  92. }
  93. // determine if point is in a possibly non-convex polygon (by William
  94. // Randolph Franklin); returns 1 for strictly interior points, 0 for
  95. // strictly exterior points, and 0 or 1 for the remaining points.
  96. // Note that it is possible to convert this into an *exact* test using
  97. // integer arithmetic by taking care of the division appropriately
  98. // (making sure to deal with signs properly) and then by writing exact
  99. // tests for checking point on polygon boundary
  100. bool PointInPolygon(const vector<PT> &p, PT q) {
  101. bool c = 0;
  102. for (int i = 0; i < p.size(); i++){
  103. int j = (i+1)%p.size();
  104. if ((p[i].y <= q.y && q.y < p[j].y ||
  105. p[j].y <= q.y && q.y < p[i].y) &&
  106. q.x < p[i].x + (p[j].x - p[i].x) * (q.y - p[i].y) / (p[j].y - p[i].y))
  107. c = !c;
  108. }
  109. return c;
  110. }
  111. // determine if point is on the boundary of a polygon
  112. bool PointOnPolygon(const vector<PT> &p, PT q) {
  113. for (int i = 0; i < p.size(); i++)
  114. if (dist2(ProjectPointSegment(p[i], p[(i+1)%p.size()], q), q) < EPS)
  115. return true;
  116. return false;
  117. }
  118. // compute intersection of line through points a and b with
  119. // circle centered at c with radius r > 0
  120. vector<PT> CircleLineIntersection(PT a, PT b, PT c, double r) {
  121. vector<PT> ret;
  122. b = b-a;
  123. a = a-c;
  124. double A = dot(b, b);
  125. double B = dot(a, b);
  126. double C = dot(a, a) - r*r;
  127. double D = B*B - A*C;
  128. if (D < -EPS) return ret;
  129. ret.push_back(c+a+b*(-B+sqrt(D+EPS))/A);
  130. if (D > EPS)
  131. ret.push_back(c+a+b*(-B-sqrt(D))/A);
  132. return ret;
  133. }
  134. // compute intersection of circle centered at a with radius r
  135. // with circle centered at b with radius R
  136. vector<PT> CircleCircleIntersection(PT a, PT b, double r, double R) {
  137. vector<PT> ret;
  138. double d = sqrt(dist2(a, b));
  139. if (d > r+R || d+min(r, R) < max(r, R)) return ret;
  140. double x = (d*d-R*R+r*r)/(2*d);
  141. double y = sqrt(r*r-x*x);
  142. PT v = (b-a)/d;
  143. ret.push_back(a+v*x + RotateCCW90(v)*y);
  144. if (y > 0)
  145. ret.push_back(a+v*x - RotateCCW90(v)*y);
  146. return ret;
  147. }
  148. // This code computes the area or centroid of a (possibly nonconvex)
  149. // polygon, assuming that the coordinates are listed in a clockwise or
  150. // counterclockwise fashion. Note that the centroid is often known as
  151. // the "center of gravity" or "center of mass".
  152. double ComputeSignedArea(const vector<PT> &p) {
  153. double area = 0;
  154. for(int i = 0; i < p.size(); i++) {
  155. int j = (i+1) % p.size();
  156. area += p[i].x*p[j].y - p[j].x*p[i].y;
  157. }
  158. return area / 2.0;
  159. }
  160. double ComputeArea(const vector<PT> &p) {
  161. return fabs(ComputeSignedArea(p));
  162. }
  163. PT ComputeCentroid(const vector<PT> &p) {
  164. PT c(0,0);
  165. double scale = 6.0 * ComputeSignedArea(p);
  166. for (int i = 0; i < p.size(); i++){
  167. int j = (i+1) % p.size();
  168. c = c + (p[i]+p[j])*(p[i].x*p[j].y - p[j].x*p[i].y);
  169. }
  170. return c / scale;
  171. }
  172. // tests whether or not a given polygon (in CW or CCW order) is simple
  173. bool IsSimple(const vector<PT> &p) {
  174. for (int i = 0; i < p.size(); i++) {
  175. for (int k = i+1; k < p.size(); k++) {
  176. int j = (i+1) % p.size();
  177. int l = (k+1) % p.size();
  178. if (i == l || j == k) continue;
  179. if (SegmentsIntersect(p[i], p[j], p[k], p[l]))
  180. return false;
  181. }
  182. }
  183. return true;
  184. }
  185. int main() {
  186. // expected: (-5,2)
  187. cerr << RotateCCW90(PT(2,5)) << endl;
  188. // expected: (5,-2)
  189. cerr << RotateCW90(PT(2,5)) << endl;
  190. // expected: (-5,2)
  191. cerr << RotateCCW(PT(2,5),M_PI/2) << endl;
  192. // expected: (5,2)
  193. cerr << ProjectPointLine(PT(-5,-2), PT(10,4), PT(3,7)) << endl;
  194. // expected: (5,2) (7.5,3) (2.5,1)
  195. cerr << ProjectPointSegment(PT(-5,-2), PT(10,4), PT(3,7)) << " "
  196. << ProjectPointSegment(PT(7.5,3), PT(10,4), PT(3,7)) << " "
  197. << ProjectPointSegment(PT(-5,-2), PT(2.5,1), PT(3,7)) << endl;
  198. // expected: 6.78903
  199. cerr << DistancePointPlane(4,-4,3,2,-2,5,-8) << endl;
  200. // expected: 1 0 1
  201. cerr << LinesParallel(PT(1,1), PT(3,5), PT(2,1), PT(4,5)) << " "
  202. << LinesParallel(PT(1,1), PT(3,5), PT(2,0), PT(4,5)) << " "
  203. << LinesParallel(PT(1,1), PT(3,5), PT(5,9), PT(7,13)) << endl;
  204. // expected: 0 0 1
  205. cerr << LinesCollinear(PT(1,1), PT(3,5), PT(2,1), PT(4,5)) << " "
  206. << LinesCollinear(PT(1,1), PT(3,5), PT(2,0), PT(4,5)) << " "
  207. << LinesCollinear(PT(1,1), PT(3,5), PT(5,9), PT(7,13)) << endl;
  208. // expected: 1 1 1 0
  209. cerr << SegmentsIntersect(PT(0,0), PT(2,4), PT(3,1), PT(-1,3)) << " "
  210. << SegmentsIntersect(PT(0,0), PT(2,4), PT(4,3), PT(0,5)) << " "
  211. << SegmentsIntersect(PT(0,0), PT(2,4), PT(2,-1), PT(-2,1)) << " "
  212. << SegmentsIntersect(PT(0,0), PT(2,4), PT(5,5), PT(1,7)) << endl;
  213. // expected: (1,2)
  214. cerr << ComputeLineIntersection(PT(0,0), PT(2,4), PT(3,1), PT(-1,3)) << endl;
  215. // expected: (1,1)
  216. cerr << ComputeCircleCenter(PT(-3,4), PT(6,1), PT(4,5)) << endl;
  217. vector<PT> v;
  218. v.push_back(PT(0,0));
  219. v.push_back(PT(5,0));
  220. v.push_back(PT(5,5));
  221. v.push_back(PT(0,5));
  222. // expected: 1 1 1 0 0
  223. cerr << PointInPolygon(v, PT(2,2)) << " "
  224. << PointInPolygon(v, PT(2,0)) << " "
  225. << PointInPolygon(v, PT(0,2)) << " "
  226. << PointInPolygon(v, PT(5,2)) << " "
  227. << PointInPolygon(v, PT(2,5)) << endl;
  228. // expected: 0 1 1 1 1
  229. cerr << PointOnPolygon(v, PT(2,2)) << " "
  230. << PointOnPolygon(v, PT(2,0)) << " "
  231. << PointOnPolygon(v, PT(0,2)) << " "
  232. << PointOnPolygon(v, PT(5,2)) << " "
  233. << PointOnPolygon(v, PT(2,5)) << endl;
  234. // expected: (1,6)
  235. // (5,4) (4,5)
  236. // blank line
  237. // (4,5) (5,4)
  238. // blank line
  239. // (4,5) (5,4)
  240. vector<PT> u = CircleLineIntersection(PT(0,6), PT(2,6), PT(1,1), 5);
  241. for (int i = 0; i < u.size(); i++) cerr << u[i] << " "; cerr << endl;
  242. u = CircleLineIntersection(PT(0,9), PT(9,0), PT(1,1), 5);
  243. for (int i = 0; i < u.size(); i++) cerr << u[i] << " "; cerr << endl;
  244. u = CircleCircleIntersection(PT(1,1), PT(10,10), 5, 5);
  245. for (int i = 0; i < u.size(); i++) cerr << u[i] << " "; cerr << endl;
  246. u = CircleCircleIntersection(PT(1,1), PT(8,8), 5, 5);
  247. for (int i = 0; i < u.size(); i++) cerr << u[i] << " "; cerr << endl;
  248. u = CircleCircleIntersection(PT(1,1), PT(4.5,4.5), 10, sqrt(2.0)/2.0);
  249. for (int i = 0; i < u.size(); i++) cerr << u[i] << " "; cerr << endl;
  250. u = CircleCircleIntersection(PT(1,1), PT(4.5,4.5), 5, sqrt(2.0)/2.0);
  251. for (int i = 0; i < u.size(); i++) cerr << u[i] << " "; cerr << endl;
  252. // area should be 5.0
  253. // centroid should be (1.1666666, 1.166666)
  254. PT pa[] = { PT(0,0), PT(5,0), PT(1,1), PT(0,5) };
  255. vector<PT> p(pa, pa+4);
  256. PT c = ComputeCentroid(p);
  257. cerr << "Area: " << ComputeArea(p) << endl;
  258. cerr << "Centroid: " << c << endl;
  259. return 0;
  260. }