Line circle intersection: Difference between revisions
Content added Content deleted
(Added Swift solution) |
|||
Line 385: | Line 385: | ||
return 0; |
return 0; |
||
}</lang> |
|||
{{out}} |
|||
<pre>The intersection points (if any) between: |
|||
A circle, center (3, -5) with radius 3, and: |
|||
a line containing the points (-10, 11) and (10, -9) is/are: |
|||
[(6, -5), (3, -2)] |
|||
a segment starting at (-10, 11) and ending at (-10, 12) is/are: |
|||
[] |
|||
a horizontal line containing the points (3, -2) and (7, -2) is/are: |
|||
[(3, -2)] |
|||
A circle, center (0, 0) with radius 4, and: |
|||
a vertical line containing the points (0, -3) and (0, 6) is/are: |
|||
[(0, 4), (0, -4)] |
|||
a vertical segment containing the points (0, -3) and (0, 6) is/are: |
|||
[(0, 4)] |
|||
A circle, center (4, 2) with radius 5, and: |
|||
a line containing the points (6, 3) and (10, 7) is/are: |
|||
[(8, 5), (1, -2)] |
|||
a segment starting at (7, 4) and ending at (11, 8) is/are: |
|||
[(8, 5)]</pre> |
|||
=={{header|D}}== |
|||
{{trans|C++}} |
|||
<lang d>import std.format; |
|||
import std.math; |
|||
import std.stdio; |
|||
immutable EPS = 1e-14; |
|||
struct Point { |
|||
private double x; |
|||
private double y; |
|||
public this(double x, double y) { |
|||
this.x = x; |
|||
this.y = y; |
|||
} |
|||
public double getX() { |
|||
return x; |
|||
} |
|||
public double getY() { |
|||
return y; |
|||
} |
|||
void toString(scope void delegate(const(char)[]) sink, FormatSpec!char fmt) const { |
|||
double mx = x; |
|||
double my = y; |
|||
// eliminate negative zero |
|||
if (mx == 0.0) { |
|||
mx = 0.0; |
|||
} |
|||
// eliminate negative zero |
|||
if (my == 0.0) { |
|||
my = 0.0; |
|||
} |
|||
sink("("); |
|||
formatValue(sink, mx, fmt); |
|||
sink(", "); |
|||
formatValue(sink, my, fmt); |
|||
sink(")"); |
|||
} |
|||
} |
|||
auto sq(T)(T x) { |
|||
return x * x; |
|||
} |
|||
auto intersects(const Point p1, const Point p2, const Point cp, double r, bool segment) { |
|||
auto x0 = cp.x; |
|||
auto y0 = cp.y; |
|||
auto x1 = p1.x; |
|||
auto y1 = p1.y; |
|||
auto x2 = p2.x; |
|||
auto y2 = p2.y; |
|||
auto A = y2 - y1; |
|||
auto B = x1 - x2; |
|||
auto C = x2 * y1 - x1 * y2; |
|||
auto a = sq(A) + sq(B); |
|||
double b, c; |
|||
bool bnz = true; |
|||
Point[] res; |
|||
if (abs(B) >= EPS) { |
|||
b = 2 * (A * C + A * B * y0 - sq(B) * x0); |
|||
c = sq(C) + 2 * B * C * y0 - sq(B) * (sq(r) - sq(x0) - sq(y0)); |
|||
} else { |
|||
b = 2 * (B * C + A * B * x0 - sq(A) * y0); |
|||
c = sq(C) + 2 * A * C * x0 - sq(A) * (sq(r) - sq(x0) - sq(y0)); |
|||
bnz = false; |
|||
} |
|||
auto d = sq(b) - 4 * a * c; // discriminant |
|||
if (d < 0) { |
|||
return res; |
|||
} |
|||
auto within(double x, double y) { |
|||
auto d1 = sqrt(sq(x2 - x1) + sq(y2 - y1)); // distance between end-points |
|||
auto d2 = sqrt(sq(x - x1) + sq(y - y1)); // distance from point to one end |
|||
auto d3 = sqrt(sq(x2 - x) + sq(y2 - y)); // distance from point to other end |
|||
auto delta = d1 - d2 - d3; |
|||
return abs(delta) < EPS; // true if delta is less than a small tolerance |
|||
} |
|||
auto fx(double x) { |
|||
return -(A * x + C) / B; |
|||
} |
|||
auto fy(double y) { |
|||
return -(B * y + C) / A; |
|||
} |
|||
auto rxy(double x, double y) { |
|||
if (!segment || within(x, y)) { |
|||
res ~= Point(x, y); |
|||
} |
|||
} |
|||
double x, y; |
|||
if (d == 0.0) { |
|||
// line is tangent to circle, so just one intersect at most |
|||
if (bnz) { |
|||
x = -b / (2 * a); |
|||
y = fx(x); |
|||
rxy(x, y); |
|||
} else { |
|||
y = -b / (2 * a); |
|||
x = fy(y); |
|||
rxy(x, y); |
|||
} |
|||
} else { |
|||
// two intersects at most |
|||
d = sqrt(d); |
|||
if (bnz) { |
|||
x = (-b + d) / (2 * a); |
|||
y = fx(x); |
|||
rxy(x, y); |
|||
x = (-b - d) / (2 * a); |
|||
y = fx(x); |
|||
rxy(x, y); |
|||
} else { |
|||
y = (-b + d) / (2 * a); |
|||
x = fy(y); |
|||
rxy(x, y); |
|||
y = (-b - d) / (2 * a); |
|||
x = fy(y); |
|||
rxy(x, y); |
|||
} |
|||
} |
|||
return res; |
|||
} |
|||
void main() { |
|||
writeln("The intersection points (if any) between:"); |
|||
auto cp = Point(3.0, -5.0); |
|||
auto r = 3.0; |
|||
writeln(" A circle, center ", cp, " with radius ", r, ", and:"); |
|||
auto p1 = Point(-10.0, 11.0); |
|||
auto p2 = Point(10.0, -9.0); |
|||
writeln(" a line containing the points ", p1, " and ", p2, " is/are:"); |
|||
writeln(" ", intersects(p1, p2, cp, r, false)); |
|||
p2 = Point(-10.0, 12.0); |
|||
writeln(" a segment starting at ", p1, " and ending at ", p2, " is/are:"); |
|||
writeln(" ", intersects(p1, p2, cp, r, true)); |
|||
p1 = Point(3.0, -2.0); |
|||
p2 = Point(7.0, -2.0); |
|||
writeln(" a horizontal line containing the points ", p1, " and ", p2, " is/are:"); |
|||
writeln(" ", intersects(p1, p2, cp, r, false)); |
|||
cp = Point(0.0, 0.0); |
|||
r = 4.0; |
|||
writeln(" A circle, center ", cp, " with radius ", r, ", and:"); |
|||
p1 = Point(0.0, -3.0); |
|||
p2 = Point(0.0, 6.0); |
|||
writeln(" a vertical line containing the points ", p1, " and ", p2, " is/are:"); |
|||
writeln(" ", intersects(p1, p2, cp, r, false)); |
|||
writeln(" a vertical segment containing the points ", p1, " and ", p2, " is/are:"); |
|||
writeln(" ", intersects(p1, p2, cp, r, true)); |
|||
cp = Point(4.0, 2.0); |
|||
r = 5.0; |
|||
writeln(" A circle, center ", cp, " with radius ", r, ", and:"); |
|||
p1 = Point(6.0, 3.0); |
|||
p2 = Point(10.0, 7.0); |
|||
writeln(" a line containing the points ", p1, " and ", p2, " is/are:"); |
|||
writeln(" ", intersects(p1, p2, cp, r, false)); |
|||
p1 = Point(7.0, 4.0); |
|||
p2 = Point(11.0, 8.0); |
|||
writeln(" a segment starting at ", p1, " and ending at ", p2, " is/are:"); |
|||
writeln(" ", intersects(p1, p2, cp, r, true)); |
|||
}</lang> |
}</lang> |
||
{{out}} |
{{out}} |