Skip to content

Commit cd6c130

Browse files
committed
Rewrite CircleLine to avoid LineProjectionReflection
1 parent a9ce406 commit cd6c130

File tree

2 files changed

+34
-10
lines changed

2 files changed

+34
-10
lines changed

content/geometry/CircleLine.h

Lines changed: 6 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -3,23 +3,22 @@
33
* Date: 2019-10-29
44
* License: CC0
55
* Source: https://vlecomte.github.io/cp-geo.pdf
6-
* Description: Finds the intersection between a circle and a line. Returns a
7-
* vector of either 0, 1, or 2 intersection points. P is intended to be
8-
* Point<double>
6+
* Description: Finds the intersection between a circle and a line.
7+
* Returns a vector of either 0, 1, or 2 intersection points.
8+
* P is intended to be Point<double>.
99
* Status: unit tested
1010
*/
1111

1212
#pragma once
1313

1414
#include "Point.h"
15-
#include "lineDistance.h"
16-
#include "LineProjectionReflection.h"
1715

1816
template<class P>
1917
vector<P> circleLine(P c, double r, P a, P b) {
20-
double h2 = r*r - a.cross(b,c)*a.cross(b,c)/(b-a).dist2();
18+
P ab = b - a, p = a + ab * (c-a).dot(ab) / ab.dist2();
19+
double s = a.cross(b, c), h2 = r*r - s*s / ab.dist2();
2120
if (h2 < 0) return {};
22-
P p = lineProj(a, b, c), h = (b-a).unit() * sqrt(h2);
2321
if (h2 == 0) return {p};
22+
P h = ab.unit() * sqrt(h2);
2423
return {p - h, p + h};
2524
}

stress-tests/geometry/CircleLine.cpp

Lines changed: 28 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -1,12 +1,11 @@
11
#include "../utilities/template.h"
2+
#include "../utilities/randGeo.h"
23

4+
#include "../../content/geometry/lineDistance.h"
35
#include "../../content/geometry/CircleLine.h"
46

57
typedef Point<double> P;
68
int main() {
7-
cin.sync_with_stdio(0);
8-
cin.tie(0);
9-
cin.exceptions(cin.failbit);
109
{
1110
auto res = circleLine(P(0, 0), 1, P(-1, -1), P(1, 1));
1211
assert(res.size() == 2);
@@ -21,5 +20,31 @@ int main() {
2120
auto res = circleLine(P(4, 4), 1, P(0, 0), P(5, 0));
2221
assert(res.size() == 0);
2322
}
23+
rep(it,0,100000) {
24+
P a = randIntPt(5);
25+
P b = randIntPt(5);
26+
P c = randIntPt(5);
27+
if (a == b) {
28+
// Not a well defined line
29+
continue;
30+
}
31+
double r = sqrt(rand() % 49);
32+
vector<P> points = circleLine(c, r, a, b);
33+
34+
// Soundness
35+
assert(sz(points) <= 2);
36+
for (P p : points) {
37+
// Point is on circle
38+
assert(abs((p - c).dist() - r) < 1e-6);
39+
// Point is on line
40+
assert(lineDist(a, b, p) < 1e-6);
41+
}
42+
43+
// Best-effort completeness check:
44+
// in some easy cases we must have points in the intersection.
45+
if ((a - c).dist() < r - 1e-6 || (b - c).dist() < r - 1e-6 || ((a + b) / 2 - c).dist() < r - 1e-6) {
46+
assert(!points.empty());
47+
}
48+
}
2449
cout<<"Tests passed!"<<endl;
2550
}

0 commit comments

Comments
 (0)