Courbes de Bézier

Voici une proposition de correction de l'exercice 2.18 du poly d'analyse numérique sur les courbes de Bézier.

Haskell
import Graphics.EasyPlot
 
type Point = (Float,Float)
 
mapT :: (Float -> Float) -> Point -> Point
mapT f (a1, a2) = (f a1, f a2)
 
zipT :: (Float -> Float -> Float) -> Point -> Point -> Point
zipT f (a,b) (c,d) = (f a c, f b d)
 
infixr 4 @*
(@*) :: Float -> Point -> Point
(@*) k p = mapT (*k) p
 
infixr 2 @+
(@+) :: Point -> Point -> Point
(@+) p1 p2 = zipT (+) p1 p2
 
(@-) :: Point -> Point -> Point
(@-) p1 p2 = zipT (-) p1 p2
 
bezier2 :: [Point] -> [Graph2D Float Float]
bezier2 [p0,p1,p2] =
    let m = \ t -> (1 - t)**2 @* p0 @+ 2*t*(1 - t) @* p1  @+ t**2 @* p2 in
    [ 
    Data2D [Title "Courbe de Bézier d'ordre 2", Color Blue,  Style Lines] []  [m t | t <-  [0, 2**(-8) .. 1]],
    Data2D [Title "Direction de départ", Color Green, Style Lines] []  [p0,p1],
    Data2D [Title "Direction d'arrivée", Color Red  , Style Lines] []  [p1,p2]
    ]
bezier2 _ = []
 
 
 
bezier3 :: [Point] -> [Graph2D Float Float]
bezier3 [p0,p1,p2,p3] =
    let m = \ t -> (1 - t)**3 @* p0 @+ 3*t*(1 - t)**2 @* p1  @+ 3*(1 - t)*t**2 @* p2  @+ t**3 @* p3 in
    [ 
    Data2D [Title "", Color Blue,  Style Lines] []  [m t | t <-  [0, 2**(-8) .. 1]],
    Data2D [Title "", Color Green, Style Lines] []  [p0,p1],
    Data2D [Title "", Color Red  , Style Lines] []  [p2,p3]
    ]
bezier3 _ = []
 
 
beziaux :: [Point] -> [Point]
-- Rajoute les points pour que la courbe soit de classe C1
beziaux (p1:p2:p3:p4:xs) =
    p1:p2:p3:p4:(beziaux (p4:((2 @* p4) @-  p3):xs))
beziaux _ = []
 
bezierP :: [Point] -> [Graph2D Float Float]
-- Colle les bouts de bezier3
bezierP [] = []
bezierP listeP =
    let (x1,x2) = splitAt 4 listeP in
    (bezier3 x1) ++ (bezierP x2)
 
bezier :: TerminalType -> [Point] -> IO Bool
-- crée le graphique avec le type de terminal en option (X11, PDF, ...)
bezier option listeP = plot option (bezierP $ beziaux listeP)
 
 
--bezier X11 [(0,2),(0,3),(0,6),(-2,6),(-4,2),(-4,0),(0,-10),(0,-10),(4,-2),(4,0),(4,6),(2,6),(0,3),(0,2)]
 
bspline3 :: [Point] -> [Graph2D Float Float]
bspline3 [p0,p1,p2,p3] =
    let m = \ t -> (1/6) @* ((1 - t)**3 @* p0 @+ (3*t**3 -6*t**2 +4) @* p1  @+ (-3*t**3 + 3*t**2 + 3*t + 1) @* p2  @+ t**3 @* p3)  in
    [ 
    Data2D [Title "", Color Blue,  Style Lines] []  [m t | t <-  [0, 0.01 .. 1]],
    Data2D [Title "", Color Green, Style Lines] []  [p0,p1],
    Data2D [Title "", Color Red  , Style Lines] []  [p2,p3]
    ]
bspline3 _ = []
 
bsplinaux :: [Point] -> [Point]
-- Rajoute les points pour que la courbe soit de classe C1
bsplinaux (p1:p2:p3:p4:xs) =
    p1:p2:p3:p4:(bsplinaux (p2:p3:p4:xs))
bsplinaux _ = []
 
bsplineP :: [Point] -> [Graph2D Float Float]
-- Colle les bouts de bezier3
bsplineP [] = []
bsplineP listeP =
    let (x1,x2) = (take 4 listeP, drop 4 listeP) in
    (bspline3 x1) ++ (bsplineP x2)
 
bspline :: TerminalType -> [Point] -> IO Bool
-- crée le graphique avec le type de terminal en option (X11, PDF, ...)
bspline option listeP = plot option (bsplineP $ bsplinaux listeP)

courtesy of webmatter.de