Collision Checker
raytrace_primitive.cc
Go to the documentation of this file.
2 
3 #include <cmath>
4 #include <iostream>
5 #include <vector>
6 
8 
9 namespace collision {
10 namespace raytrace {
11 
13  x = 0;
14  y = 0;
15 };
16 Point::Point(const Eigen::Vector2d &pnt) : x(pnt.x()), y(pnt.y()){};
17 Point::Point(const Point &pnt) : x(pnt.x), y(pnt.y){};
18 
19 // Adapted from
20 // http://csharphelper.com/blog/2014/09/determine-where-a-line-intersects-a-circle-in-c/
21 int findLineCircleIntersections(double cx, double cy, double radius,
22  const Eigen::Vector2d &p1,
23  const Eigen::Vector2d &p2,
24  std::vector<Eigen::Vector2d> &inters) {
25  double dx, dy, A, B, C, det, t;
26 
27  dx = p2.x() - p1.x();
28  dy = p2.y() - p1.y();
29 
30  A = dx * dx + dy * dy;
31  B = 2 * (dx * (p1.x() - cx) + dy * (p1.y() - cy));
32  C = (p1.x() - cx) * (p1.x() - cx) + (p1.y() - cy) * (p1.y() - cy) -
33  radius * radius;
34 
35  det = B * B - 4 * A * C;
36  if ((A <= 0.0000001) || (det < 0)) {
37  // No real solutions.
38  return 0;
39  } else if (det == 0) {
40  // One solution.
41  t = -B / (2 * A);
42  inters.push_back(Eigen::Vector2d(p1.x() + t * dx, p1.y() + t * dy));
43  return 1;
44  } else {
45  // Two solutions.
46  t = (double)((-B + sqrt(det)) / (2 * A));
47  inters.push_back(Eigen::Vector2d(p1.x() + t * dx, p1.y() + t * dy));
48 
49  t = (double)((-B - sqrt(det)) / (2 * A));
50  inters.push_back(Eigen::Vector2d(p1.x() + t * dx, p1.y() + t * dy));
51  return 2;
52  }
53 }
54 
55 void RaytraceDebugOutput(const char *message) {
56 #if RAYTRACE_DEBUG
57  std::cout << message;
58 #endif
59 }
60 
61 void RaiseRaytraceError(const char *message) {
62 #if RAYTRACE_DEBUG
63  std::cout << message;
64 #endif
65 }
66 
67 // Adapted from
68 // https://www.geeksforgeeks.org/check-if-two-given-line-segments-intersect/
69 bool onSegment(Point p, Point q, Point r) {
70  if (q.x <= max(p.x, r.x) && q.x >= min(p.x, r.x) && q.y <= max(p.y, r.y) &&
71  q.y >= min(p.y, r.y))
72  return true;
73 
74  return false;
75 }
76 
77 // To find orientation of ordered triplet (p, q, r).
78 // The function returns following values
79 // 0 --> p, q and r are colinear
80 // 1 --> Clockwise
81 // 2 --> Counterclockwise
82 int orientation(Point p, Point q, Point r) {
83  // See 10th slides from following link for derivation of the formula
84  // http://www.dcs.gla.ac.uk/~pat/52233/slides/Geometry1x1.pdf
85  double val = (q.y - p.y) * (r.x - q.x) - (q.x - p.x) * (r.y - q.y);
86 
87  if (val == 0) return 0; // colinear
88 
89  return (val > 0) ? 1 : 2; // clock or counterclock wise
90 }
91 
92 inline double det(double a, double b, double c, double d) {
93  return a * d - b * c;
94 }
95 
96 bool lineLineIntersect(double x1, double y1, // Line 1 start
97  double x2, double y2, // Line 1 end
98  double x3, double y3, // Line 2 start
99  double x4, double y4, // Line 2 end
100  double &ixOut, double &iyOut) // Output
101 {
102  // http://mathworld.wolfram.com/Line-LineIntersection.html
103 
104  double detL1 = det(x1, y1, x2, y2);
105  double detL2 = det(x3, y3, x4, y4);
106  double x1mx2 = x1 - x2;
107  double x3mx4 = x3 - x4;
108  double y1my2 = y1 - y2;
109  double y3my4 = y3 - y4;
110 
111  double xnom = det(detL1, x1mx2, detL2, x3mx4);
112  double ynom = det(detL1, y1my2, detL2, y3my4);
113  double denom = det(x1mx2, y1my2, x3mx4, y3my4);
114  if (denom == 0.0) // Lines don't seem to cross
115  {
116  ixOut = NAN;
117  iyOut = NAN;
118  return false;
119  }
120 
121  ixOut = xnom / denom;
122  iyOut = ynom / denom;
123  if (!isfinite(ixOut) || !isfinite(iyOut)) // Probably a numerical issue
124  return false;
125 
126  return true; // All OK
127 }
128 
129 // Part taken from
130 // https://www.geeksforgeeks.org/check-if-two-given-line-segments-intersect/ The
131 // main function that returns true if line segment 'p1q1' and 'p2q2' intersect.
132 bool doIntersect(Point p1, Point q1, Point p2, Point q2,
133  std::vector<Point> &inters) {
134  // Find the four orientations needed for general and
135  // special cases
136  int o1 = orientation(p1, q1, p2);
137  int o2 = orientation(p1, q1, q2);
138  int o3 = orientation(p2, q2, p1);
139  int o4 = orientation(p2, q2, q1);
140 
141  // General case
142  if (o1 != o2 && o3 != o4) {
143  double int_x = 0;
144  double int_y = 0;
145  if (lineLineIntersect(p1.x, p1.y, q1.x, q1.y, p2.x, p2.y, q2.x, q2.y, int_x,
146  int_y)) {
147  Point intersection1;
148  intersection1.x = int_x;
149  intersection1.y = int_y;
150  inters.push_back(intersection1);
151  return true;
152  } else {
153  raytrace::RaiseRaytraceError("numeric issue with points intersection");
154  return false;
155  }
156  }
157 
158  // if p1, p2, q1, q2 are collinear
159  if (o1 == 0 && o2 == 0) {
160  int outnum = 0;
161 
162  // if p2 or q2 lies on p1q1
163 
164  if (onSegment(p1, p2, q1)) {
165  outnum++;
166  inters.push_back(p2);
167  }
168  if (outnum == 2) return true;
169 
170  if (onSegment(p1, q2, q1)) {
171  outnum++;
172  inters.push_back(q2);
173  }
174 
175  if (outnum == 2) return true;
176 
177  // if p1 or q1 lies on p2q2
178 
179  if (onSegment(p2, p1, q2)) {
180  outnum++;
181  inters.push_back(p1);
182  }
183 
184  if (outnum == 2) return true;
185 
186  if (onSegment(p2, q1, q2)) {
187  outnum++;
188  inters.push_back(q1);
189  }
190 
191  // if(outnum==2) return true;
192  return true;
193  }
194 
195  // Special Cases
196  // p1, q1 and p2 are colinear and p2 lies on segment p1q1
197  if (o1 == 0 && onSegment(p1, p2, q1)) {
198  inters.push_back(p2);
199  return true;
200  }
201 
202  // p1, q1 and q2 are colinear and q2 lies on segment p1q1
203  if (o2 == 0 && onSegment(p1, q2, q1)) {
204  inters.push_back(q2);
205  return true;
206  }
207 
208  // p2, q2 and p1 are colinear and p1 lies on segment p2q2
209  if (o3 == 0 && onSegment(p2, p1, q2)) {
210  inters.push_back(p1);
211  return true;
212  }
213 
214  // p2, q2 and q1 are colinear and q1 lies on segment p2q2
215  if (o4 == 0 && onSegment(p2, q1, q2)) {
216  inters.push_back(q1);
217  return true;
218  }
219 
220  return false; // Doesn't fall in any of the above cases
221 }
222 } // namespace raytrace
223 } // namespace collision
bool lineLineIntersect(double x1, double y1, double x2, double y2, double x3, double y3, double x4, double y4, double &ixOut, double &iyOut)
void RaiseRaytraceError(const char *)
int findLineCircleIntersections(double cx, double cy, double radius, const Eigen::Vector2d &p1, const Eigen::Vector2d &p2, std::vector< Eigen::Vector2d > &inters)
double det(double a, double b, double c, double d)
void RaytraceDebugOutput(const char *)
bool onSegment(Point p, Point q, Point r)
bool doIntersect(Point p1, Point q1, Point p2, Point q2, std::vector< Point > &inters)
int orientation(Point p, Point q, Point r)