Line circle intersection: Difference between revisions

Content added Content deleted
(Added Wren)
Line 1,579: Line 1,579:
a segment starting at (7, 4) and ending at (11, 8) is/are:
a segment starting at (7, 4) and ending at (11, 8) is/are:
[(8, 5)]</pre>
[(8, 5)]</pre>

=={{header|Nim}}==
{{trans|Go}}
<lang Nim>import math, strutils

const Eps = 1e-14

type Point = tuple[x, y: float]

func `$`(p: Point): string =
let x = if p.x == 0.0: 0.0 else: p.x
let y = if p.y == 0.0: 0.0 else: p.y
"($1, $2)".format(x, y)


func intersects(p1, p2, cp: Point; r: float; segment: bool): seq[Point] =
let
(x0, y0) = cp
(x1, y1) = p1
(x2, y2) = p2
A = y2 - y1
B = x1 - x2
C = x2 * y1 - x1 * y2
var
a = A^2 + B^2
b, c: float
bnz = true
if abs(B) >= Eps:
b = 2 * (A * C + A * B * y0 - B^2 * x0)
c = C^2 + 2 * B * C * y0 - B^2 * (r^2 - x0^2 - y0^2)
else:
b = 2 * (B * C + A * B * x0 - A^2 * y0)
c = C^2 + 2 * A * C * x0 - A^2 * (r^2 - x0^2 - y0^2)
bnz = false
let d = b^2 - 4 * a * c
if d < 0: return # Line & circle don't intersect.

func within(x, y: float): bool =
## Checks whether a point is within a segment.
let
d1 = sqrt((x2 - x1)^2 + (y2 - y1)^2) # Distance between end-points.
d2 = sqrt((x - x1)^2 + (y - y1)^2) # Distance from point to one end.
d3 = sqrt((x2 - x)^2 + (y2 - y)^2) # Distance from point to other end.
delta = d1 - d2 - d3
result = abs(delta) < Eps # True if delta is less than a small tolerance.

var x, y: float
template fx: float = -(A * x + C) / B
template fy: float = -(B * y + C) / A
template rxy() =
if not segment or within(x, y):
result.add (x, y)

if d == 0:
# Line is tangent to circle, so just one intersect at most.
if bnz:
x = -b / (2 * a)
y = fx()
rxy()
else:
y = -b / (2 * a)
x = fy()
rxy()
else:
# Two intersects at most.
let d = sqrt(d)
if bnz:
x = (-b + d) / (2 * a)
y = fx()
rxy()
x = (-b - d) / (2 * a)
y = fx()
rxy()
else:
y = (-b + d) / (2 * a)
x = fy()
rxy()
y = (-b - d) / (2 * a)
x = fy()
rxy()


when isMainModule:

var cp: Point = (3.0, -5.0)
var r = 3.0
echo "The intersection points (if any) between:"
echo "\n A circle, center (3, -5) with radius 3, and:"
echo "\n a line containing the points (-10, 11) and (10, -9) is/are:"
echo " ", intersects((-10.0, 11.0), (10.0, -9.0), cp, r, false)
echo "\n a segment starting at (-10, 11) and ending at (-11, 12) is/are"
echo " ", intersects((-10.0, 11.0), (-11.0, 12.0), cp, r, true)
echo "\n a horizontal line containing the points (3, -2) and (7, -2) is/are:"
echo " ", intersects((3.0, -2.0), (7.0, -2.0), cp, r, false)
cp = (0.0, 0.0)
r = 4.0
echo "\n A circle, center (0, 0) with radius 4, and:"
echo "\n a vertical line containing the points (0, -3) and (0, 6) is/are:"
echo " ", intersects((0.0, -3.0), (0.0, 6.0), cp, r, false)
echo "\n a vertical segment starting at (0, -3) and ending at (0, 6) is/are:"
echo " ", intersects((0.0, -3.0), (0.0, 6.0), cp, r, true)
cp = (4.0, 2.0)
r = 5.0
echo "\n A circle, center (4, 2) with radius 5, and:"
echo "\n a line containing the points (6, 3) and (10, 7) is/are:"
echo " ", intersects((6.0, 3.0), (10.0, 7.0), cp, r, false)
echo "\n a segment starting at (7, 4) and ending at (11, 8) is/are:"
echo " ", intersects((7.0, 4.0), (11.0, 8.0), cp, r, true)</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.0, -5.0), (3.0, -2.0)]

a segment starting at (-10, 11) and ending at (-11, 12) is/are
@[]

a horizontal line containing the points (3, -2) and (7, -2) is/are:
@[(3.0, -2.0)]

A circle, center (0, 0) with radius 4, and:

a vertical line containing the points (0, -3) and (0, 6) is/are:
@[(0.0, 4.0), (0.0, -4.0)]

a vertical segment starting at (0, -3) and ending at (0, 6) is/are:
@[(0.0, 4.0)]

A circle, center (4, 2) with radius 5, and:

a line containing the points (6, 3) and (10, 7) is/are:
@[(8.0, 5.0), (1.0, -2.0)]

a segment starting at (7, 4) and ending at (11, 8) is/are:
@[(8.0, 5.0)]</pre>


=={{header|Perl}}==
=={{header|Perl}}==