Given a set of points in the plane, find the circle of minimum radius that encloses all points.
This is also known as the smallest enclosing circle problem or minimum bounding circle problem.
Welzl's algorithm (1991) is a randomized incremental algorithm that runs in expected linear time O(n).
- Randomly permute the input points
- Maintain a current circle that encloses processed points
- When a point lies outside the current circle, recursively compute a new circle that must include this point on its boundary
- The recursion uses a "support set" of points that must lie on the circle's boundary
function welzl(P, R):
if P is empty or |R| = 3:
return trivial_circle(R)
choose random p ∈ P
D = welzl(P \ {p}, R)
if p ∈ D:
return D
else:
return welzl(P \ {p}, R ∪ {p})
- Expected O(n) where n is number of points
- Worst case O(n!) but practically very efficient
- O(n) due to recursion stack
Examines all possible circles defined by:
- Single points (radius 0)
- Pairs of points (diameter circle)
- Triples of points (circumcircle)
Time complexity: O(n⁴) - only suitable for small n (≤ 10)
- Stores coordinates as numpy array
- Supports n-dimensional points (though some operations are 2D-specific)
- Methods for distance calculation and vector operations
- Stores center (Point) and radius
contains()method checks if a point is inside (with tolerance)- Static methods for constructing circles from 1-3 points
-
circle_from_two_points(p1, p2):- Returns circle with diameter p1-p2
- Center is midpoint, radius is half distance
-
circle_from_three_points(p1, p2, p3):- Returns circumcircle through three points
- Uses determinant formula for 2D points
- Handles collinear points by falling back to diameter circle
-
welzl_algorithm(points, support):- Recursive implementation of Welzl's algorithm
- Uses backtracking for support set management
-
min_circle_welzl(points, random_seed):- Wrapper that shuffles points and calls welzl_algorithm
- Supports reproducible results via random seed
from min_circle_cover import Point, min_circle_welzl
# Create points
points = [
Point([0, 0]),
Point([1, 0]),
Point([0, 1]),
Point([0.5, 0.5])
]
# Compute minimum enclosing circle
circle = min_circle_welzl(points, random_seed=42)
print(f"Center: {circle.center.coords}")
print(f"Radius: {circle.radius}")
# Check if all points are inside
for p in points:
print(f"Point {p.coords} inside: {circle.contains(p)}")circle_from_three_pointsuses 2D-specific formula- Base case for Welzl assumes at most 3 support points (in 2D)
- A sphere in d dimensions is defined by d+1 points in general position
- Welzl's algorithm generalizes with support set size ≤ d+1
- Circumsphere calculation requires solving linear equations
-
Replace
circle_from_three_pointswithsphere_from_pointsthat:- Solves linear system for center coordinates
- Uses more robust numerical methods (SVD for near-degenerate cases)
-
Update base case condition from
|R| = 3to|R| = d+1 -
Use dimensional geometry libraries for robust computations
class Sphere:
def __init__(self, center: Point, radius: float):
self.center = center
self.radius = radius
@staticmethod
def from_points(points: List[Point]) -> 'Sphere':
"""Compute smallest sphere enclosing given points (1 to d+1 points)."""
# Use linear algebra to solve for center
# Radius = distance from center to any point
pass
def welzl_nd(points: List[Point], support: List[Point], dimension: int) -> Sphere:
"""Welzl algorithm for d-dimensional spheres."""
if len(points) == 0 or len(support) == dimension + 1:
return Sphere.from_points(support)
# ... similar to 2D versionA complete implementation for arbitrary dimensions is provided in min_sphere_cover.py. This implementation generalizes Welzl's algorithm to d-dimensional spaces.
- Dimension-agnostic: Works for any dimension d ≥ 2
- Robust geometry: Uses least-squares solving for circumsphere computation
- Degeneracy handling: Falls back to subset methods for collinear/coplanar points
- Backward compatibility: For 2D points, results match the 2D circle implementation
from min_sphere_cover import PointND, min_sphere_welzl
# 3D points
points = [
PointND([0, 0, 0]),
PointND([1, 0, 0]),
PointND([0, 1, 0]),
PointND([0, 0, 1])
]
sphere = min_sphere_welzl(points, random_seed=42)
print(f"Center: {sphere.center.coords}")
print(f"Radius: {sphere.radius}")- The
SphereNDclass represents spheres in n-dimensional space SphereND.from_points()uses linear least squares to compute the smallest enclosing sphere for 1 to d+1 points- The Welzl algorithm is parameterized by dimension, with base case
|support| = d+1 - For degenerate cases (points lying on a lower-dimensional subspace), the algorithm automatically falls back to appropriate subsets
- Use tolerance (1e-9) for containment checks
- Handle near-collinear/coplanar points gracefully
- Consider using
decimalorfractionsfor exact arithmetic in small cases
- Welzl algorithm works well for thousands of points
- For very large sets, consider approximation algorithms
- Parallelization possible: partition points, compute circles, merge
- Computer Graphics: Bounding volumes for collision detection
- Geographic Information Systems: Service area determination
- Robotics: Workspace analysis and path planning
- Machine Learning: Support vector data description (one-class classification)
- Manufacturing: Minimum material usage for circular parts
The implementation includes:
- Unit tests for basic cases (1-3 points)
- Comparison with brute force for small n
- Random point generation for stress testing
To run tests:
python min_circle_cover.pyA visualization script visualize.py is provided to generate plots of points and their minimum enclosing circles.
- Points displayed as blue circles
- Minimum enclosing circle shown in red
- Circle center marked with red 'x'
- Radius shown as green dashed line
- Information box with center coordinates, radius, and coverage statistics
- Multiple example configurations
- Triangle: Three points forming a right triangle
- Random: 20 random points in [-5,5] range
- Clustered: Points in two Gaussian clusters with an outlier
python visualize.pyThis will generate three PNG files:
fig/min_circle_triangle.pngfig/min_circle_random.pngfig/min_circle_clustered.png
from visualize import plot_min_circle
from min_circle_cover import Point, min_circle_welzl
points = [Point([0,0]), Point([1,0]), Point([0,1])]
circle = min_circle_welzl(points, random_seed=42)
fig, ax = plot_min_circle(points, circle, "My Points")
plt.savefig('my_circle.png')- Welzl, E. (1991). Smallest enclosing disks (balls and ellipsoids). In New Results and New Trends in Computer Science.
- de Berg, M., et al. (2008). Computational Geometry: Algorithms and Applications.
- Wikipedia: Smallest-circle problem
- Optimize d-dimensional implementation for very high dimensions (d > 100)
- Add 3D visualization for sphere cover
- Implement approximation algorithms for very large sets
- Add support for weighted points
- Integrate with geometric libraries (Shapely, CGAL)
This implementation is provided for educational and research purposes.