Skip to article frontmatterSkip to article content
Site not loading correctly?

This may be due to an incorrect BASE_URL configuration. See the MyST Documentation for reference.

Chapter 95 — Midpoints and Interpolation

Prerequisites: ch094 (Distance Between Points)

Outcomes: Compute midpoints and weighted averages of points; Implement linear interpolation (lerp) between any two points; Understand interpolation as parameterized path traversal; Connect to animation, splines, and data imputation

Midpoint and Weighted Average

The midpoint of two points P and Q is: M = (P + Q) / 2 = ((x₁+x₂)/2, (y₁+y₂)/2)

The weighted average generalizes this: W(t) = (1-t)·P + t·Q, t ∈ [0, 1]

  • t = 0: W = P

  • t = 0.5: W = midpoint

  • t = 1: W = Q

  • t ∈ (0,1): W is between P and Q

This is linear interpolation (lerp). As t sweeps 0→1, W traces the line segment from P to Q.

Extrapolation: If t < 0 or t > 1, W falls outside the segment. This is valid mathematically but may not be physically meaningful.

(This is the same “parameterized path” idea as parametric curves in ch107.)

# --- Interpolation visualization ---
import numpy as np
import matplotlib.pyplot as plt
plt.style.use('seaborn-v0_8-whitegrid')

def lerp(P, Q, t):
    """Linear interpolation: (1-t)*P + t*Q."""
    return (1 - t) * np.asarray(P) + t * np.asarray(Q)

P = np.array([1.0, 1.0])
Q = np.array([5.0, 4.0])

t_vals = np.linspace(-0.3, 1.3, 200)
path = np.array([lerp(P, Q, t) for t in t_vals])

fig, ax = plt.subplots(figsize=(9, 6))
ax.plot(path[:,0], path[:,1], color='gray', linewidth=1, linestyle='--', label='Extrapolation')

t_seg = np.linspace(0, 1, 100)
seg = np.array([lerp(P, Q, t) for t in t_seg])
ax.plot(seg[:,0], seg[:,1], color='steelblue', linewidth=3, label='Segment (t∈[0,1])')

for t, color, label in [(0,'steelblue','P (t=0)'), (0.25,'green','t=0.25'), (0.5,'orange','Midpoint (t=0.5)'),
                         (0.75,'purple','t=0.75'), (1.0,'crimson','Q (t=1)')]:
    pt = lerp(P, Q, t)
    ax.plot(*pt, 'o', color=color, markersize=10, zorder=5)
    ax.annotate(label, pt, xytext=(5,5), textcoords='offset points', fontsize=9)

ax.set_xlabel('x'); ax.set_ylabel('y')
ax.set_title('Linear Interpolation: W(t) = (1-t)P + tQ'); ax.legend(fontsize=9)
plt.tight_layout(); plt.show()
C:\Users\user\AppData\Local\Temp\ipykernel_26608\3300307872.py:31: UserWarning: Glyph 8712 (\N{ELEMENT OF}) missing from font(s) Arial.
  plt.tight_layout(); plt.show()
c:\Users\user\OneDrive\Documents\book\.venv\Lib\site-packages\IPython\core\pylabtools.py:170: UserWarning: Glyph 8712 (\N{ELEMENT OF}) missing from font(s) Arial.
  fig.canvas.print_figure(bytes_io, **kw)
<Figure size 900x600 with 1 Axes>

Multi-Point Interpolation

# --- Interpolation along a path through multiple points ---
import numpy as np
import matplotlib.pyplot as plt
plt.style.use('seaborn-v0_8-whitegrid')

def lerp_path(waypoints, n_samples=200):
    """Linearly interpolate through a sequence of waypoints."""
    pts = np.array(waypoints)
    n = len(pts)
    # Parameter t: uniform from 0 to n-1
    t_vals = np.linspace(0, n-1, n_samples)
    result = []
    for t in t_vals:
        i = int(t)
        frac = t - i
        if i >= n-1:
            result.append(pts[-1])
        else:
            result.append(lerp(pts[i], pts[i+1], frac))
    return np.array(result)

waypoints = [(0,0),(2,3),(5,1),(7,4),(9,2)]
path = lerp_path(waypoints)

fig, ax = plt.subplots(figsize=(10, 5))
wp = np.array(waypoints)
ax.scatter(wp[:,0], wp[:,1], s=100, color='crimson', zorder=5, label='Waypoints')
for i, (x,y) in enumerate(waypoints):
    ax.annotate(f'W{i}', (x,y), xytext=(5,5), textcoords='offset points', fontsize=10)
ax.plot(path[:,0], path[:,1], color='steelblue', linewidth=2, label='Linear path')
ax.plot(wp[:,0], wp[:,1], 'k--', linewidth=1, alpha=0.3)
ax.set_title('Piecewise Linear Interpolation Through Waypoints')
ax.set_xlabel('x'); ax.set_ylabel('y'); ax.legend()
plt.tight_layout(); plt.show()

print("Total path length:", sum(np.linalg.norm(path[i+1]-path[i]) for i in range(len(path)-1)))
<Figure size 1000x500 with 1 Axes>
Total path length: 13.59085258013351

Applications

  • Animation: lerp from start pose to end pose over n_frames → smooth transition

  • Color blending: lerp(rgb_start, rgb_end, t) → gradient

  • Data imputation: missing value at time t → lerp between flanking observed values

  • Bézier curves (ch116): recursive lerp generates smooth curves through control points

  • Texture mapping in graphics: bilinear interpolation = lerp in 2 dimensions

Exercises

Easy 1. Find the midpoint of (2, 5) and (8, 1). Then find the point 1/3 of the way from P to Q.

Easy 2. Implement lerp_color(c1, c2, t) for RGB tuples. Blend red (255,0,0) and blue (0,0,255) at t=0, 0.25, 0.5, 0.75, 1.0.

Medium 1. Given GPS coordinates (lat, lon), lerp 10 interpolated points between two cities. (Assume flat Earth for simplicity.)

Medium 2. Implement bilinear interpolation for a 2D grid: given a 2D array of values and a fractional (i, j) index, return the interpolated value using lerp in both dimensions.

Hard. Implement smooth step interpolation: smoothstep(t) = 3t² - 2t³. Compare lerp vs smoothstep animation (plot both over 100 frames). Smoothstep has zero derivative at t=0 and t=1 — why does this matter for animation?

Summary

  • Midpoint: M = (P+Q)/2; weighted average: W(t) = (1-t)P + tQ

  • lerp traces the line segment from P to Q as t goes 0→1

  • Piecewise linear interpolation connects waypoints with straight segments

  • This is the foundation for Bézier curves, splines, and animation

Forward connections:

  • ch107 (Parametric Curves): lerp with t parameterizes all curves

  • ch116 (Bézier Curves): recursive lerp → smooth curves

  • ch285 (Regression): imputation strategies use interpolation