Connectés : 1
pFwiki :: start
formes pascaliennes
alain marty 06/12/2011
document en cours d'édition
.

immersion d'une pL4 (cubique) et d'une pS22 (quadrangle) dans une biquadrique (pS33). Considérée dans l'espace, la cubique est une pL12 [ (13-1) = (4-1)*[(3-1)+(3-1)] = 12 ]. Et la pS22 est une pS55 : elle est construite sur deux pL2 immergées qui sont des pL5 dans l'espace : [ (5-1) = (2-1)*[(3-1)+(3-1)] = 4 ], et un segment immergé dans cette pS55 sera une pL9 dans l'espace : [ (9-1) = (2-1)*[(5-1)+(5-1)] = 8 ]. L'immersion d'une pForme dans une pForme produit une pForme. On reste en famille et on parle le même langage !

Une pForme immergée dans une pForme est une pForme.

sommaire (and abstract)

  • introduction
  • 1) formes multilinéaires récursives
  • 10) divine récursion
  • 11) point
  • 12) segment
  • 13) facette gauche
  • 14) cube gauche
  • 15) hypercube gauche
  • 16) première généralisation
  • 2) diagonales
  • 20) sortir du linéaire
  • 21) facette gauche et quadrique
  • 23) biquadrique et cubique
  • 24) triquadrique et quintique
  • 25) tetracubique
  • 3) généralisation : les pFormes
  • 30) le triangle de Pascal
  • 31) définition générale
  • 32) propriétés
  • 321) subdivision
  • 322) élévation du degré
  • 323) reparamétrisation
  • 324) pFgetSubForm()
  • 325) pFgetSubPoint()
  • 326) pFgetPijk()
  • 327) transformations
  • 4) interpolations
  • 40) algèbre linéaire
  • 41) pôles et noeuds
  • 42) immersions
  • 421) pCourbe immergée dans une pSurface
  • 422) pSurface immergée dans une pSurface
  • 423) pSurface immergée dans un pVolume
  • 5) combinaisons
  • 50) travail sur les pFormes
  • 51) pFormes rationnelles
  • 511) coniques
  • 512) cônes, cylindres, tores et sphères
  • 513) nurbs
  • 52) concaténations
  • 521) splines quadriques
  • 522) splines cubiques
  • 53) combinaisons linéaires
  • 531) pSurfaces symétriques
  • 532) pSurfaces de Coons
  • 533) pSurfaces de Gordon
  • 54) produits cartésiens
  • 541) surfaces de révolution
  • 542) surfaces tubulaires
  • 55) ...
  • conclusion
  • code
  • références

introduction

On se propose de construire une famille de formes gauches (courbes, surfaces, volumes, hypervolumes) engendrées initialement par l'application récursive d'une opération simple :

« construire le milieu 
de deux points »

Mais comment écrire le milieu de deux points, et au delà toute combinaison de points ? On sait combiner linéairement des vecteurs dans un espace vectoriel. Mais l'espace des points (appelé espace affine, sans métrique définie) ne possède pas toutes les propriétés d'un espace vectoriel même s'il lui ressemble et notamment, toutes les combinaisons linéaires de points ne sont pas valables. On peut par exemple définir la somme de deux vecteurs de façon indépendante du repère, mais on ne peut pas le faire pour deux points. En revanche, la demi–somme de deux points produit un point invariant dans un changement de repère et constitue de ce fait une combinaison linéaire pondérée valable.

De manière générale, on montre que toute combinaison linéaire de n points est valable si elle satisfait à la condition :

iki.Pi = 1, avec i € [0,n-1]
Seront notamment correctes des expressions comme :
p = (p0 + p1)/2 
p = 2.p0 – p1
p = (2.p0 + p1)/3
p = (p0 + 3.p1 + 3.p2 + p3)/8

La première retourne le milieu de deux points, la seconde le point symétrique de p1 par rapport à p0, la troisième le point au tiers du segment [p0p1], la dernière le milieu d'une cubique [p0,p1,p2,p3]. On notera que tout ceci n'est qu'une autre expression des théorèmes bien connus sur les barycentres. Ceci ayant été précisé, nous pouvons construire une première famille de 'formes multilinéaires récursives' construites avec un couple d'opérations, l'étendre par application d'une opération de « diagonalisation », et enfin proposer la définition générale des formes pascaliennes.

Tous les exemples seront construits dans l'environnement Sketchup, depuis la console Ruby, sur la base de scripts écrits dans un fichier texte "PF/pFormes.rb". La bibliothèque "PF/pFlibs.rb" écrite dans le langage Ruby embarqué dans Sketchup définit l'ensemble des pFormes. La syntaxe correspondante sera appelée SRpF (Sketchup/Ruby/pFormes).

1) formes multilinéaires récursives

Au sommaire de cette section :

  • 10 récursion
  • 11 un point de R4
  • 12 un segment de droite
  • 13 une facette gauche
  • 14 un cube gauche
  • 15 un hypercube gauche
  • 16 première généralisation

L'application d'un couple d'opérations à un ensemble de points va nous permettre de générer naturellement les premières formes linéaires de la géométrie : des segments de droite, des facettes (gauches), des cubes (gauches), des hypercubes (gauches), et au-delà si nécessaire.

10) récursion

Les points de l'espace sont définis par des tableaux de nombres réels. Afin de préparer la construction des objets géométriques, on se propose de partitionner l'intervalle [0,1] en le divisant récursivement en deux :

  0     1       2       3       4
                            [...,...]
                    [0/8,1/8]
                    :       [...,...]
            [0/4,1/4]
            :       :       [...,...]
            :       [1/8,2/8]
            :               [...,...]
    [0/2,1/2]
    :       :               [...,...]
    :       :       [2/8,3/8]
    :       :       :       [...,...]
    :       [1/4,2/4]
    :               :       [...,...]
    :               [3/8,4/8]
    :                       [...,...]
[0,1]
    :                       [...,...]
    :               [4/8,5/8]
    :               :       [...,...]
    :       [2/4,3/4]
    :       :       :       [...,...]
    :       :       [5/8,6/8]
    :       :               [...,...]
    [1/2,2/2]
            :               [...,...]
            :       [6/8,7/8]
            :       :       [...,...]
            [3/4,4/4]
                    :       [...,...]
                    [7/8,8/8]
                            [...,...]

En s'arrêtant à l'étape 3) et une fois les doublons éliminés, on obtient le résultat suivant :

 [0.0, 0.125, 0.25, 0.375, 
           0.5, 0.625, 0.75, 0.875, 1.0] 
un peu de code

Pour obtenir "automatiquement" ce résultat - et aller sans mal beaucoup plus loin - on écrit les lignes suivantes dans la console Ruby de Sketchup :

1. ma_partition = Partition.new( [0,1] )
2. ma_partition.build( 3 )
3. ma_partition.draw()
  • La première ligne fait appel à une classe appelée "Partition" pour créer un objet appelé "ma_partition" initialisé avec le tableau de deux nombres [0,1],
  • La deuxième ligne commande à cet objet de se partitionner récursivement en trois étapes,
  • La troisième ligne commande à cet objet d'afficher le résultat.

Pour information, la classe "Partition" est définie ci-dessous en cinq fonctions :

class Partition

   def initialize( tab )
      @_in = tab
      @_last = @_in[@_in.length()-1]
      @_out = []
   end
	
   def build( rec ) 
      subdivision( @_in, rec )
      @_out.push( @_last )
   end
	
   def subdivision( tab, rec ) 
      if (rec >0)
         m = middle( tab[0], tab[1] )
         subdivision( [tab[0], m], rec-1 )
         subdivision( [m, tab[1]], rec-1 )
      else
         @_out.concat( tab )
         @_out.pop()
      end
   end
	
   def middle( a, b )
      return ( a+b )/2.0
   end
	
   def draw()
      return @_out
   end
	
end

Il faut noter que l'application du processus récursif pour une valeur infinie de "recursion" produit un ensemble infini et "dense" de points situés dans l'intervalle [0..1]. Un ensemble dense mais pas continu au sens mathématique du terme, car il n'est pas en bijection avec le corps R des nombres réels ; il suffit de penser aux valeurs 1/3 ou PI/4 qui, bien que dans contenues dans l'intervalle [0..1], ne lui appartiennent pas. Nous verrons que cela a une incidence sur la nature des formes géométriques que nous allons aborder.

la classe PF

La classe "Partition" est le prototype de la classe "PF" gérant la totalité des Formes Pascaliennes. Le code est disponible en fin de document. Son analyse sort du champ de ce document mais on retrouvera toujours dans les exemples présentés les trois phases principales "Création, Partition, Affichage" appliquées aux objets géométriques (segments, surfaces, volumes,...) du plus simple au plus complexe :

1. pForme = PF.new( tableau de points )
2. pForme.build( recursion )
3. pForme.draw( style )

11) point


figure 1.1 : un point

Les combinaisons linéaires de points envisagées plus haut sont exprimables dans un espace affine de dimension quelconque Rn. Pour des raisons qui seront données un peu plus loin, nous opèrerons sur des points toujours définis dans R4, en utilisant la forme dite des coordonnées homogènes ou forme projective : [x,y,z,w], associant au point de R4 le point de R3 défini par [x/w,y/w,z/w]. Dans un premier temps, on prendra par défaut w=1 et on oubliera qu'on travaille dans l'espace R4. On le retrouvera dans la section sur les coniques et les NURBS.

Dans la syntaxe SRpF, un point sera créé et affiché ainsi :

def point( m = 90 )
	pP = PF.new( [ m, m, m ] )
	pP.draw( "P" )
end

Dans cet exemple, les coordonnées du point sont [90,90,90] :

  • la méthode new() de la classe PF crée une pForme "point",
  • la méthode draw() l'affiche. Le paramètre "P" de la méthode draw() précise que le point est affiché ... comme un point !

12) segment


figure 1.2 : un segment

Deux points p0 et p1 étant donnés, nous en construisons un troisième, pm, situé au milieu :

pm = (p0 + p1)/2

Noter que la somme des coefficients est: 1/2 + 1/2 = 1. Ce troisième point pm donne naissance à deux couples de points (p0,pm) et (pm,p1), et à l'irrésistible envie de recommencer à gauche et à droite pour obtenir les points au 1/4 et au 3/4 et ainsi de suite.

Comme nous l'avons déjà vu concernant la partition de l'intervalle unité, l'application récursive de ce processus pour une valeur infinie de la récursion produit un ensemble infini et "dense" de points situés entre les deux points p0 et p1, un "segment de droite" que nous désignerons par pL2 (les raisons de cette notation seront données plus loin dans le texte) et que nous écrirons :

pL2 = [ p0, p1 ]

Pour les mêmes raisons cet ensemble de points (pL2) n'est pas à proprement parler un segment de droite tel qu'on le définit habituellement en géométrie. Si le processus récursif amène bien à un ensemble de points dont le nombre est aussi grand qu'on le souhaite, avec une distance entre chaque point tendant bien vers zéro, l'ensemble obtenu n'est pas continu et n'est pas "réellement" un segment de droite.

On définit habituellement dans Rn un segment de droite reliant un couple de points (p0, p1) comme l'ensemble des points p satisfaisant à l'application linéaire bijective :

p(t) = (1-t)•p0 + t•p1,
avec t dans l'intervalle [0,1] € R 

Cet ensemble de points est infini et continu (comme R), et des points comme p(1/3) ou p(k) avec k = racine(2)/2, peuvent bien être atteints sur ce segment de droite ; on a vu que tel n'est pas le cas de pL2 qui est en relation bijective avec l'ensemble des partitions de l'unité (1/2, 1/4, 1/8,...). On a dit d'un tel ensemble qu'il est dense, et c'est bien cette propriété de densité qui nous intéresse, notamment parce qu'elle nous permettra de retrouver le concept indispensable de tangente. Nous y reviendrons plus longuement dans la section 2, et pour la suite nous conviendrons d'assimiler notre pL2 à un "vrai" segment de droite et les formes dérivées (surfaces, volumes,...) aux formes continues classiques de la géométrie.

Dans la syntaxe SRpF, un segment sera créé et affiché ainsi :

def segment( m = 90, finesse = 3 )
	pL2 = PF.new( 
               [ [-m,-m,-m ], 
                 [ m, m, m ] ] )
	pL2.build( finesse )
	pL2.draw( "P" )
end

Dans cet exemple, le segment relie deux points de coordonnées [-90,-90,-90] et [90,90,90] :

  • la méthode new() crée une pForme segment à partir d'un tableau de deux points,
  • la méthode build() lance un processus récursif de construction d'un tableau de points distribués sur le segment ; on retrouve les résultats du paragraphe 10) sur la récursion :
  • pour finesse = 0, le tableau est limité aux deux points extrémités [ 0, 1 ]
  • pour finesse = 1, le tableau contient les points [ 0, 1/2, 1 ]
  • pour finesse = 2, le tableau contient les points [ 0, 1/4, 1/2, 3/4, 1 ]
  • etc ...
  • la méthode draw() affiche le segment. Le paramètre "P" précise que le segment est affiché ... comme une suite de points. Avec la valeur "L" pour ce paramètre le segment serait affiché comme une suite de segments.

13) facette quadrangle gauche


figure 1.3 : une facette gauche

Soient deux segments pL2_0 et pL2_1 construits sur les points (p00,p01) et (p10,p11). Considérant le segment construit sur les milieux respectifs des extrémités des segments pL2_0 et pL2_1 :

pL2_M = [ q0, q1 ] 
où q0 = (p00 + p10)/2 
et q1 = (p01 + p11)/2

Par analogie avec la construction du segment, l'application récursive de ce processus aux couples de segments à gauche (pL2_0,pL2_M) et à droite (pL2_M,pL2_1) produit un ensemble infini et dense de segments formant une portion de surface, un "quadrangle gauche" que nous désignerons par pS22 et que nous écrirons :

pS22 = [ pL2_0, pL2_1 ] 
     = [ p00, p01], [p10, p11] ] 

Comme pour le segment, cet ensemble de segments (pL2) n'est pas un quadrangle tel qu'on le définit habituellement en géométrie. Si le processus récursif amène bien à un ensemble de segments dont le nombre est aussi grand qu'on le souhaite, avec une distance entre chaque segment tendant bien vers zéro, l'ensemble obtenu n'est pas continu et n'est pas "réellement" une surface quadrangle. On définit habituellement dans Rn une surface quadrangle reliant un couple de segments ( [p00,p01], [p10,p11] ) comme l'ensemble des points p satisfaisant à l'application bilinéaire bijective :

p(u,v) = (1-u)•pL_0(v) + u•pL_1(v)
avec pL_0(v) = (1-v)•p00 + v•p01 
et   pL_1(v) = (1-v)•p10 + u•p11
p(u,v) = (1-u)•( (1-v)•p00 + v•p01 ) 
       +     u•( (1-v)•p10 + u•p11 ),
p(u,v) = (1-u)•(1-v)•p00 + u•(1-v)•p01 
       +     (1-u)•v•p10 +     u•v•p11,
avec u,v dans l'intervalle [0,1] € R

Pour la suite nous conviendrons d'assimiler notre pS22 à un quadrangle classique de la géométrie.

Dans la syntaxe SRpF, un quadrangle sera créé et affiché ainsi :

def quadrangle( m = 90, finesse = [3,3] )
	l2_0 = [ [ -m,-m, 0 ], 
                 [  m,-m, m ] ]
	l2_1 = [ [ -m, m, m ], 
                 [  m, m, 0 ] ]
	pS22 = PF.new( [ l2_0, l2_1 ] )
	pS22.build( finesse )
	pS22.draw( "S" )
end

Dans cet exemple, le quadrangle relie deux segments situés sur deux faces d'un cube de côtés [180,180,90] :

  • la méthode new() crée une pForme quadrangle appelée pS22 à partir de deux tableaux de deux points,
  • la méthode build() lance un processus récursif de construction d'un tableau carré de points distribués sur le quadrangle,
  • pour finesse = [0,0], le tableau est limité aux quatre points extrémités [0,1]*[0,1]
  • pour finesse = [1,1], le tableau contient les points [0,1/2,1]*[0,1/2,1]
  • pour finesse = [2,2], le tableau contient les points [0,1/4,1/2,3/4,1]*[0,1/4,1/2,3/4,1]
  • etc ...
  • la méthode draw() affiche le quadrangle. Le paramètre "S" précise que le quadrangle est affiché comme un ensemble de facettes triangulaires. Avec la valeur "L" pour ce paramètre le quadrangle serait affiché comme une famille de segments et avec la valeur "P" comme un tableau de points.

14) cube gauche


figure 1.4 : un cube gauche

Soient deux quadrangles pS22_0 et pS22_1 construits sur les couples de segments (pL2_00,pL2_01) et (pL2_10,pL2_11). Considérons le quadrangle pS22_M construit sur les milieux respectifs des extrémités des segments. Par analogie avec la construction du quadrangle, l'application récursive de de ce processus aux couples de quadrangles en haut (pS22_0,pS22_M) et en bas (pS22_M,pS22_1) produit un ensemble infini et dense de quadrangles formant une portion de volume, un "cuboïde" que nous désignerons par pV222 et que nous écrirons :

pV222 = [ pS22_0, pS22_1 ]
      = [ [ pL2_00, pL2_01 ], 
          [ pL2_10, pL2_11 ] ]
      = [ [ [p000, p001], [p010, p011] ], 
          [ [p100, p101], [p110, p111] ] ] 

Ici aussi, cet ensemble de quadrangles (pV222) n'est pas à proprement parler un volume tel qu'on le définit habituellement en géométrie. Si le processus récursif amène bien à un ensemble de quadrangles dont le nombre est aussi grand qu'on le souhaite, avec une distance entre chaque quadrangle tendant bien vers zéro, l'ensemble obtenu n'est pas continu et n'est pas "réellement" un volume. On définit habituellement dans Rn un cuboïde reliant un couple de quadrangles ( pS22_0, pS22_1 ) comme l'ensemble des points p satisfaisant à l'application trilinéaire bijective :

p(u,v,w) = 
     (1-u)•pS22_0(v,w) + u•pS22_1(v,w),
où pS22_0(v,w) = (1-u)•(1-v)•p000 
+ u•(1-v)•p001 + (1-u)•v•p010 + u•v•p011
et pS22_0(v,w) = (1-u)•(1-v)•p100 
+ u•(1-v)•p101 + (1-u)•v•p110 + u•v•p111
p(u,v,w) = 
(1-u)•(1-v)•(1-w)•p000 + ... + u•v•w•p111
avec u,v,w dans l'intervalle [0,1] € R 

Pour la suite nous conviendrons d'assimiler notre pV222 à un classique cuboïde de la géométrie.

Dans la syntaxe SRpF, un cuboïde sera créé et affiché ainsi :

def cuboide( m = 90, finesse = [3,3,3] )
pL2_00 = PF.new( 
      [ [ -m,-m, 0 ], [ m,-m, m ] ] )
pL2_01 = PF.new( 
      [ [ -m, m, m ], [ m, m, 0 ] ] )
pS22_0 = PF.new( 
    [ pL2_00.poles(), pL2_01.poles() ] )
pS22_1 = PF.new( pS22_0.poles() )
pS22_1.rotate( [0,0,15] )      # optionnel
pS22_1.scale( [0.5,0.5,0.5] )  # optionnel
pS22_1.translate( [0,0,m] )    #
pV222 = PF.new( 
    [ pS22_0.poles(), pS22_1.poles() ] )
pV222.build( finesse )
pV222.draw( "V" )
end

Dans cet exemple, le cube gauche est construit sur deux quadrangles :

  • le premier quadrangle pS22_0 est construit sur deux segments : pL2_00 et pL2_01,
  • le second pS22_1 est créé à partir du premier, optionnellement pivoté et scalé et enfin translaté de 90 sur l'axe Oz,
  • la méthode new() crée une pForme cuboïde appelée pV222 à partir de deux pS22,
  • la méthode build() lance un processus récursif de construction d'un tableau cubique de points distribués dans le cuboïde,
  • pour finesse = [0,0,0], le tableau est limité aux huit points extrémités [0,1]*[0,1]*[0,1]
  • pour finesse = [1,1,1], le tableau contient les points [0,1/2,1]*[0,1/2,1]*[0,1/2,1]
  • etc ...
  • la méthode draw() affiche le cube gauche. Le paramètre "V" précise qu'il sera affiché comme un ensemble de six facettes. Avec la valeur "S" il sera affiché comme un mille-feuilles de facettes. Avec la valeur "L" il sera affiché comme une famille de segments et avec la valeur "P" comme un semis volumique de points.

15) hypercube gauche


figure 1.5 : un hypercube gauche

Soient deux cubes gauches pV222_0 et pV222_1. L'application récursive d'un processus analogue aux précédents produit un ensemble infini et dense de cubes gauches formant une portion d'hypervolume, un "hypercube gauche" que nous désignerons par pH2222 et que nous écrirons :

pH2222 = [ pV222_0, pV222_1 ]

Dans la syntaxe SRpF, un hypercube gauche sera créé et affiché ainsi :

def hypercube( finesse = [3,3,3,3] )
   pV222_0 = ... 
   pV222_1 = ... 
   pH2222 = PF.new( [ pV222_0, pV222_1 ] )
   pH2222.build( finesse )
   pH2222.draw( "P" )
end

Dans cet exemple, l'hypercube gauche est construit sur deux cubes gauches définis auparavant :

  • la méthode new() crée une pForme hypercube appelé pH2222 à partir de deux pV222,
  • la méthode build() lance un processus récursif de construction d'un tableau hypercubique de points distribués dans l'hypercube gauche,
  • pour finesse = [0,0,0,0], le tableau est limité aux seize points extrémités,
  • pour finesse = [1,1,1], le tableau contient les points [0,1/2,1]*[0,1/2,1]*[0,1/2,1]*[0,1/2,1]
  • etc ...
  • la méthode draw() affiche l'hypercube gauche. Pour l'instant seule la valeur "P" peut être choisie pour représenter l'hypercube sous forme d'un semis "hypervolumique" de points.

Nous découvrirons l'utilité d'une telle construction un peu plus loin, lorsque nous nous intéresserons au contenu des pFormes, et notamment à leurs pFormes diagonales et immergées.

16) première conclusion

Deux opérations, la construction d'une forme milieu et l'application récursive de cette construction permettent donc de produire une famille de formes multilinéaires. Nous noterons que la construction d'une forme milieu produit une forme de même dimension et que l'application récursive de cette construction produit une forme de dimension supérieure. Ces formes sont gauches dans le cas général (à l'exception du segment bien sûr), le quadrangle est une portion du classique paraboloïde hyperbolique, une surface réglée à double courbure négative, et les six faces du cube gauche sont des facettes gauches.

Ces formes sont 'pleines', chaque point d'une forme peut être adressé : un cube gauche est un volume rempli de points et non une simple enveloppe vide, et il en est de même pour l'hypercube. On a bien ainsi défini des formes cohérentes dans lesquelles il va être possible de travailler et dont on pourra par exemple extraire des 'sous–formes'. Une opération inverse, la diagonalisation, produisant une forme de dimension inférieure mais plus complexe qu'un segment linéaire nous conduira à de nouvelles extensions de ces opérations fondamentales.

2) diagonales

Au sommaire de cette section :

  • 21) facette gauche et quadrique
  • 22) biquadrique et cubique
  • 23) triquadrique et quintique
  • 24) tetracubique

Toutes les formes précédentes sont linéaires plusieurs fois, elles sont engendrées par des familles de droites, mais elles n'en contiennent pas moins de « vraies » courbes présentant un certain intérêt. La facette gauche, par exemple, est une surface en forme de selle de cheval présentant une certaine courbure dès que les deux segments générateurs ne sont plus coplanaires. En repliant une facette gauche sur elle–même jusqu'à confondre deux sommets opposés, on construit une sorte de triangle dont un côté est un arc de parabole. Ce 'pliage' de la facette gauche nous permet de construire une courbe, une forme de dimension inférieure à celle de la facette gauche, mais de complexité supérieure au segment de droite.

21) facette gauche et quadrique


figure 2.1 : un quadrangle et sa quadrique

Soit une facette gauche construite sur deux segments (pL2_0,pL2_1) définis sur deux couples de points (p00,p01) et (p10,p11) :

pS22 = [ pL2_0, pL2_1 ]
     = [ [ p00, p01 ], [ p10, p11 ] ],

Le point milieu de la facette peut se définir par :

pm = ( (p00 + p01)/2 + (p10 +p11)/2 )/2
   = ( p00 + p01 + p10 + p11 )/4

Ce point détermine quatre sous–facettes (p00,pm), (p01,pm), (p10,pm) et (p11,pm). En recommençant ainsi récursivement l'opération sur les deux sous–facettes en diagonale construites sur les couples (p00,pm) et (pm,p11), on engendre un ensemble infini et dense de points, une courbe reliant en diagonale les points p00 et p11 de la facette gauche. A ce stade rien ne nous permet de connaître les caractéristiques de cette courbe.

Cette forme est de dimension inférieure à celle de la facette et de degré supérieur à ses génératrices. On est amené à réécrire le point milieu en fonction de trois points :

pm = ( p0 + 2*p1 + p2 )/4
avec :
   p0 =   p00,
   p1 = ( p01+p10 )/2,
   p2 =       p11

Cette expression peut être retrouvée par un processus récursif en deux temps conduisant au point pm à partir du triplet (p0,p1,p2), à l'aide de deux points milieux intermédiaires q0 et q1:

1)  q0 = (p0 + p1)/2,
    q1 = (p1 + p2)/2,
2)  pm = (q0 + q1)/2

L'application récursive de ce processus pour une valeur infinie de la récursion produit un ensemble infini et "dense" de points situés "entre" les trois points p0, p1 et p2, un "segment de parabole" que nous désignerons par pL3 et que nous écrirons :

pL3 = [ p0,p1,p2 ]
point de vue algébrique

En se souvenant de l'expression algébrique d'une facette gauche :

p(u,v) = (1-u)•(1-v)•p00 + u•(1-v)•p01 
       +     (1-u)•v•p10 +     u•v•p11,
avec u,v dans l'intervalle [0,1] € R

on exprime la courbe diagonale en égalant les valeurs u et v et conduisant à :

p(u) = (1-u)2•p0 + 2•(1-u)•u•p1 + u2•p2
avec :
   p0 =   p00,
   p1 = ( p01+p10 )/2,
   p2 =       p11
et pour u = 1/2
p(1/2) = ( p0 + 2*p1 + p2 )/4

On retrouve bien l'expression du point milieu trouvée de façon géométrique. Une autre approche est également possible en écrivant :

p(t)  = (1-t)•q0(t) + t•q1(t),
q0(t) = (1-t)•p0 + t•p1,
q1(t) = (1-t)•p1 + t•p2,
soit :
p(t) = (1-t)2•p0 + 2•(1-t)•t•p1 + t2•p2
avec t dans l'intervalle [0,1] € R

Nous retrouvons dans cette construction l'algorithme proposé par Paul de Faget de Casteljau pour le cas d'une parabole définie par trois points, un algorithme qui se trouve ainsi logiquement relié au processus de génération de la famille des formes multilinéaires récursives, par une sorte de contraction/pliage/diagonalisation d'une facette gauche. Quelle que soit l'approche on est en présence d'une courbe dite "de Bézier", du nom de son "inventeur" Pierre Bézier. Nous aurons l'occasion d'y revenir et d'éclairer les apports des uns et des autres dans ce domaine des formes courbes.

Dans la syntaxe SRpF, nous écrirons ainsi les deux approches :

1) à partir d'une facette gauche :
def diag( )
   pS22 = PF.new( tableau carré de points )
   pS22.build( [3,3] ) # optionnel
   pS22.draw( "S" )    # optionnel
   diag = pS22.diag()
   diag.build( 0 )     # affichage du
   diag.draw( "L" )    # polygone contrôle
   diag.build( 3 )
   diag.draw( "P" )    # 
end
2) à partir de trois points :
def pL3( )
   pL3 = PF.new( [ p0, p1, p2 ] )
   pL3.build( 0 )     # affichage du
   pL3.draw( "L" )    # polygone contrôle
   pL3.build( 3 )
   pL3.draw( "P" )
end

Noter que dans les deux cas, la courbe parabole est représentée sous la forme d'une série de points et accompagnée de son polygone de contrôle. On notera qu'elle passe par les points d'extrémité mais pas par le point intermédiaire.

Cette diagonalisation de la facette gauche nous a permis de construire une forme de dimension inférieure à celle de la facette gauche, mais de complexité supérieure au segment de droite. De façon plus générale le processus de diagonalisation va nous permettre de quitter le monde purement rectiligne des formes multilinéaires récursives et d'aborder celui de formes gauches plus complexes.


... à suivre !


.

une coque de bateau représentée par un pVolume
code
def ship()
   coque = [
[[3.0/2,0,-1.0/32],[3.0/2,-1.0/4,-1.0/32],[3.0/2,-1.0/2,0],[3.0/2,-1.0/4,1.0/32],[3.0/2,0,1.0/32]],
[[2.0/2,0,-1.0/32],[2.0/2,-1.0/4,-1.0/32],[2.0/2,-1.0,0],[2.0/2,-1.0/4,1.0/32],[2.0/2,0,1.0/32]],
[[1.0/2,0,-1.0/16],[1.0/2,-1.0/2,-1.0/16],[1.0/2,-1.0,0],[1.0/2,-1.0/2,1.0/16],[1.0/2,0,1.0/16]],
[[0.0/2,0,-1.0/2],[0.0/2,-1.0/2,-2.0/2],[0.0/2,-1.0,0],[0.0/2,-1.0/2,2.0/2],[0.0/2,0,1.0/2]],
[[-1.0/2,0,-1.0/2],[-1.0/2,-1.0/2,-1.0/2],[-1.0/2,-1.0/4,0],[-1.0/2,-1.0/2,1.0/2],[-1.0/2,0,1.0/2]],
[[-2.0/2,0,-1.0/4],[-2.0/2,-1.0/8,-1.0/4],[-3.0/2,-1.0/8,0],[-2.0/2,-1.0/8,1.0/4],[-2.0/2,0,1.0/4]]
]
   pCoque_ext = PF.new( coque )				# coque extérieure
   pCoque_ext.rotate( [90,0,0] )			# pivoté sur Ox
   pCoque_ext.draw( "L" )				# affichage des polygones de contrôle
   pCoque_in = pCoque_ext.parallel( -0.05 )	        # coque intérieure
   ship = PF.new( [pCoque_ext.poles(), pCoque_in.poles()] )    # volume de la coque
   ship.build( [0,3,3] )				# construction des points du volume
   ship.draw( "V" )				        # affichage en volume (les 6 faces)
   ship.draw( "L" )				        # affichage en couples
end
 
pFwiki