Smallest enclosing circle problem: Difference between revisions
Content added Content deleted
(added Raku programming solution) |
|||
Line 341: | Line 341: | ||
Radius is: 2.7946020036995454 |
Radius is: 2.7946020036995454 |
||
</pre> |
</pre> |
||
=={{header|Nim}}== |
|||
{{trans|Go}} |
|||
{{trans|Wren}} |
|||
<lang Nim>import math, random, strutils |
|||
type |
|||
Point = tuple[x, y: float] |
|||
Circle = tuple[c: Point; r: float] |
|||
func `$`(p: Point): string = |
|||
## Return the string representation of a point. |
|||
"($1, $2)".format(p.x, p.y) |
|||
func dist(a, b: Point): float = |
|||
## Return the distance between two points. |
|||
hypot(a.x - b.x, a.y - b.y) |
|||
func getCircleCenter(bx, by, cx, cy: float): Point = |
|||
## Return the center of a circle defined by three points. |
|||
let |
|||
b = bx * bx + by * by |
|||
c = cx * cx + cy * cy |
|||
d = bx * cy - by * cx |
|||
result = ((cy * b - by * c) / (2 * d), (bx * c - cx * b) / (2 * d)) |
|||
func contains(ci: Circle; p: Point): bool = |
|||
## Return whether a circle contains the point 'p'. |
|||
## Used by 'in' and 'notin'. |
|||
dist(ci.c, p) <= ci.r |
|||
func contains(ci: Circle; ps: seq[Point]): bool = |
|||
## Return whether a circle contains a slice of points. |
|||
## Used by 'in'. |
|||
for p in ps: |
|||
if p notin ci: return false |
|||
result = true |
|||
func `$`(ci: Circle): string = |
|||
## Return the string representation of a circle. |
|||
"Center $1, Radius $2".format(ci.c, ci.r) |
|||
func circleFrom3(a, b, c: Point): Circle = |
|||
## Return the smallest circle that intersects three points. |
|||
var i = getCircleCenter(b.x - a.x, b.y - a.y, c.x - a.x, c.y - a.y) |
|||
i.x += a.x |
|||
i.y += a.y |
|||
result = (c: i, r: dist(i, a)) |
|||
func circleFrom2(a, b: Point): Circle = |
|||
## Return the smallest circle that intersects two points. |
|||
let c = ((a.x + b.x) * 0.5, (a.y + b.y) * 0.5) |
|||
result = (c: c, r: dist(a, b) * 0.5) |
|||
func secTrivial(rs: seq[Point]): Circle = |
|||
## Return the smallest enclosing circle for n <= 3. |
|||
case rs.len |
|||
of 0: return ((0.0, 0.0), 0.0) |
|||
of 1: return (rs[0], 0.0) |
|||
of 2: return circleFrom2(rs[0], rs[1]) |
|||
of 3: discard |
|||
else: raise newException(ValueError, "There shouldn't be more than three points.") |
|||
# Three points. |
|||
for i in 0..1: |
|||
for j in (i + 1)..2: |
|||
let c = circleFrom2(rs[i], rs[j]) |
|||
if rs in c: return c |
|||
result = circleFrom3(rs[0], rs[1], rs[2]) |
|||
proc welzl(ps: var seq[Point]; rs: seq[Point]; n: int): Circle = |
|||
## Helper function for Welzl method. |
|||
var rc = rs |
|||
if n == 0 or rc.len == 3: return secTrivial(rc) |
|||
let idx = rand(n-1) |
|||
let p = ps[idx] |
|||
swap ps[idx], ps[n-1] |
|||
let d = welzl(ps, rc, n-1) |
|||
if p in d: return d |
|||
rc.add p |
|||
result = welzl(ps, rc, n-1) |
|||
proc welzl(ps: seq[Point]): Circle = |
|||
# Applies the Welzl algorithm to find the SEC. |
|||
var pc = ps |
|||
pc.shuffle() |
|||
result = welzl(pc, @[], pc.len) |
|||
when isMainModule: |
|||
randomize() |
|||
const Tests = [@[(0.0, 0.0), (0.0, 1.0), (1.0, 0.0)], |
|||
@[(5.0, -2.0), (-3.0, -2.0), (-2.0, 5.0), (1.0, 6.0), (0.0, 2.0)]] |
|||
for test in Tests: |
|||
echo welzl(test)</lang> |
|||
{{out}} |
|||
<pre>Center (0.5, 0.5), Radius 0.7071067811865476 |
|||
Center (1.0, 1.0), Radius 5.0</pre> |
|||
=={{header|Phix}}== |
=={{header|Phix}}== |