Courbes B-Spline

Objectifs d'apprentissage

À la fin de cette leçon, vous serez en mesure de :

  • Expliquer l'avantage du contrôle local des B-splines par rapport à Bézier
  • Construire les fonctions de mélange cubiques
  • Tracer une courbe B-spline à partir de points de contrôle
  • Assurer le passage par les extrémités (points triplés)
  • Comparer les courbes de Bézier et B-spline

Prérequis

  • Courbes de Bézier
  • Polynômes cubiques par morceaux

Motivation : le contrôle local

Limitation des courbes de Bézier

Dans une courbe de Bézier, chaque point de contrôle influence toute la courbe. Modifier un seul point change l'ensemble de la forme.

Pour les applications de conception (CAO), cela pose problème : un designer qui veut ajuster une petite partie de la courbe doit anticiper les effets globaux.

L'avantage des B-splines

Les B-splines (Basis splines) offrent un contrôle local : modifier un point de contrôle n'affecte qu'une portion limitée de la courbe.

💡

Comparaison

  • Bézier : 1 point modifié → toute la courbe change
  • B-spline : 1 point modifié → seule la région voisine change

Les fonctions de mélange cubiques

Définition

Une B-spline cubique uniforme utilise 4 fonctions de mélange définies sur u[0,1]u \in [0, 1] :

b1(u)=(1u)36b_{-1}(u) = \frac{(1-u)^3}{6}
b0(u)=3u36u2+46b_0(u) = \frac{3u^3 - 6u^2 + 4}{6}
b1(u)=3u3+3u2+3u+16b_1(u) = \frac{-3u^3 + 3u^2 + 3u + 1}{6}
b2(u)=u36b_2(u) = \frac{u^3}{6}

Propriétés

PropriétéDescription
Partition de l'unitéb1+b0+b1+b2=1b_{-1} + b_0 + b_1 + b_2 = 1 pour tout uu
Non-négativitébi(u)0b_i(u) \geq 0
Support localChaque fonction ne couvre que 4 segments
Symétrieb1(u)=b2(1u)b_{-1}(u) = b_2(1-u), b0(u)=b1(1u)b_0(u) = b_1(1-u)

Valeurs aux extrémités

Fonctionu = 0u = 1
b1b_{-1}1/60
b0b_04/61/6
b1b_11/64/6
b2b_201/6

Définition d'une courbe B-spline

Formulation

Une courbe B-spline cubique définie par les points de contrôle Pi1,Pi,Pi+1,Pi+2P_{i-1}, P_i, P_{i+1}, P_{i+2} est :

Bi(u)=b1(u)Pi1+b0(u)Pi+b1(u)Pi+1+b2(u)Pi+2\mathbf{B}_i(u) = b_{-1}(u) P_{i-1} + b_0(u) P_i + b_1(u) P_{i+1} + b_2(u) P_{i+2}

pour u[0,1]u \in [0, 1].

Courbe complète

Pour n+1n+1 points de contrôle P0,P1,,PnP_0, P_1, \ldots, P_n, la courbe est composée de n2n-2 segments B-spline raccordés :

B(u)=Bi(ui+1)pour u[i1,i],i=1,,n2\mathbf{B}(u) = \mathbf{B}_i(u - i + 1) \quad \text{pour } u \in [i-1, i], \quad i = 1, \ldots, n-2

Représentation matricielle

Forme matricielle

Bi(u)=16UMbPi\mathbf{B}_i(u) = \frac{1}{6} \mathbf{U} \cdot M_b \cdot \mathbf{P}_i

où :

U=(u3u2u1)\mathbf{U} = \begin{pmatrix} u^3 & u^2 & u & 1 \end{pmatrix}
Mb=(1331363030301410)M_b = \begin{pmatrix} -1 & 3 & -3 & 1 \\ 3 & -6 & 3 & 0 \\ -3 & 0 & 3 & 0 \\ 1 & 4 & 1 & 0 \end{pmatrix}
Pi=(Pi1PiPi+1Pi+2)\mathbf{P}_i = \begin{pmatrix} P_{i-1} \\ P_i \\ P_{i+1} \\ P_{i+2} \end{pmatrix}

Comparaison avec Bézier

AspectBézierB-spline
MatriceMBezM_{Bez}16Mb\frac{1}{6} M_b
Facteur11/6
Passage aux extrémitésOui (toujours)Non (par défaut)

Le problème du passage par les extrémités

Observation

Contrairement aux courbes de Bézier, une B-spline ne passe pas automatiquement par ses points de contrôle extrêmes.

En u=0u = 0 :

B1(0)=16P0+46P1+16P2P0\mathbf{B}_1(0) = \frac{1}{6}P_0 + \frac{4}{6}P_1 + \frac{1}{6}P_2 \neq P_0

Solution : les points triplés

Pour forcer le passage par P0P_0, on triple le premier point de contrôle :

P2=P1=P0P_{-2} = P_{-1} = P_0

Ainsi, le segment B1\mathbf{B}_{-1} utilise trois fois P0P_0 :

B1(0)=16P0+46P0+16P0=P0\mathbf{B}_{-1}(0) = \frac{1}{6}P_0 + \frac{4}{6}P_0 + \frac{1}{6}P_0 = P_0

Visualisation interactive

En pratique

Pour une courbe B-spline passant par ses extrémités avec n+1n+1 points de contrôle « utiles », on définit :

  • P2=P1=P0P_{-2} = P_{-1} = P_0 (début)
  • Pn+1=Pn+2=PnP_{n+1} = P_{n+2} = P_n (fin)

Propriétés des B-splines

Contrôle local

Un point de contrôle PiP_i n'influence que les segments Bi2,Bi1,Bi,Bi+1\mathbf{B}_{i-2}, \mathbf{B}_{i-1}, \mathbf{B}_i, \mathbf{B}_{i+1}.

Continuité automatique

Aux jonctions entre segments, la courbe B-spline est automatiquement C2C^2 continue (fonction, dérivée première et dérivée seconde continues).

Convexité locale

Chaque segment est contenu dans l'enveloppe convexe de ses 4 points de contrôle.


Jonction de segments B-spline

Principe

Quand uu passe de 1 (fin d'un segment) à 0 (début du suivant), les groupes de points se décalent :

  • Segment ii : utilise Pi1,Pi,Pi+1,Pi+2P_{i-1}, P_i, P_{i+1}, P_{i+2}
  • Segment i+1i+1 : utilise Pi,Pi+1,Pi+2,Pi+3P_i, P_{i+1}, P_{i+2}, P_{i+3}

Les 3 points communs assurent la continuité C2C^2.

Visualisation

Si les points Pi1,Pi,Pi+1P_{i-1}, P_i, P_{i+1} sont alignés, la courbe passe « droit » entre les segments. Sinon, elle tourne de manière fluide.


Exemple numérique

Points de contrôle

Pointxy
P0P_000
P1P_112
P2P_232
P3P_340

Avec points triplés

Pour le passage par les extrémités :

  • P2=P1=P0=(0,0)P_{-2} = P_{-1} = P_0 = (0, 0)
  • P4=P5=P3=(4,0)P_4 = P_5 = P_3 = (4, 0)

Calcul en u = 0.5 (segment central)

Le segment central utilise P0,P1,P2,P3P_0, P_1, P_2, P_3 :

b1(0.5)=(0.5)36=0.1256=0.0208b_{-1}(0.5) = \frac{(0.5)^3}{6} = \frac{0.125}{6} = 0.0208
b0(0.5)=3(0.125)6(0.25)+46=0.3751.5+46=0.479b_0(0.5) = \frac{3(0.125) - 6(0.25) + 4}{6} = \frac{0.375 - 1.5 + 4}{6} = 0.479
b1(0.5)=0.375+0.75+1.5+16=2.8756=0.479b_1(0.5) = \frac{-0.375 + 0.75 + 1.5 + 1}{6} = \frac{2.875}{6} = 0.479
b2(0.5)=0.1256=0.0208b_2(0.5) = \frac{0.125}{6} = 0.0208
x(0.5)=0.0208×0+0.479×1+0.479×3+0.0208×4=2.0x(0.5) = 0.0208 \times 0 + 0.479 \times 1 + 0.479 \times 3 + 0.0208 \times 4 = 2.0
y(0.5)=0.0208×0+0.479×2+0.479×2+0.0208×0=1.916y(0.5) = 0.0208 \times 0 + 0.479 \times 2 + 0.479 \times 2 + 0.0208 \times 0 = 1.916

Comparaison Bézier vs B-spline

AspectBézierB-spline
ContrôleGlobalLocal
Passage aux extrémitésAutomatiqueNécessite points triplés
Continuité aux jonctionsÀ gérer manuellementAutomatiquement C²
IntuitivitéPlus simple à comprendrePlus puissant pour le design
ApplicationsPolices, icônesCAO, animation 3D

Extension aux surfaces

Surfaces B-spline

Une surface B-spline bicubique est définie par une grille de points de contrôle PijP_{ij} :

S(u,v)=ijPijbi(u)bj(v)\mathbf{S}(u, v) = \sum_{i} \sum_{j} P_{ij} \cdot b_i(u) \cdot b_j(v)

Ces surfaces sont très utilisées en modélisation 3D pour créer des formes organiques.


Algorithme Python

bspline.pypython
import numpy as np

def blend_functions(u):
  """
  Calcule les 4 fonctions de mélange B-spline cubiques.
  """
  u2, u3 = u * u, u * u * u

  b_m1 = (1 - u) ** 3 / 6
  b_0 = (3 * u3 - 6 * u2 + 4) / 6
  b_1 = (-3 * u3 + 3 * u2 + 3 * u + 1) / 6
  b_2 = u3 / 6

  return np.array([b_m1, b_0, b_1, b_2])

def bspline_segment(P, u):
  """
  Évalue un segment B-spline cubique.

  Paramètres:
      P : 4 points de contrôle [P_{i-1}, P_i, P_{i+1}, P_{i+2}]
      u : paramètre dans [0, 1]

  Retourne:
      point sur la courbe
  """
  b = blend_functions(u)
  return sum(b[i] * P[i] for i in range(4))

def bspline_curve(control_points, num_points=100, closed=False):
  """
  Génère une courbe B-spline complète.

  Paramètres:
      control_points : liste de points [(x, y), ...]
      num_points : nombre de points à générer par segment
      closed : si True, ferme la courbe

  Retourne:
      curve : tableau des points de la courbe
  """
  P = np.array(control_points, dtype=float)
  n = len(P) - 1

  if closed:
      # Ajouter des points pour fermer
      P = np.vstack([P[-1], P, P[0], P[1]])
  else:
      # Tripler les extrémités
      P = np.vstack([P[0], P[0], P, P[-1], P[-1]])

  n_segments = len(P) - 3
  curve = []

  for seg in range(n_segments):
      segment_points = P[seg:seg + 4]
      for u in np.linspace(0, 1, num_points, endpoint=(seg == n_segments - 1)):
          curve.append(bspline_segment(segment_points, u))

  return np.array(curve)

def bspline_matrix(P, u):
  """
  Évalue un segment B-spline par la forme matricielle.
  """
  M_b = np.array([
      [-1,  3, -3, 1],
      [ 3, -6,  3, 0],
      [-3,  0,  3, 0],
      [ 1,  4,  1, 0]
  ]) / 6

  U = np.array([u**3, u**2, u, 1])

  return U @ M_b @ P

# Exemple
control_points = [(0, 0), (1, 2), (3, 2), (4, 0)]

curve = bspline_curve(control_points, num_points=20)

print("Courbe B-spline :")
for i in range(0, len(curve), 10):
  print(f"  Point {i}: ({curve[i, 0]:.3f}, {curve[i, 1]:.3f})")

# Comparaison avec segment central
P = np.array(control_points)
print("\nSegment central (u=0.5):")
pt = bspline_segment(P, 0.5)
print(f"  ({pt[0]:.3f}, {pt[1]:.3f})")

Résumé

ConceptDescription
Fonctions de mélange4 fonctions cubiques b1,b0,b1,b2b_{-1}, b_0, b_1, b_2
Contrôle local1 point affecte seulement 4 segments
ContinuitéAutomatiquement C2C^2
Passage aux extrémitésPoints triplés : P2=P1=P0P_{-2} = P_{-1} = P_0
Représentation matricielleB(u)=16UMbP\mathbf{B}(u) = \frac{1}{6} \mathbf{U} M_b \mathbf{P}

Pour aller plus loin

La prochaine leçon abordera l'interpolation de surfaces, où nous verrons comment étendre les techniques d'interpolation polynomiale aux fonctions de deux variables z=f(x,y)z = f(x, y).