AA2022


Benjamin Dupont et Jean-Jacques BOURDIN

E-mail :
Benjamin.Dupont NOSPAM @ univ-paris8.fr
(enlever le NO Spam)


jj NOSPAM @ up8.edu
(enlever le NO Spam)


Algorithmique Avancée 2022


Présentation et Complexité



  1. Présentation
  2. Constantes et complexité
    1. Calculs et mesures de complexité
    2. Constantes
    3. Exemple
  3. De la Droite Discrète
    1. Algorithme trivial
    2. DDA et accélération
    3. Mots de trace
    4. Algorithme rapide
  4. Graphes
    1. Codages
    2. Algorithmes
  5. Compression
    1. Rappels, champs de bits
    2. Bases
    3. Compression sans perte
    4. Compression avec perte
    5. Compression d'images
  6. Modélisation, Illumination, Rendus
    1. 2D/3D
    2. Modélisation
    3. Illumination
    4. Lumière
    5. Rendus, quelques effets
    6. Rendus Expressifs
    7. IA et jeux
      1. Algorithmes
  7. Projets


  • De la Droite Discrète

    1. Définition
      De droite il n'est pas question, de chemin discret approximant un segment de droite entre deux points, oui.
    2. De l'évidence à la référence

      void droite (int x0, int y0, int x1, int y1) {
        int x, y;
        float yf;
        
        for (x = x0; x <= x1; x++) {
           yf = (float) (x - x0) * (y1 - y0);
           yf /= (x1 - x0);
           yf += y0;
           y = (int) (yf + 0.5); /* approximation à l’entier le plus proche*/
           affiche(x,y);
        }
      }
      					

      C‘est à la fois simple et peut efficace. Jack Bresenham a présenté un travail fort différent en 1962 (publié en 1965).

      L‘idée principale est de trouver une mesure de l‘écart entre un point et le point qui devrait être juste. En x la valeur réelle de y doit être
      yr = (x * dy) / dx
      Si vous avez le choix entre y et y+1, valeurs entières, il faut comparer :

      Si | y - yr | > [ y + 1 - yr | alors il faut prendre y + 1 comme nouvelle valeur.

      Il ne reste plus alors qu'à étuder cette inégalité, la simplifier et comprendre qu‘elle est équivalente à

      delta (x,y) = 2 * x * dy - 2 * y * dx - dx

      Si delta > 0 y++

      de là l'algorithme suivant :

      void droite_br (int u, int v) {
      /* u est dx, v est dy */
         int x, y, delta, incD, incH;
      
         incH   = v << 1;
         delta  = incH - u;
         incD   = delta - u;
         for (x = 0, y = 0; x <= u; x++) {
            affiche(x, y);
            if (delta > 0) {
               y++;
               delta += incD;
            }
            else {
               delta += incH;
            }
         }
      }
      

    3. Améliorer la référence
      1. Pas de deux, Rokne, Wyvill et Wu (CG&A 1993)
        Vous trouverez cet article dans le catalogue de la bibliothèque. Il faut se connecter à votre compte sur le portail de l'Université, puis, dans l'onglet BU en ligne, tout en bas, consulter les bases de données. La seconde est "l’ACM digital library", vous y allez et, là, en haut à gauche vous trouvez un champ recherche, tapez le titre "Fast line scan-conversion" et c’est la permière entrée.

        Pour réussir ce programme, il "suffit" de remarquer que la fonction delta reste la même

        delta (x,y) = 2 * x * dy - 2 * y * dx - dx
              

        Il suffit donc de compter que, quand on regarde en x+2, on calcule delta(x+2,y) qui se déduit assez facilement de delta, non ?

        Si on est dans la partie haute de l‘octant, il faut regarder delta(x+2, y+1)

        Avez-vous encore besoin d‘aide pour écrire cette fonction ?

      2. Pas de trois, Graham et Iyengar (CG&A 1994)
        "Double- and triple-step incremental generation of lines"
        Vous le trouverez de la même manière.
      3. Pas de trois ou quatre, Gill (CG&A 1994) via le pas de 4, ou 5 ou N
      4. Pas auto-adaptatif, B. et B. (CG&A 2000)
        Article complet.

      Vous trouverez ici le TP sur les droites.

    4. PGCD, Angel et Morrison (CG&A 1991)
      /* u est dx, v est dy */
      • Calculer g le pgcd de u et v.
      • Calculer ug= u/g et vg= v/g
      • Calculer la droite de pente (ug, vg).
      • Pour l’affichage, réitérer g fois le chemin trouvé.

        Ils annoncent être trois fois plus rapides que Bresenham. Comme le pgcd moyen est 4, ce serait un résultat un peu faible. Le problème est que le pgcd moyen est bien environ 4 mais plus de 60% des couples d'entiers ont un pgcd égal à 1. Pour 60% des couples, il n'y a aucune accélération. Donc le temps passé à faire des calculs ne peut pas être inférieur à 60% du temps initial !

        Il faut rajouter à cela le calcul du pgcd et les 40% de couples de nombres pour lesquels l'accélération est forte (10). On doit être à plus de 64% du temps initial. L'accélération est forte, sans doute une vitesse de 1.5, ce qui est très faible par rapport à ce qui est annoncé.

        White.local: a.out 1001
        le nombre de gcd valant 1 est 608383
        le nombre de gcd different de 1 est 393618 soit 39.283194 % 
        la moyenne de tous les gcd est 3.833826
        la moyenne des gcd non un est 9.759455
        

    5. Chercher ailleurs et autrement
      1. "Sous les pavés"
        Quelques propriétés significatives présentées par Wu :

        	   - There are at most two basic directions and these ones can differ only by unity, modulo eight.
        	   - One of these values always occurs “singly”.
        	   - Successive occurrences of the principal direction occurring singly are as uniformly spaced as possible.
        

        Notons 0 et 1 ces deux directions, la droite suit donc un chemin décrit par un mot de l‘alphabet {0,1}. Notons ce mot w(dx,dy).
      2. Euclide et applications
        1. Dulucq et Bourdin Principe général :
          • la fonction phi de m transforme un 1 en une plage de m 0 suivis d'un 1.
          • la fonction phi de m transforme un 0 en une plage de (m+1) 0 suivis d'un 1.
          • la fonction psi de m transforme un 0 en un 0 suivi d'une plage de m 1.
          • la fonction psi de m transforme un 1 en un 0 suivi d'une plage de (m+1) 1.
          • la fonction db traite des cas particuliers, pour éviter les nombreuses fois où on voudrait relancer une récursivité inutile.
          Algorithme dans le premier octant :
          • si u > 2 * v
            w(u,v)=phi(m,w(p,q))
            avec
            m = (u-v)/v
            p = v
            q = v - u % v
            phi (m,"0") = "000...01" (m+1) fois 0 et un 1
            phi (m,"1") = "00...01" (m) fois 0 et un 1
          • si u < 2 * v
            w(u,v)=psi(m,w(p,q))
            avec
            m = v/(u-v)
            p = u-v
            q = v % (u - v)
            psi (m,"0") = "011...1" 0 et (m) fois 1
            psi (m,"1") = "0111...1" 0 et (m+1) fois 1
          • Green and Pitteway
                   droite (dx, dy) {
                      dx -= dy;
                      s = "0";
                      t = "1";
                      while (dx != dy) {
                         if (dx > dy) {
                            dx -= dy;
                            t = s . t;
                         }
                         else {
                            dy -= dx;
                            s = s . t;
                         }
                      }
                      return ( s . t ) ^dx;
                   }
                    

            La version suivante calcule la droite "meilleure approximation".

                   droitebest (dx, dy) {
                      dx -= dy;
                      s = "0";
                      t = "1";
                      while (dx != dy) {
                         if (dx > dy) {
                            dx -= dy;
                            t = s . t ^(-1);
                         }
                         else {
                            dy -= dx;
                            s = t . s ^(-1);
                         }
                      }
                      return ( s . t ^ (-1) ) ^dx;
                    }
                  
          • Berstel
          • Une fois connue la décomposition de la fraction dy/dx en série de fractions continues

            dy/dx = [u0; u1, u2, u3, ..., un]

            l’algorithme suivant peut être utilisé.

            	  w(0) = 0
            	  w(1) = 0^(u1-1) . 1
            	  w(i) = w(i-1)^ui . w(i-2)  (i impair)
            	  w(i) = w(i-2) . w(i-1)^ui  (i pair)
            	
            . est l’opérateur de concaténation tandis que "w^n" est la duplication n fois du mot w. Exemple d’utilisation : soit la droite de pente 3/11. La décomposition est [0; 3, 1, 2]. On a :
            	  w(0) = 0
            	  w(1) = 0 0 1
            	  w(2) = 0 0 0 1
            	  w(3) = 0 0 0 1 0 0 0 1 0 0 1
            	
            Reste à savoir comment on obtient la décomposition d’une fraction en série de fractions continues.
            D'abord remarquons que, dans ce qui nous intéresse, la fraction v/u est plus petite que 1. Donc la fraction v/u vaut 0+1/(u/v)
            Mais u/v c'est u divisé par v plus u modulo v divisé par v.
            vi/ui = 1/(mi + vj/uj), avec
            j = i + 1
            mi = (int) (ui / vi)
            vj = ui % vi
            uj = vi
            On continue ainsi jusqu’à ce que vj soit inférieur à 2.
            la suite [m0; m1, m2, m3,...,mn] est une représentation de la fraction v/u.
      3. Plages (Spans)
      4. Récapitulation et algorithme rapide
        De tout cela découle un algorithme particulièrement rapide (près de 20 fois plus rapide que celui de Bresenham en 1965), qui est présenté dans cet article à Eurographics, en 1999.

    Dernière mise à jour : 3/10/2022 (19h)