Skip to content

Commit 28c2cbf

Browse files
Chilleesimonlindholm
authored andcommitted
Added line projection/reflection, circle line intersection, and a debugging utility (#133)
1 parent f327c4c commit 28c2cbf

File tree

5 files changed

+113
-0
lines changed

5 files changed

+113
-0
lines changed

content/geometry/CircleLine.h

Lines changed: 25 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,25 @@
1+
/**
2+
* Author: Victor Lecomte, chilli
3+
* Date: 2019-10-29
4+
* License: CC0
5+
* 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>
9+
* Status: unit tested
10+
*/
11+
12+
#pragma once
13+
14+
#include "Point.h"
15+
#include "lineDistance.h"
16+
#include "LineProjectionReflection.h"
17+
18+
template<class P>
19+
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();
21+
if (h2 < 0) return {};
22+
P p = lineProj(a, b, c), h = (b-a).unit() * sqrt(h2);
23+
if (h2 == 0) return {p};
24+
return {p - h, p + h};
25+
}
Lines changed: 21 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,21 @@
1+
/**
2+
* Author: Victor Lecomte, chilli
3+
* Date: 2019-10-29
4+
* License: CC0
5+
* Source: https://vlecomte.github.io/cp-geo.pdf
6+
* Description: Projects point p onto line ab. Set refl=true to get reflection
7+
* of point p across line ab insted. The wrong point will be returned if P is
8+
* an integer point and the desired point doesn't have integer coordinates.
9+
* Products of three coordinates are used in intermediate steps so watch out
10+
* for overflow.
11+
* Status: fuzz-tested
12+
*/
13+
#pragma once
14+
15+
#include "Point.h"
16+
17+
template<class P>
18+
P lineProj(P a, P b, P p, bool refl=false) {
19+
P v = b - a;
20+
return p - v.perp()*(1+refl)*v.cross(p-a)/v.dist2();
21+
}

content/geometry/Point.h

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -34,4 +34,6 @@ struct Point {
3434
// returns point rotated 'a' radians ccw around the origin
3535
P rotate(double a) const {
3636
return P(x*cos(a)-y*sin(a),x*sin(a)+y*cos(a)); }
37+
friend ostream& operator<<(ostream& os, P p) {
38+
return os << "(" << p.x << "," << p.y << ")"; }
3739
};

fuzz-tests/geometry/CircleLine.cpp

Lines changed: 34 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,34 @@
1+
#include <bits/stdc++.h>
2+
using namespace std;
3+
4+
#define rep(i, a, b) for (int i = a; i < (b); ++i)
5+
#define trav(a, x) for (auto &a : x)
6+
#define all(x) x.begin(), x.end()
7+
#define sz(x) (int)(x).size()
8+
typedef long long ll;
9+
typedef pair<int, int> pii;
10+
typedef vector<int> vi;
11+
12+
#include "../../content/geometry/CircleLine.h"
13+
14+
typedef Point<double> P;
15+
int main() {
16+
cin.sync_with_stdio(0);
17+
cin.tie(0);
18+
cin.exceptions(cin.failbit);
19+
{
20+
auto res = circleLine(P(0, 0), 1, P(-1, -1), P(1, 1));
21+
assert(res.size() == 2);
22+
assert((res[1]-P(sqrt(2)/2, sqrt(2)/2)).dist() < 1e-8);
23+
}
24+
{
25+
auto res = circleLine(P(0, 0), 1, P(-5, 1), P(5, 1));
26+
assert(res.size() == 1);
27+
assert((res[0]-P(0,1)).dist() < 1e-8);
28+
}
29+
{
30+
auto res = circleLine(P(4, 4), 1, P(0, 0), P(5, 0));
31+
assert(res.size() == 0);
32+
}
33+
cout<<"Tests passed!"<<endl;
34+
}
Lines changed: 31 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,31 @@
1+
#include <bits/stdc++.h>
2+
using namespace std;
3+
4+
#define rep(i, a, b) for (int i = a; i < (b); ++i)
5+
#define trav(a, x) for (auto &a : x)
6+
#define all(x) x.begin(), x.end()
7+
#define sz(x) (int)(x).size()
8+
typedef long long ll;
9+
typedef pair<int, int> pii;
10+
typedef vector<int> vi;
11+
12+
#include "../../content/geometry/LineProjectionReflection.h"
13+
14+
typedef Point<double> P;
15+
int main() {
16+
cin.sync_with_stdio(0);
17+
cin.tie(0);
18+
const int lim = 5;
19+
for (int i = 0; i < 100000; i++) {
20+
P p = P(rand() % lim, rand() % lim);
21+
P a = P(rand() % lim, rand() % lim);
22+
P b = P(rand() % lim, rand() % lim);
23+
while (a == b)
24+
b = P(rand() % lim, rand() % lim);
25+
auto proj = lineProj(a, b, p, false);
26+
auto refl = lineProj(a, b, p, true);
27+
assert(lineDist(a, b, proj) < 1e-8);
28+
auto manProj = (refl + p) / 2;
29+
assert((proj-manProj).dist() < 1e-8);
30+
}
31+
}

0 commit comments

Comments
 (0)