Smallest enclosing circle problem: Difference between revisions

m
Line 40:
P = eltype(pts)
F = eltype(P)
projector, centers, square_radii = ProjectorStack(P[]), P[], F[]
centers = P[]
square_radii = F[]
empty_center = F(NaN) * first(pts)
GärtnerBoundary(centers, square_radii, projector, empty_center)
end
 
prefix(pts, i) = view(pts, 1:i)
Base.length(b::GärtnerBoundary) = length(b.centers)
Base.isempty(b::GärtnerBoundary) = length(b) == 0
 
function push_if_stable!(b::GärtnerBoundary, pt)
Line 58 ⟶ 52:
return true
end
q0, center = first(b.centers), b.centers[end]
 
C, r2 = r2center =- q0, b.square_radii[end]
q0 = first(b.centers)
centerQm, M = pt - q0, b.centers[end]projector
C = center - q0
r2 = b.square_radii[end]
 
Qm = pt - q0
M = b.projector
Qm_bar = M*Qm
residue, e = Qm - Qm_bar, sqdist(Qm, C) - r2
z, tol = 2*sqnorm(residue), eps(eltype(pt)) * max(r2, one(r2))
 
e = sqdist(Qm, C) - r2
z = 2*sqnorm(residue)
 
tol = eps(eltype(pt)) * max(r2, one(r2))
isstable = abs(z) > tol
if isstable
Line 91 ⟶ 76:
pop!(b.projector)
end
return b
end
 
Line 100 ⟶ 85:
 
function isinside(pt, nsphere::NSphere; atol=0, rtol=0)
r2, R2 = sqdist(pt, center(nsphere)), sqradius(nsphere)
return r2 <= R2 || isapprox(r2, R2;atol=atol^2,rtol=rtol^2)
R2 = sqradius(nsphere)
r2 <= R2 || isapprox(r2, R2;atol=atol^2,rtol=rtol^2)
end
 
function allinside(pts, nsphere; kw...)
for pt in pts
isinside(pt, nsphere; kw...) || return false
end
true
end
allinside(pts, nsphere; kw...) = all(pt -> isinside(pt, nsphere; kw...), pts)
 
function move_to_front!(pts, i)
Line 121 ⟶ 99:
end
 
prefix(pts, i) = view(pts, 1:i)
Base.length(b::GärtnerBoundary) = length(b.centers)
Base.isempty(b::GärtnerBoundary) = length(b) == 0
center(b::NSphere) = b.center
radius(b::NSphere) = sqrt(b.sqradius)
Line 127 ⟶ 108:
sqdist(p1::AbstractVector, p2::AbstractVector) = sqnorm(p1-p2)
sqnorm(p) = sum(abs2,p)
ismaxlength(b::GärtnerBoundary) = length(b) == length(b.empty_center) + 1
 
function NSphere(b::GärtnerBoundary)
ifreturn isempty(b) ? NSphere(b.empty_center, 0.0) :
c =NSphere(b.centers[end], b.empty_centersquare_radii[end])
r2 = zero(eltype(c))
else
c = b.centers[end]
r2 = b.square_radii[end]
end
NSphere(c,r2)
end
 
function ismaxlength(b::GärtnerBoundary)
dim = length(b.empty_center)
length(b) == dim + 1
end
 
function welzl!(pts, bdry)
bdry_len, support_count, nsphere = length(bdry), 0, NSphere(bdry)
support_count = 0
nsphere = NSphere(bdry)
ismaxlength(bdry) && return nsphere, 0
for i in eachindex(pts)
Line 167 ⟶ 136:
function find_max_excess(nsphere, pts, k1)
T = eltype(first(pts))
e_max, k_max = T(-Inf), k1 -1
k_max = k1 -1
for k in k1:length(pts)
pt = pts[k]
Line 182 ⟶ 150:
function welzl(points, maxiterations=2000)
pts = deepcopy(points)
bdry, t = GärtnerBoundary(pts), 1
t = 1
nsphere, s = welzl!(prefix(pts, t), bdry)
for i in 1:maxiterations
Line 189 ⟶ 156:
P = eltype(pts)
F = eltype(P)
if e > <= eps(F) && break
pt = pts[k]
push_if_stable!(bdry, pt)
nsphere_new, s_new = welzl!(prefix(pts, s), bdry)
pop!(bdry)
move_to_front!(pts, k)
nsphere = nsphere_new
t, s = s t+ =1, ss_new + 1
s = s_new + 1
else
return nsphere
end
end
return nsphere
end
 
function testwelzl()
testdata =[
4,105

edits