Point clouds often contain measurements that lie inside the region formed by their outermost samples. A convex hull reduces that cloud to its smallest convex boundary, which makes the perimeter and enclosed area available for later geometry work.

SciPy's scipy.spatial.ConvexHull accepts a two-dimensional NumPy array and delegates hull construction to Qhull. The returned vertices indexes preserve counterclockwise order for 2-D input, so indexing the original array produces an ordered polygon boundary.

Two interior samples are included to show that they do not become boundary vertices. For a 2-D hull, SciPy reports the perimeter through hull.area and the polygon area through hull.volume; a shoelace calculation independently cross-checks the area.

Steps to calculate a convex hull with SciPy:

  1. Create the initial convex_hull_demo.py script with SciPy imports and a two-dimensional point array.
    $ cat > convex_hull_demo.py <<'PY'
    import numpy as np
    from scipy.spatial import ConvexHull
    
    points = np.array([
        [0.0, 0.0],
        [2.0, 0.0],
        [2.0, 1.5],
        [0.0, 1.0],
        [0.8, 0.5],
        [1.2, 0.9],
    ])
    PY

    The first four points form the outer quadrilateral, while the last two points lie inside it.

  2. Append the hull calculation and ordered boundary extraction to convex_hull_demo.py.
    $ cat >> convex_hull_demo.py <<'PY'
    
    hull = ConvexHull(points)
    boundary = points[hull.vertices]
    PY
  3. Append the boundary coordinate and measurement report to convex_hull_demo.py.
    $ cat >> convex_hull_demo.py <<'PY'
    
    print("boundary vertex indexes:", hull.vertices.tolist())
    print("boundary coordinates:")
    for index, coordinates in zip(hull.vertices, boundary):
        print(f"  {index}: ({coordinates[0]:.1f}, {coordinates[1]:.1f})")
    print(f"perimeter: {hull.area:.3f}")
    print(f"area: {hull.volume:.3f}")
    PY

    The last two points sit inside the quadrilateral, so they should not appear in hull.vertices.

  4. Append an independent shoelace-area check to convex_hull_demo.py.
    $ cat >> convex_hull_demo.py <<'PY'
    
    next_boundary = np.roll(boundary, -1, axis=0)
    shoelace_area = 0.5 * abs(
        np.sum(boundary[:, 0] * next_boundary[:, 1])
        - np.sum(boundary[:, 1] * next_boundary[:, 0])
    )
    np.testing.assert_allclose(hull.volume, shoelace_area)
    print(f"shoelace area check: {shoelace_area:.3f}")
    PY

    For 2-D input, hull.area is the perimeter and hull.volume is the polygon area. In higher dimensions, the same attributes mean surface area and volume.

  5. Run convex_hull_demo.py to calculate the boundary, perimeter, and area.
    $ python3 convex_hull_demo.py
    boundary vertex indexes: [0, 1, 2, 3]
    boundary coordinates:
      0: (0.0, 0.0)
      1: (2.0, 0.0)
      2: (2.0, 1.5)
      3: (0.0, 1.0)
    perimeter: 6.562
    area: 2.500
    shoelace area check: 2.500