Line circle intersection: Difference between revisions

Content added Content deleted
Line 1,691: Line 1,691:
The line is secant to circle with radius: 4
The line is secant to circle with radius: 4
</pre>
</pre>

=={{header|Ruby}}==
{{trans|C++}}
<lang ruby>EPS = 1e-14

def sq(x)
return x * x
end

def intersects(p1, p2, cp, r, segment)
res = []
(x0, y0) = cp
(x1, y1) = p1
(x2, y2) = p2
aa = y2 - y1
bb = x1 - x2
cc = x2 * y1 - x1 * y2
a = sq(aa) + sq(bb)
if bb.abs >= EPS then
b = 2 * (aa * cc + aa * bb * y0 - sq(bb) * x0)
c = sq(cc) + 2 * bb * cc * y0 - sq(bb) * (sq(r) - sq(x0) - sq(y0))
bnz = true
else
b = 2 * (bb * cc + aa * bb * x0 - sq(aa) * y0)
c = sq(cc) + 2 * aa * cc * x0 - sq(aa) * (sq(r) - sq(x0) - sq(y0))
bnz = false
end
d = sq(b) - 4 * a * c # disciminant
if d < 0 then
return res
end

# checks whether a point is within a segment
within = ->(x, y) {
d1 = Math.sqrt(sq(x2 - x1) + sq(y2 - y1)) # distance between end-points
d2 = Math.sqrt(sq(x - x1) + sq(y - y1)) # distance from point to one end
d3 = Math.sqrt(sq(x2 - x) + sq(y2 - y)) # distance from point to other end
delta = d1 - d2 - d3
return delta.abs < EPS # true if delta is less than a small tolerance
}

fx = ->(x) {
return -(aa * x + cc) / bb
}

fy = ->(y) {
return -(bb * y + cc) / aa
}

rxy = ->(x, y) {
if not segment or within.call(x, y) then
if x == 0.0 then
x = 0.0
end
if y == 0.0 then
y = 0.0
end
res << [x, y]
end
}

if d == 0.0 then
# line is tangent to circle, so just one intersect at most
if bnz then
x = -b / (2 * a)
y = fx.call(x)
rxy.call(x, y)
else
y = -b / (2 * a)
x = fy.call(y)
rxy.call(x, y)
end
else
# two intersects at most
d = Math.sqrt(d)
if bnz then
x = (-b + d) / (2 * a)
y = fx.call(x)
rxy.call(x, y)
x = (-b - d) / (2 * a)
y = fx.call(x)
rxy.call(x, y)
else
y = (-b + d) / (2 * a)
x = fy.call(y)
rxy.call(x, y)
y = (-b - d) / (2 * a)
x = fy.call(y)
rxy.call(x, y)
end
end

return res
end

def main
print "The intersection points (if any) between:\n"

cp = [3.0, -5.0]
r = 3.0
print " A circle, center %s with radius %f, and:\n" % [cp, r]

p1 = [-10.0, 11.0]
p2 = [10.0, -9.0]
print " a line containing the points %s and %s is/are:\n" % [p1, p2]
print " %s\n" % [intersects(p1, p2, cp, r, false)]

p2 = [-10.0, 12.0]
print " a segment starting at %s and ending at %s is/are:\n" % [p1, p2]
print " %s\n" % [intersects(p1, p2, cp, r, true)]

p1 = [3.0, -2.0]
p2 = [7.0, -2.0]
print " a horizontal line containing the points %s and %s is/are:\n" % [p1, p2]
print " %s\n" % [intersects(p1, p2, cp, r, false)]

cp = [0.0, 0.0]
r = 4.0
print " A circle, center %s with radius %f, and:\n" % [cp, r]

p1 = [0.0, -3.0]
p2 = [0.0, 6.0]
print " a vertical line containing the points %s and %s is/are:\n" % [p1, p2]
print " %s\n" % [intersects(p1, p2, cp, r, false)]
print " a vertical line segment containing the points %s and %s is/are:\n" % [p1, p2]
print " %s\n" % [intersects(p1, p2, cp, r, true)]

cp = [4.0, 2.0]
r = 5.0
print " A circle, center %s with radius %f, and:\n" % [cp, r]

p1 = [6.0, 3.0]
p2 = [10.0, 7.0]
print " a line containing the points %s and %s is/are:\n" % [p1, p2]
print " %s\n" % [intersects(p1, p2, cp, r, false)]

p1 = [7.0, 4.0]
p2 = [11.0, 8.0]
print " a segment starting at %s and ending at %s is/are:\n" % [p1, p2]
print " %s\n" % [intersects(p1, p2, cp, r, true)]
end

main()</lang>
{{out}}
<pre>The intersection points (if any) between:
A circle, center [3.0, -5.0] with radius 3.000000, and:
a line containing the points [-10.0, 11.0] and [10.0, -9.0] is/are:
[[6.0, -5.0], [3.0, -2.0]]
a segment starting at [-10.0, 11.0] and ending at [-10.0, 12.0] is/are:
[]
a horizontal line containing the points [3.0, -2.0] and [7.0, -2.0] is/are:
[[3.0, -2.0]]
A circle, center [0.0, 0.0] with radius 4.000000, and:
a vertical line containing the points [0.0, -3.0] and [0.0, 6.0] is/are:
[[0.0, 4.0], [0.0, -4.0]]
a vertical line segment containing the points [0.0, -3.0] and [0.0, 6.0] is/are:
[[0.0, 4.0]]
A circle, center [4.0, 2.0] with radius 5.000000, and:
a line containing the points [6.0, 3.0] and [10.0, 7.0] is/are:
[[8.0, 5.0], [1.0, -2.0]]
a segment starting at [7.0, 4.0] and ending at [11.0, 8.0] is/are:
[[8.0, 5.0]]</pre>


=={{header|Swift}}==
=={{header|Swift}}==