Environnement de développement d’un plugin WordPress

May 17th, 2013

J’avais envie de me lancer dans le développement d’un petit plugin pour WordPress sur mon Mac.

Je n’ai aucune expérience en développement web et n’avais aucune idée de quels outils j’avais besoin, ni de la façon de travailler.

Par contre, je tenais absolument à utiliser un gestionnaire de versions, en l’occurrence Subversion, qui est celui que je connais le mieux.

Voici un descriptif de ce que j’ai mis en place et utilisé.

Installation de MAMP

Il a été rapidement clair que pour pouvoir développer confortablement un plugin pour WordPress, il faut une installation locale d’une version (voire plusieurs) de WordPress.

Pour ce faire, il suffit d’installer MAMP, qui intègre toutes les applications nécessaires au bon fonctionnement de WordPress : Apache, MySql, PHP, etc. Il existe une déclinaison pour Windows (WAMP) et pour Linux (LAMP).

MAMP peut être téléchargé à l’adresse suivante : http://www.mamp.info/en/mamp/index.html

Il suffit ensuite de démarrer le paquet d’installation. Celle-ci se déroule sans encombre.

Aller dans /Applications/MAMP/ et démarrer MAMP. Comme MAMP PRO est installé, il fait la demande suivante :

Décocher et cliquer Lancer MAMP. Eventuellement, désinstaller MAMP PRO en cochant toutes les cases du désinstalleur.

Après le démarrage, MAMP affiche l’état des serveurs, qui sont inactifs.

Cliquer sur Démarrer les serveurs. Normalement, ils s’activent et passent au vert.

L’activation des serveurs provoque l’affichage dans votre navigateur par défaut de l’URL http://localhost:8888/MAMP/?language=French.

À partir de cette page, il est possible d’administrer les différents outils qui composent notre serveur web local.

Création d’une base de données pour WordPress

Pour fonctionner, WordPress a besoin d’une base de données MySQL, qui sera ensuite configurée et remplie par ses soins.

Utiliser l’utilitaire phpMyAdmin, accessible par le navigateur web, sur l’onglet phpMyAdmin.

Il faut activer l’onglet Bases de données, puis donner un nom à la nouvelle base de données qui sera utilisée par WordPress (par exemple wptest). Cliquer ensuite sur le bouton Créer.

Il n’y a rien d’autre à faire !

Installation locale de WordPress

Télécharger WordPress sur le site http://fr.wordpress.org.

Suivre les instructions indiquées :

  1. Créer un répertoire wordpress dans /Applications/MAMP/htdocs/ et y copier les fichiers téléchargés.
  2. Renommer wp-config-sample.php en wp-config.php
  3. Éditer le fichier wp-config.php afin d’y configurer le nom de la base de données WordPress ainsi que l’identifiant à utiliser :
    define('DB_NAME', 'wptest');
    define('DB_USER', 'root');
    define('DB_PASSWORD', 'root');
  4. Remplacer “put your unique phrase here” par votre propre phrase.
  5. Comme notre installation locale de WordPress est destinée au développement, activer le mode debug : define('WP_DEBUG', true);
  6. Aller à la page localhost:8888/wordpress/. La configuration automatique commence.
  7. Si tout se passe bien, WordPress est désormais complètement utilisable.

Installer l’IDE

On m’a conseillé, pour développer en PHP, d’utiliser Aptana Studio. Cet IDE, basé sur Eclipse, permet d’installer ensuite un bundle spécifique à WordPress.

Installation de Git

Pour installer ce bundle, il faut disposer d’un client Git. Les binaires pour Mac sont téléchargeables à l’adresse http://git-scm.com/download/mac.

Ensuite, installer le paquet git-1.8.2.1-intel-universal-snow-leopard.pkg. Le script setup git PATH for non-terminals programs.sh n’a pas besoin d’être exécuté.

Il faut également s’assurer que le port TCP 9418 soit ouvert.

Installation de Aptana Studio

Télécharger Aptana Studio à l’adresse http://www.aptana.com/products/studio3/download. Si vous possédez déjà Eclipse, vous pouvez installer Aptana sous forme d’un plugin. Pour ma part, j’ai préféré télécharger la version autonome d’Aptana Studio.

L’installation ne pose aucun problème.

Installation du bundle WordPress

Pour installer le bundle WordPress (ou d’autres) d’Aptana Studio, aller dans le menu Commands->Bundle Developement->Install Bundle. Choisir WordPress dans la liste.

Installation d’un client Subversion

J’ai choisi d’utiliser SmartSVN comme client Subversion pour Mac. La version gratuite me permet de faire tout ce dont j’ai besoin.

Créer un projet de développement

Emplacement du bac à sable

J’ai choisi de créer un dépôt Subversion par plugin.

Je ne voulais pas placer mon bac à sable (ou autrement dit, l’emplacement de ma copie locale du dépôt Subversion de mon projet) directement dans le répertoire plugins de mon installation locale de WordPress, bien que plusieurs personnes font ça. Il y a principalement deux raisons à ce choix :

  • Le projet de développement contient des fichiers qui n’ont pas a figurer dans le répertoire des plugins WordPress. Je pense par exemple aux fichiers de configuration du projet qu’Aptana génère, aux fichiers traitant de la documentation interne ainsi qu’aux éventuels fichiers de ressource.
  • Si j’ai plusieurs installations locales de WordPress, par exemple avec différentes versions de WordPress pour les tests, je veux éviter de faire un checkout du dépôt dans chaque répertoire plugins de chaque installation locale, car ça deviendrait vite ingérable.

La solution que j’ai trouvée pour tenir compte de ces contraintes est de créer des symlink (les alias sont plus faciles à gérer depuis le Finder, mais ils ne sont malheureusement pas transparents aux yeux de WordPress). J’ai donc, dans le répertoire plugins de mon installation locale de WordPress, créé avec le Terminal un lien sur le répertoire de développement de mon plugin :

ln -s ~/Documents/Aptana\ Studio\ 3\ Workspace/MonPlugin /Applications/MAMP/htdocs/wordpress/wp-content/plugins/monplugin

Ainsi, notre installation locale de WordPress (ou nos installations s’il y en a plusieurs) utilise(nt) toujours la toute dernière version du plugin, ce qui rend les tests très aisés.

Remarque : pour que l’utilisation des symlinks fonctionne correctement, apache doit être configuré (dans le fichier httpd.conf) pour les accepter (option FollowSymLinks), ce qui est le cas par défaut, lorsqu’il est installé avec MAMP, pour le répertoire /Applications/MAMP/htdocs/.

Auto-completion avec l’API WordPress

Il reste un problème, découlant de cette solution, à régler : Comme notre projet est isolé des fichiers de WordPress, Aptana ne va pas être en mesure de faire de la completion automatique avec les fonctions de l’API WordPress.

Pour corriger ce problème, il suffit d’ajouter le chemin de  notre installation locale de WordPress au chemins de construction de PHP (PHP Buildpath).

Dans Aptana Studio, ouvrir le menu Project->Properties. Choisir dans la zone latérale gauche la propriété PHP Buildpath, sélectionner l’onglet External Directories, puis cliquer sur Add .... Il ne reste plus qu’à sélectionner le répertoire local de l’installation WordPress (par exemple /Applications/MAMP/htdocs/wordpress) et le tour est joué.

Le bug des symlink

Tant que le plugin WordPress que vous développez n’est constitué que d’un fichier, tout va bien.

Par contre, si votre plugin doit faire appel à d’autres fichiers, par exemple pour ajouter une feuille de style spécifique, l’utilisation de symlinks pose problème car WordPress ne les gère pas correctement.

Beaucoup de développeurs sont très ennuyés par cette situation et espèrent que la version 3.6 de WordPress intègre un correctif. Le ticket #16953 permet de suivre l’avancement de ce problème.

Dans l’intervalle, un petit patch très pratique créé par Kaspars Dambis doit être ajouté dans le code du plugin. C’est un moindre mal comparé à l’énorme avantage que l’on a d’utiliser les symlinks.

// ---- Patch pour autoriser le symlinking avec ce plugin.
// Patch créé par Kaspars Dambis (http://konstruktors.com/blog/wordpress/3635-plugins-via-symlinks/)
// Le bug #16953 traite de cette problématique : http://core.trac.wordpress.org/ticket/16953
// Avec un peu de chance, une solution sera à disposition dans le version 3.6 de WordPress.
add_filter( 'plugins_url', 'your_plugin_symlink_fix', 10, 3 );

function your_plugin_symlink_fix( $url, $path, $plugin ) {
   if ( strstr( $plugin, basename(__FILE__) ) )
      return str_replace( dirname(__FILE__), '/' . basename( dirname( $plugin ) ), $url );
   return $url;
}

Dans le cas cité plus haut où une feuille de style doit être chargée, il suffira de placer le fichier css dans le répertoire du plugin…

…et de la charger selon la méthode traditionnelle :

// Chargement de la feuille de style spécifique à ce plugin
if ( ! function_exists( 'monplugin_add_stylesheet' ) ) {

	add_action( 'wp_enqueue_scripts', 'monplugin_add_stylesheet' );

	function monplugin_add_stylesheet() {
	    wp_register_style( 'monplugin-style',  plugins_url('monplugin-style.css', __FILE__));
	    wp_enqueue_style( 'monplugin-style' );
	}
}

Déploiement

Une fois le plugin testé avec l’installation locale de WordPress, il ne reste plus qu’à le déployer sur une installation distante. Pour ce faire, Aptana Studio permet de configurer une connexion pour transférer facilement les fichiers locaux sur le serveur distant.

Il faut donc disposer d’une connexion FTP permettant d’accéder à l’installation distante de WordPress, puis il faut configurer cette connexion au niveau du projet Aptana.

Depuis le menu contextuel de l’élément Connections, choisir Add New Connection... (ou double-cliquer sur l’élément).

Une fenêtre de configuration s’ouvre.

Donner un nom à la nouvelle connexion et créer une nouvelle destination distante en cliquant sur le bouton New....

Valider les paramètres FTP de connexion en cliquant sur OK.

Dès lors, chaque fois qu’un des fichiers du plugin doit être mise à jour sur le serveur distant, il suffit de le sélectionner et de cliquer sur l’icône Upload.

Pixelmator : ombre portée

May 4th, 2013

Étonnamment, Pixelmator ne propose pas par défaut un effet d’ombre portée.

On trouve facilement plusieurs tutoriels sur le web expliquant comment faire, manuellement, une ombre portée. Ces techniques nécessitent l’emploi des calques et prend un peu de temps.

Je suis tombé sur une technique qui me semble bien plus propre : créer un filtre Quartz réalisant une ombre portée, et utiliser ce filtre à partir de Pixelmator.

Le filtre en question existe et peut être téléchargé à cette adresse : http://belightcommunity.free.fr/download_file.php?uid=49 (ou ici si le lien ne fonctionne plus)

Décompresser l’archive zip (si OS X ne le fait pas automatiquement).

Placer le fichier obtenu (BC_Shadow_1.5.qtz) dans le répertoire /Bibliothèque/Compositions/ (ou en anglais /Library/Compositions/).

Redémarrer Pixlmator. Le filtre se trouve désormais dans les effets, catégorie Autres, et se nomme Shadow.

iPhoto ’09 avec Mountain Lion

February 24th, 2013

Je viens de recevoir mon nouvel iMac 27″, version fin-2012, avec Mountain Lion et iLife ’11 préinstallés.

Jusqu’ici, j’utilisais un iMac 24″, version fin 2007, avec Snow Leopard et iLife ’09.

Certainement ma plus grosse déception a été de découvrir la nouvelle mouture d’iPhoto ’11 (9.4.2).

Pour moi, iPhoto ’09 (8.1.2) convenait très bien pour ce que j’en faisais : J’y stockais toutes mes photos de famille et j’appréciais de pouvoir le trier en plein écran. Je pouvais ensuite facilement les glisser-déposer dans une autre application pour éventuellement procéder à quelques retouches.

Il m’arrivait également fréquemment d’y ajouter des dessins de mes enfants, numérisés. Je modifiais alors la date de numérisation pour y mettre la date à laquelle le dessin avait été réalisé.

Avec iPhoto ’11, je suis allé de déceptions en déceptions : tout d’abord, la pire, c’est la disparition du mode plein écran. D’autre part, et c’est très agaçant, lorsque je fais un glisser-déposer d’une photo, l’ascenseur d’iPhoto bouge, ce qui fait que lorsque ma photo a été déposée dans une autre application et que je retourne à l’application iPhoto, elle ne se trouve plus au même endroit.

Enfin, le changement de date d’une photo est devenu très laborieux puisqu’il n’est plus possible de directement la modifier depuis la fenêtre des informations, mais qu’il faut passer par le menu Photos->Ajuster la date et l'heure, qui n’est pas disponible lorsqu’une photo est sélectionnée et affichée en grand.

J’ai donc voulu revenir à iPhoto ’09. Avec mon iMac de l’époque, j’avais obtenu le DVD d’installation d’iLife ^09 et possédait donc l’installeur. Malheureusement, j’ai du faire face à plusieurs problèmes.

Utiliser l’installeur

Malheureusement, si je tente de démarrer le paquet iLife '09.pkg, celui-ci refuse d’y installer iPhoto : Même en faisant une installation personnalisée, iPhoto (et iMovie) restent grisés et ne peuvent pas être sélectionnés.

J’ai donc continuer mes investigations.

Installer directement le paquet iPhoto

Avec le menu contextuel, choisir Afficher le contenu du paquet iLife ’09, puis aller dans Contents/Installers. Afficher le contenu du paquet iPhoto.mpkg, puis aller dans Contents/Installers.

Double-cliquer sur iPhoto.pkg. Malheureusment, Mountain Lion refuse de l’installer.

Il faut donc persévérer !

Décompresser manuellement le paquet iPhoto

Afficher le contenu du paquet iPhoto, puis aller dans le dossier Contents. Double-cliquer sur Archive.pax.gz. Le système le décompresse et crée un dossier Archive contenant un répertoire Applications, lui-même contenant l’application iPhoto.

Déplacer cette application dans le dossier Applications de l’ordinateur.

Démarrer iPhoto : un message d’erreur indique que cette application ne peut pas être démarrée sur ce système.

En détaillant le rapport généré en vue signaler le problème à Apple, j’ai constaté qu’iPhoto ’09 cherche à accéder au framework iLifeSlideShow.

Dyld Error Message:
Library not loaded: /System/Library/PrivateFrameworks/iLifeSlideshow.framework/Versions/A/iLifeSlideshow
Referenced from: /Applications/iPhoto.app/Contents/MacOS/iPhoto
Reason: image not found

Il faut donc installer manuellement ce framework :

Afficher le contenu du paquet iLife ’09, puis Contents/Installers/ et double-cliquer sur iLifeSlideShow.pkg.

L’installation se déroule sans problème. Le système doit être redémarré…et ensuite, il est possible de démarrer iPhoto ’09 ! Ouf !

Merci Apple pour m’avoir fait perdre trois soirées pour ça ! Grrr !

Police de caractères d’une page web

June 6th, 2012

Pour connaître la police de caractères utilisée sur une page web, il existe un petit outil qui fait des merveilles : WhatFont.

C’est une extension pour Safari ou Chrome. Lorsque cette extension est enclenchée, en passant la souris sur le texte d’une page web, une bulle d’info apparaît et indique le nom de la police utilisée. Si l’on clique sur cette bulle, plus de détails sont affichés (famille, taille, couleur, etc.)

Cet outil est également disponible sous forme de bookmarklet.

Si l’on souhaite connaître la police de caractères d’une image, on peut utiliser le site WhatTheFont, qui propose également une application mobile.

Formules mathématiques dans WordPress : MathJax

March 3rd, 2012

Quelques uns de mes articles nécessitent de représenter des formules mathématiques.

Jusqu’ici, j’avais utilisé la seule solution que je connaissais : le site LaTex Equation Editor for Writing Maths on the Internet !

Le principe est simple : la formule mathématique à afficher est une image, générée à la volée par ce site, en fonction d’une formule décrite selon la syntaxe de LaTex. L’avantage de cette méthode est qu’elle fonctionne dans tous navigateurs.

Le désavantage est que la qualité de l’image est discutable et nécessite un accès au site mentionné plus haut pour que l’affichage de l’article soit correct.

MathJax

C’est tout à fait par hasard que je suis tombé sur MathJax et plus particulièrement le plug-in MathJax-Latex. Il permet d’afficher une formule mathématique, décrite dans la syntaxe de LaTex, sous forme textuelle :

L’avantage de la forme textuelle est qu’elle supporte bien le zoom et permet d’être copier-coller. MathJax propose même un menu contextuel permettant un copier-coller plus performant.

La syntaxe est simple, il suffit de placer la formule entre les balises [latex] et [/latex]. Ainsi :

[latex]\sum_{k=1}^{n}k^{2}=\frac{n(n+1)(2n+1)}{6}[/latex]

affichera le résultat suivant :

Si le résultat est trop petit, ajouter \large en début de formule :

[latex]\large\sum_{k=1}^{n}k^{2}=\frac{n(n+1)(2n+1)}{6}[/latex]

Le résultat sera le suivant :

Il est également possible de placer la formule entre les délimiteurs $$. Par exemple :

$ $\sum_{k=1}^{n}k^{2}=\frac{n(n+1)(2n+1)}{6}$ $

Ce qui donne :

$$\sum_{k=1}^{n}k^{2}=\frac{n(n+1)(2n+1)}{6}$$

Attention : si vous avez installé le plug-in Jetpack, il faut désactiver l’extension latex.  Sinon, les formules placées entre les balises [latex] seront affichées sous forme d’images.

Mandelbrot

February 18th, 2012

L’ensemble de Mandelbrot est une fractale bien connue pour son aspect si particulier en forme de cardioïde :

Cet ensemble est défini selon une formule relativement simple que nous verrons plus loin. Mais comme cette formule fait intervenir les nombres complexes, un petit rappel ne fera pas de mal.

Les nombres complexes

Si l’on se limite à l’ensemble des nombres réels (R), il est impossible de calculer la racine carrée d’un nombre négatif, comme par exemple .

L’ensemble des nombres complexes () permet de résoudre ce genre de problème. L’idée est de nommer le résultat de par la lettre i. Cette lettre représente la partie imaginaire du nombre. Ainsi :

$$\sqrt{-16}=\sqrt(-1\cdot 16)=\sqrt(-1)\cdot\sqrt(16)=i4$$

On dit que i4 est la partie imaginaire d’un nombre. Rien n’empêche qu’un nombre complexe possède également une partie réelle. On note donc un nombre complexe sous la forme (a + ib), où a est la partie réelle et b la partie imaginaire.

Comme les nombres réels sont constitués de deux composantes (la partie réelle et la partie imaginaire), il est facile de les représenter graphiquement sur un plan. Par convention, la partie réelle du nombre est dessinée en abscisse et la partie imaginaire en ordonnée. Voici par exemple la représentation du nombre complexe (3 + i4) :

Plutôt que d’utiliser la forme (a + ib), il est également possible de représenter un nombre complexe par son module (la longueur du segment) et son argument (l’angle). On parle de notation polaire.

Le module, noté |z|, se calcule facilement au moyen du théorème de Pythagore :

$$|z|=\sqrt{a^{2}+b^{2}}$$

Opérations utiles

L’addition et la multiplication de nombres complexes est associative, commutative et distributive, au même titre qu’avec les nombres réels.

L’addition de deux nombres complexes (a+ib) et (a’+ib’) est une opération très simple :

$$(a + ib) + (a{}’ + ib{}’) = a+a{}’ + i(b+b{}’)$$

La multiplication de deux nombres complexes est une opération également relativement simple :

$$(a + ib) \cdot (a{}’ + ib{}’) = aa{}’ + aib{}’ + iba{}’ + i^{2}bb{}’$$

Comme i2= -1, on peut donc écrire :

$$(a + ib) \cdot (a{}’ + ib{}’) = aa{}’ – bb{}’ + i(ab{}’+a{}’b)$$

Pour représenter graphiquement l’ensemble de Mandelbrot, nous n’aurons pas besoin d’autres opérations.

L’ensemble de Mandelbrot

Un nombre complexe C fait partie de l’ensemble de Mandelbrot si la suite < ne tend pas vers l'infini (en module). .

Il a été démontré en 1990 que cet ensemble a une dimension de Hausdorff de 2. Cela signifie que dès que le module de cette suite dépasse 2, c’est que le nombre en question ne fait pas partie de l’ensemble de Mandelbrot.

À savoir également que l’ensemble de Mandelbrot est compris entre les nombres complexes (-2.1 – i1.2) et (0.6 + i1.2).

Représentation de l’ensemble de Mandelbrot

Pour afficher à l’écran l’ensemble de Mandelbrot, l’idée est d’associer à la surface de la fenêtre un intervalle de nombres complexes. Ainsi, chaque pixel de la fenêtre représente un nombre complexe pour lequel on pourra déterminer s’il appartient ou non à l’ensemble.

Il faut donc, pour chaque pixel de l’écran déterminer à quel nombre complexe il correspond, puis vérifier si ce nombre fait partie de l’ensemble de Mandelbrot. Si c’est le cas, le pixel sera affiché en noir. Sinon, il restera en blanc.

La plupart des langages de programmation ne permettent pas de manipuler en standard les nombres complexes. Toutefois, le calcul de la suite étant assez simple, il est facile de la calculer au moyen de nombres réels uniquement.

Posons et .

Calculons :

$$Z_{n+1}=Z_{n}\cdot Z_{n} + C=(Za_{n}+iZb_{n})\cdot (Za_{n}+iZb_{n}) + (Ca+ib)$$

$$Z_{n+1}=Za{_{n}}^{2}-Zb{_{n}}^{2}+i(2\cdot Za_{n} \cdot Zb_{n}) + Ca+iCb$$

Nous obtenons donc les calculs réels suivants :

$$Za_{n+1}=Z{_{na}}^{2}-Z{_{nb}}^{2}+Ca$$

$$Zb_{n+1}=2\cdot Za_{n} \cdot Zb_{n} + Cb$$

Reste à calculer cette suite pour déterminer si elle converge vers l’infini ou pas.

Nous avons vu plus haut que dès que le module de Z dépasse 2, il est certain que le nombre complexe en question ne fait pas partie de l’ensemble de Mandelbrot.

Il faut tester si le module est inférieur à 2 :

$$|z| < 2$$

Donc :

$$\sqrt{a^{2}+b^{2}} < 2$$

Nous pouvons simplifier le calcul en élevant les deux termes au carré :

$$a^{2}+b^{2} < 4$$

Par contre, si le nombre fait partie de l’ensemble, il faudrait calculer la suite à l’infini, ce qui n’est bien sûr pas réaliste. L’idée est donc de calculer les éléments de la suite jusqu’à un nombre d’itérations maximal, par exemple 200. Si après 200 itérations, le module de Z ne dépasse pas 2, on considère que la suite ne tend pas vers l’infini et que le nombre complexe fait partie de l’ensemble de Mandelbrot.

Il est donc impossible de dessiner cet ensemble de façon exacte. Sa représentation est une approximation dont l’exactitude dépend du nombre maximal d’itérations.

Algorithme

Voici l’algorithme permettant de vérifier si un nombre complexe C fait partie de l’ensemble de Mandelbrot :

procédure déterminant si C fait partie de l'ensemble de Mandelbrot
données : C : complexe
          Ca, Cb, Za, Zb, ZaTemp : réels
          Iteration, MaxIteration : entiers

début
   MaxIteration ← 200
   Ca ← partie réelle de C
   Cb ← partie imaginaire de C

   Za ← 0
   Zb ← 0

   Iteration ← 0

   tant que Za*Za + Zb*Zb < 4 et Iteration < MaxIteration faire
      ZaTemp ← Za*Za-Zb*Zb+Ca
      Zb ← 2*Za*Zb+Cb
      Za ← ZaTemp
      Iteration ← Iteration+1
   fin tant que

   si Iteration = MaxIteration alors
      le point fait partie de l'ensemble de Mandelbrot
   sinon
      le point ne fait pas partie de l'ensemble de Mandelbrot
   fin si
fin

Reste à utiliser cet algorithme pour dessiner quelque chose à l’écran. Il faut donc passer en revue chaque pixel de l’écran, déterminer à quels nombres complexes ils correspondent et les afficher s’ils appartiennent à l’ensemble de Mandelbrot.

Pour simplifier les choses, et comme l’ensemble de Mandelbrot est symétrique par l’abscisse, nous pouvons inverser l’orientation mathématique de l’axe imaginaire (l’ordonnée, axe vertical) afin qu’il soit dans la même direction que l’axe vertical d’affichage de l’écran.

procédure dessin de l'ensemble de Mandelbrot
données : LargeurEcran, HauteurEcran, Ligne, Colonne : entiers
          IntervalleComplexeGauche, IntervalleComplexeHaut,
          IntervalleComplexeDroite, IntervalleComplexeBas : réels
début
   IntervalleComplexeGauche ← -2.1
   IntervalleComplexeHaut ← 1.2
   IntervalleComplexeDroite ← 0.6
   IntervalleComplexeBas ← -1.2

   pour Ligne allant de 0 à HauteurEcran faire
      pour Colonne allant de 0 à LargeurEcran faire
         Ca ← Colonne * (IntervalleComplexeDroite - IntervalleComplexeGauche) / LargeurEcran + IntervalleComplexeGauche
         Cb ← Ligne * (IntervalleComplexeBas - IntervalleComplexeHaut) / HauteurEcran + IntervalleComplexeHaut

         si (Ca,Cb) fait partie de l'ensemble de Mandelbrot faire
            dessiner en Colonne, Ligne un point noir
         sinon
            dessiner en Colonne, Ligne un point blanc
         fin si
      fin pour
   fin pour
fin

 Implémentation en C++ avec Qt

Voici une implémentation simple en C++ et Qt des algorithmes présentés ci-dessus.

#include <QtGui/QApplication>

#include <QImage>
#include <QLabel>

const int IMAGE_WIDTH = 1024;
const int IMAGE_HEIGHT = 1024;

const int MAX_ITERATION = 200;

const unsigned int WHITE = 0x0FFFFFFFF;
const unsigned int BLACK = 0x0FF000000;

bool isInMandelbrotSet(double Ca, double Cb);

// Programme principal
int main(int ArgC, char *ArgV[]) {
    QApplication App(ArgC, ArgV);

    // Construit une image vide
    QImage Image(IMAGE_WIDTH, IMAGE_HEIGHT, QImage::Format_RGB32);
    Image.fill(WHITE);

    // Détermine l'intervalle à afficher
    QRectF ComplexArea(-2.2, -1.5, 3, 3);

    // Vérifie si les points font partie de l'ensemble de Mandelbrot
    for (int Line = 0; Line < IMAGE_HEIGHT; ++Line) {
        for (int Col = 0; Col < IMAGE_WIDTH; ++Col) {
            double Ca = Col * ComplexArea.width() / IMAGE_WIDTH + ComplexArea.left();
            double Cb = Line * ComplexArea.height() / IMAGE_HEIGHT + ComplexArea.top();

            if (isInMandelbrotSet(Ca, Cb))
                Image.setPixel(Col, Line, BLACK);
        }
    }

    // Affiche l'image dans une fenêtre
    QPixmap MandelbrotPixmap = QPixmap::fromImage(Image);
    QLabel Label;
    Label.setWindowTitle("Mandelbrot");
    Label.setPixmap(MandelbrotPixmap);
    Label.setMinimumSize(IMAGE_WIDTH, IMAGE_HEIGHT);
    Label.show();

    return App.exec();
}

// Détermine si le nombre complexe défini par Ca+iCb fait
// partie de l'ensemble de MandelBrot.
bool isInMandelbrotSet(double Ca, double Cb) {
    double Za = 0;
    double Zb = 0;

    int Iteration = 0;

    while (Za*Za + Zb*Zb < 4. && Iteration < MAX_ITERATION) {
        double ZaTemp = Za * Za - Zb * Zb + Ca;
        Zb = 2. * Za * Zb + Cb;
        Za = ZaTemp;
        ++Iteration;
    }

    return Iteration == MAX_ITERATION;
}

Et voilà le résultat :

Représentation colorée

Si vous avez déjà vu des représentations de l’ensemble de Mandelbrot, vous serez sans doute déçus par le résultat austère, noir et blanc, obtenu.

Toutefois, la représentation ci-dessus est conforme à la donnée mathématique : les points noirs sont ceux qui font partie de l’ensemble de Mandelbrot.

Par contre, ce qui est intéressant, ce sont les points qui ne font pas partie de l’ensemble. Au bout d’un certain nombre d’itérations, ces points sont exclus. L’idée est alors de leur donner un couleur, différente selon le nombre d’itérations qu’il a fallu pour les exclure.

Solution simple

Un ordinateur est capable de recréer des millions de couleurs en mélangeant (synthèse additive) les trois couleurs primaires rouge, vert et bleu.

Pour chaque couleur primaire, il est possible de donner une intensité comprise en zéro (noir) et 255 (couleur vive).

Nous pourrions donc fixer à 256 le nombre maximal d’itérations dans notre algorithme. Dès lors, il suffit d’utiliser directement le nombre d’itérations obtenu comme intensité d’une des couleurs de base, par exemple le rouge.

Si le nombre maximal (256) est atteint le point sera dessiné en noir.

Le programme doit être modifié de telle sorte que la méthode isInMandelbrotSet() retourne un paramètre supplémentaire contenant le nombre d’itérations.

#include <QtGui/QApplication>

#include <QImage>
#include <QLabel>

const int IMAGE_WIDTH = 1024;
const int IMAGE_HEIGHT = 1024;

const int MAX_ITERATION = 256;

const unsigned int WHITE = 0x0FFFFFFFF;
const unsigned int BLACK = 0x0FF000000;

bool isInMandelbrotSet(double Ca, double Cb, int* pIterationCount = 0);

// Programme principal
int main(int ArgC, char *ArgV[])
{
    QApplication App(ArgC, ArgV);

    // Construit une image vide
    QImage Image(IMAGE_WIDTH, IMAGE_HEIGHT, QImage::Format_RGB32);
    Image.fill(WHITE);

    // Détermine l'intervalle à afficher
    QRectF ComplexArea(-2.2, -1.5, 3, 3);

    // Vérifie si les points font partie de l'ensemble de Mandelbrot
    for (int Line = 0; Line < IMAGE_HEIGHT; ++Line) {
        for (int Col = 0; Col < IMAGE_WIDTH; ++Col) {
            double Ca = Col * ComplexArea.width() / IMAGE_WIDTH + ComplexArea.left();
            double Cb = Line * ComplexArea.height() / IMAGE_HEIGHT + ComplexArea.top();

            int Iteration = 0;
            if (isInMandelbrotSet(Ca, Cb, &Iteration))
                Image.setPixel(Col, Line, BLACK);
            else
               Image.setPixel(Col, Line, Iteration*256*256);
        }
    }

    // Affiche l'image dans une fenêtre
    QPixmap MandelbrotPixmap = QPixmap::fromImage(Image);
    QLabel Label;
    Label.setWindowTitle("Mandelbrot");
    Label.setPixmap(MandelbrotPixmap);
    Label.setMinimumSize(IMAGE_WIDTH, IMAGE_HEIGHT);
    Label.show();

    return App.exec();
}

// Détermine si le nombre complexe défini par Ca+iCb fait
// partie de l'ensemble de MandelBrot.
bool isInMandelbrotSet(double Ca, double Cb, int* pIterationCount) {
    double Za = 0;
    double Zb = 0;

    int Iteration = 0;

    while (Za*Za + Zb*Zb < 4. && Iteration < MAX_ITERATION) {
        double ZaTemp = Za * Za - Zb * Zb + Ca;
        Zb = 2. * Za * Zb + Cb;
        Za = ZaTemp;
        ++Iteration;
    }

    if (pIterationCount)
       *pIterationCount = Iteration;
    return Iteration == MAX_ITERATION;
}

Voilà le résultat obtenu :

Il y a sans doute moyen de faire mieux !

Le problème vient du fait que la surface éloignée de l’ensemble de Mandelbrot est très sombre, car il faut peu d’itérations pour déterminer que ces points ne font pas partie de l’ensemble.

Par contre, pour les points proches de la frontière de l’ensemble, les variations du nombre d’itérations sont plus marquées, mais le choix des couleurs ne rend pas compte de cette diversité.

Solution avancée

La meilleure solution est donc de mettre au point un dégradé de couleurs. Toute la difficulté sera de choisir judicieusement les couleurs constituant ce dégradé.

Voici un dégradé possible :

Les couleurs clés sont les suivantes :

Position Couleur R V B Hexadécimal
0 % rouge foncé 128 0 0 800000h
20 % jaune 255 255 0 FFFF00h
40 % orange 255 165 0 FFA500h
60 % pourpre 160 32 240 A020F0h
80 % bleu nuit 25 25 112 191970h
100 % rouge foncé 128 0 0 800000h

Et voilà le résultat correspondant :

Le rendu est bien plus satisfaisant !

La principale difficulté consiste donc à programmer le dégradé de couleur, en particulier en ce qui concerne les couleurs intermédiaires.

Pour ce faire, le plus simple est de coder une classe capable de gérer un dégradé entre certaines couleurs clé.

Le code étant trop long pour être affiché sur cette page, il peut être téléchargé : Projet Qt : MandelBrotGUI

À la découverte de la fractale

La partie amusante peut maintenant commencer : changer l’intervalle affiché afin d’admirer de magnifiques figures fractales.

C’est la ligne suivante qui détermine l’intervalle qui sera affiché :

    // Détermine l'intervalle à afficher
    QRectF ComplexArea(-2.2, -1.5, 3, 3);

Le premier nombre indique la limite gauche de l’intervalle (-2.2). Le deuxième nombre, sa limite haute (-1.5). Les deux derniers nombres indiquent la largeur et la hauteur de l’intervalle (3). Pour un affichage dans une fenêtre carrée, il faudrait que la largeur et la hauteur soient identiques.

Observons ce que l’on obtient avec les valeurs suivantes : -0.83, -0.21, 0.05, 0.05. La ligne de code devient QRectF ComplexArea(-0.83, -0.21, 0.05, 0.05);

Lissage des couleurs

Cette vue spectaculaire souffre toutefois encore d’un petit défaut : le dégradé de couleurs présente un effet d’escaliers. C’est la conséquence d’utiliser directement le nombre d’itérations pour obtenir une couleur, qui est un nombre entier. Le résultat est donc discret (à l’opposé de continu), ce qui provoque  dans certaines situations ces escaliers disgracieux.

Pour y remédier il existe différents algorithmes dont le normalized iteration count*. Il permet de calculer une variation décimale du nombre d’itérations pour obtenir un dégradé plus fin.

La formule est la suivante :

$$n+\frac{\log (\log b)-\log(\log \left | Z_{n} \right |)}{\log 2}$$

n est le nombre d’itérations et b le rayon de sortie (qui correspond à la dimension de Hausdorff et qui vaut donc 2 dans notre cas).

L’amélioration est nette :

Essayons d’autres valeurs : -0.749, -0.177488, 0.02, 0.02. La ligne de code devient QRectF ComplexArea(-0.749, -0.177488, 0.02, 0.02);

Nombre d’itérations

Nous avons vu plus haut que pour déterminer si un nombre fait partie de l’ensemble ou pas, il faudrait théoriquement calculer la suite à l’infini. Une approximation est donc réalisée en limitant le nombre d’itérations effectué lors du calcul de la suite.

Le problème d’une telle approximation, c’est que lorsqu’on veut afficher des détails, elle a un impact direct sur la précision obtenue.

Voici, pour les valeurs -0.726277, -0.257609, 0.000332257, 0.000332257 le résultat avec une limite de 256 itérations :

La cardioïde est passablement déformée. Voici une meilleure approximation avec une limite de 512 itérations :

Avec une limite de 1024 itérations :

Et enfin avec une limite de 2048 itérations :

Toute la difficulté revient à trouver une limite qui donne de bons résultats, en un temps acceptable !


Sources :

Wikipédia : Ensemble de Mandelbrot

Wikipedia : Mandelbrot set

Coloring dynamical systems in the complex plane, Garcia, Fernandez, Barrallo, Martin

Vitesse moyenne

January 14th, 2012

Voici un petit problème physico-mathématique que j’ai trouvé très intéressant.

L’énoncé est très simple :

Une voiture se déplace d’un point A à un point B à la vitesse constante de 10 km/h.
À quelle vitesse (toujours constante) doit-elle rouler, en revenant du point B jusqu’au point A, pour que sa vitesse moyenne soit de 22 km/h ?


Photo de Ian Britton, obtenue de www.freefoto.com.

Avant de continuer de lire, essayez de trouver la réponse !

Première solution

Vous avez peut-être obtenu comme réponse 34 km/h, sans être franchement convaincu de la justesse du résultat ?

En faisant une simple moyenne arithmétique, on obtient effectivement 34 km/h.

$$v_{moyenne} = \frac{v_{aller} + v_{retour}}{2}$$

$$v_{moyenne} = \frac{v_{aller} + v_{retour}}{2}$$

$$v_{retour} = 2\cdot v_{moyenne}-v_{aller} = 2\cdot 22-10=34\, km/h$$

Le problème avec cette solution est qu’elle ne tient pas compte du temps. Si la voiture avait roulé autant de temps à 10 km/h qu’à 34 km/h, sa moyenne serait effectivement 22 km/h.

Mais, en roulant à 10 km/h le long de la distance AB, elle va passer plus de temps à cette vitesse qu’en revenant depuis le point B.

Deuxième solution

Dès lors, il faut réécrite notre équation en tenant compte du temps. Pour ce faire, rappelons la formule de base pour le calcul d’une vitesse :

$$vitesse = \frac{distance}{temps}$$

Dès lors, le temps pour parcourir une distance se calcule ainsi :

$$temps = \frac{distance}{vitesse}$$

Soient et les vitesses d’aller et de retour et la distance entre le point A et le point B.

Soit le temps passé pour aller du point A au point B :

$$t_{aller} = \frac{AB}{v_{aller}}$$

Soit le temps passé pour aller du point B au point A :

$$t_{retour} = \frac{AB}{v_{retour}}$$

$$v_{moyenne} = \frac{distance\,totale}{temps\,total} = \frac{2\cdot AB}{t_{aller} + t_{retour}}=\frac{2\cdot AB}{\frac{AB}{v_{aller}}+\frac{AB}{v_{retour}}}$$

$$v_{moyenne} = \frac{2\cdot AB}{\frac{AB\cdot v_{retour}}{v_{aller}\cdot v_{retour}}+\frac{AB\cdot v_{aller}}{v_{retour}\cdot v_{aller}}}=\frac{2\cdot AB\cdot v_{aller}\cdot v_{retour}}{AB\cdot (v_{aller}+v_{retour})}=2\cdot\frac{v_{aller}\cdot v_{retour}}{v_{aller}+v_{retour}}$$

À partir de cette dernière formule, retrouvons celle permettant de calculer la vitesse retour :

$$v_{moyenne}\cdot v_{aller} + v_{moyenne}\cdot v_{retour} = 2\cdot v_{aller}\cdot v_{retour}$$

$$v_{moyenne}\cdot v_{retour} – 2\cdot v_{aller}\cdot v_{retour} = -v_{moyenne}\cdot v_{aller}$$

$$v_{retour} (v_{moyenne} – 2 v_{aller}) = -v_{moyenne}\cdot v_{aller}$$

$$v_{retour}=-\frac{v_{moyenne}\cdot v_{aller}}{v_{moyenne} – 2 v_{aller}}$$

Il ne nous reste plus qu’à résoudre la formule avec des valeurs numériques :

$$v_{retour}=-\frac{22\cdot 10}{22 – 2\cdot 10}=-\frac{220}{2}=-110\,km/h$$

Voilà un résultat pour le moins surprenant ! Est-ce qu’il indique une erreur ? Vérifions notre calcul :

$$v_{moyenne} =2\cdot\frac{v_{aller}\cdot v_{retour}}{v_{aller}+v_{retour}}=2\cdot\frac{10\cdot -110}{10+(-110)}=\frac{-2200}{-100}=22\,km/h$$

Il faut se rendre à l’évidence : notre calcul est mathématiquement parfaitement juste ! Par contre, il est physiquement irréalisable !

Explication

Cela peut être expliqué de la façon suivante : si à l’aller, notre vitesse moyenne est de 10 km/h, cela signifie qu’en une heure, nous avons parcouru 10 kilomètres. Si nous avions la possibilité de revenir instantanément à notre point de départ, nous aurions alors parcouru, en une heure, 20 kilomètres (l’aller-retour), ce qui donne une vitesse moyenne de 20 km/h.

En clair, il est impossible de faire plus que doubler sa vitesse moyenne.

Pour illustrer cela différement, dessinons la courbe de notre fonction :

On voit que la courbe pour une vitesse de retour positive tend vers 20 km/h.

Ceci peut être également démontré au moyen des limites.

$$v_{moyenne} =2\cdot\frac{v_{aller}\cdot v_{retour}}{v_{aller}+v_{retour}}$$

Si l’on note v pour la vitesse de retour :

$$\lim\limits_{v \to \infty} 2\cdot\frac{v_{aller}\cdot v}{v_{aller}+v}=2\cdot v_{aller}$$

La limite confirme donc ce que l’on a vu plus haut.

Conclusion

Nous avons vu lors de la première solution que la moyenne arithmétique n’est pas adaptée à ce genre de problème.

Dans notre situation, c’est la moyenne harmonique qu’il faut utiliser.

À noter que si vous avez des notions de base d’électrotechnique et plus particulièrement de calculs de circuits de résistances, vous avez déjà utilisé, peut-être sans le savoir, la moyenne harmonique pour calculer un couplage parallèle de résistances.

Calculs cycliques et modulo

December 16th, 2011

Le modulo

L’opération arithmétique modulo est souvent utilisée en informatique, et plus particulièrement dans le développement.

Elle est souvent présentée comme le reste d’une division entière. Par exemple :

7 ÷ 2 = 3 reste 1. Ainsi, 7 modulo 2 = 1.

27 ÷ 24 = 1 reste 3. Ainsi, 27 modulo 24 = 3.

C’est une opération qui se révèle très utile dès que l’on a affaire à des calculs cycliques, le plus connu étant le problème de l’horloge.

En effet, une horloge (digitale dans notre exemple) indique l’heure de la journée de façon numérique, les heures allant de 0 (minuit) à 23. Une heure après 23 heures, il est minuit. L’horloge recommence un cycle à zéro.

Il existe bien sûr d’autres exemples, ayant des cycles différents. Par exemple, une montre analogique a un cycle de 12 : lorsque l’aiguille a fait un tour complet, elle reprend à 1.


Les angles (en degrés) ont un cycle de 360, etc.

Calculs cycliques

Lorsque des calculs cycliques doivent être effectués, il faut tenir compte de la durée du cycle.

Par exemple, s’il est 10 heures et que l’on souhaite calculer l’heure qu’il sera dans 5 heures, il suffit de faire une addition : 10 + 5 = 15 heures.
Par contre, si il est 22 heures (et que l’on souhaite encore calculer l’heure qu’il sera dans 5 heures), la simple addition abouti à un résultat erroné : 22 + 5 = 27 heures.

Le problème vient du fait que toutes les 24 heures, l’horloge recommence à zéro. Elle travaille donc dans une arithmétique modulaire (cyclique) dont le cycle, nous l’avons vu, est de 24 heures.

L’opération arithmétique modulo permet de tenir compte du cycle. Ainsi, pour garantir que le résultat soit toujours conforme au cycle de 24 heures de l’horloge, il suffit d’appliquer un modulo à l’addition :

heure ultérieure = (heure actuelle + décalage) modulo 24.

En reprenant notre exemple :

heure ultérieure = (22 + 5) modulo 24 = 3

Ce qui est correct : 5 heures après 22 heures, il sera 3 heures du matin.

Maintenant, essayons de faire la même chose mais pour calculer une heure précédente.

Par exemple, s’il est 11 heures et que l’on souhaite calculer l’heure qu’il était il y a 7 heures, il suffit de faire une soustraction : 11 – 7 = 4 heures.
Par contre, s’il est 6 heures (et que l’on souhaite encore calculer l’heure qu’il était il y a 7 heures), la simple soustraction aboutit à un résultat erroné : 6 -7 = -1 heures. Ce n’est pas une surprise.

Dès lors, il semble logique qu’il faille appliquer la technique du modulo :

heure précédente = (heure actuelle – décalage) modulo 24.

ou selon notre exemple : heure précédente = -1 modulo 24.

Mais quel est le reste de la division de -1 par 24 ?

-1 ÷ 24 = 0 reste -1

C’est là que les problèmes commencent : dans le cas d’une arithmétique cyclique, le résultat attendu n’est pas -1 mais 23.

Cet exemple met en lumière que le reste d’une division entière et le modulo ne sont pas interchangeables :

  • Tant que les calculs sont effectués sur des nombres positifs, le reste de la division entière et le modulo donnent des résultats identiques.
  • Dès qu’un des nombres de la division est négatif, les deux opérations ne fournissent plus les mêmes résultats.

En résumé

Nous venons de voir que le modulo n’est pas une opération identique au reste de la division entière. Elle diffère en particulier lorsque le dividende et/ou le diviseur sont négatifs.

Voici un tableau récapitulatif :

Dividende Diviseur Quotient Reste Modulo
27 24 1 3 3
24 24 1 0 0
15 24 0 15 15
0 24 0 0 0
-1 24 0 -1 23

Reprenons la façon de calculer le reste d’une division :

La partie intéressante est l’arrondi : quel arrondi utiliser pour convertir le résultat de la division (un nombre réel) en un nombre entier ? Car il y a bien sûr plusieurs façons d’arrondir un nombre.

La réponse la plus évidente est de ne garder que la partie entière du résultat (c’est une troncature). Par exemple, la partie entière de 3.4 est 3. La partie entière de 4.9 est 4.

Il en résulte que la partie entière est toujours inférieure ou égale au nombre réel.

Qu’en est-il lorsque le résultat est négatif ?

Si l’on fait une troncature, la partie entière de -3.4 est -3. La partie entière de -4.9 est -4.

On constate qu’avec cette méthode le sens de l’arrondi change pour les nombres négatifs : les nombres arrondis sont supérieurs ou égaux aux nombres réels.

Une autre alternative serait alors d’arrondir le nombre réel au nombre entier inférieur (arrondi vers -∞). Ainsi, l’arrondi de -3.4 serait -4 et celui de -4.9 serait -5. Ainsi, peu importe que le nombre à arrondir soit positif ou négatif, son arrondi est toujours égal ou inférieur.

Il y a donc deux façons d’arrondir un nombre à virgule qui nous intéresse et qui donnerait des résultats corrects : soit en effectuant une troncature(arrondi vers zéro), soit en effectuant un arrondi vers -∞.

Ces deux façons de faire aboutissent au même résultat pour les nombres positifs, mais à des résultats différents pour les nombres négatifs.

C’est cette différence de méthode d’arrondi qui débouche soit sur le calcul d’un reste de la division (troncature), soit sur le modulo (arrondi vers -∞).

En résumé :

L’opérateur modulo en C++

Voyons maintenant comment réagit l’opérateur modulo en C++, symbolisé par le symbole % :

cout << 27 % 24 << "\n" // affiche 3
cout << -1 % 24 << "\n" // affiche -1

On voit que l’opérateur modulo (%) est mal nommé : il ne calcule pas le modulo, mais le reste de la division entière. Ceci provient du fait qu’en C++, la division entière utilise la troncature
pour convertir un résultat réel en entier.

Pour calculer le modulo en C++, il faut donc écrire notre propre fonction, qui utilisera un arrondi vers -∞ :

int modulo(int Dividende, int Diviseur) {
   return Dividende - std::floor(static_cast<double>(Dividende)/Diviseur) * Diviseur;
}

La fonction floor() (de la bibliothèque cmath) effectue un aarrondi vers -∞.

Le static_cast<double>() permet de forcer la division à être effectuée sur des nombres réels. Sans cela, la division retournerait directement un résultat entier (obtenu par troncature
) et la fonction floor() n’aurait plus aucun effet.

Par souci de clarté, on pourrait également écrire notre propre fonction calculant le reste de la division, en utilisant une troncature :

int remainder(int Dividende, int Diviseur) {
   return Dividende - Dividende/Diviseur * Diviseur;
}

Mais vous l’avez compris, cette fonction fait double emploi avec l’opérateur %.

Excel et VBA

Excel propose la fonction MOD(), qui calcule bel et bien le modulo.

Par contre, il faut faire attention à l’opérateur Mod de VBA, qui calcule, comme son nom ne l’indique pas, le reste !

Dividende Diviseur Quotient Reste Modulo Fonction Excel MOD() Opérateur VBA Mod
27 24 1 3 3 3 3
24 24 1 0 0 0 0
15 24 0 15 15 15 15
0 24 0 0 0 0 0
-1 24 0 -1 23 23 -1

C’est bien beau, mais à quoi ça sert ?

Voici un exemple concret qui illustre bien l’intérêt de comprendre la différence entre le reste et le modulo. Nous allons réaliser un petit programme de codage/décodage au moyen du chiffre de César.

Le chiffre de César est une méthode de chiffrement très simple (et peu robuste). Elle consiste à remplacer chaque lettre d’une phrase par une lettre à distance fixe dans l’ordre de l’alphabet. Par exemple, avec un décalage de 3, la lettre A devient D, la lettre J devient M, etc.

Ainsi, la phrase BONJOUR LES AMIS, avec un décalage de 3, deviendra ERQMRXU OHV DPLV !

Pour implémenter dans un langage informatique cette méthode de chiffrement, il faut au préalable numéroter chaque lettre (lui donner un numéro), afin de pouvoir faire le calcul du décalage.

Lors du calcul du décalage, il faut tenir compte de l’aspect cyclique de la numérotation des lettres de l’alphabet : après la lettre Z (qui a le numéro 25), il faut reprendre à la lettre A (qui a le numéro 0). Cette difficulté est contournée par l’utilisation du modulo.

Voici une première implémentation en C++ de notre application :

// Codage/décodage au moyen du chiffre de César
#include <iostream>
#include <string>
#include <algorithm>
#include <cmath>

using namespace std;

int modulo(int Dividende, int Diviseur);
int numeroDeLettre(char Letter);
char lettreDeNumero(int LetterNumber);
bool estUnCaractere(char Char);
string encodeCesar(string Phrase, int Shift);
string decodeCesar(string Phrase, int Shift);

// Programme principal
int main() {
    string Phrase;
    int Decalage = 0;

    // Saisie de la phrase et du décalage
    cout << "Phrase a coder : ";
    getline(cin, Phrase);

    // Converti la phrase en majuscules
    transform(Phrase.begin(), Phrase.end(), Phrase.begin(), ::toupper);

    cout << "Decalage : ";
    cin >> Decalage;

    // Codage et décodage
    string PhraseEncodee = encodeCesar(Phrase, Decalage);
    cout << "\nPhrase codee :  " << PhraseEncodee << "\n\n";

    return 0;
}

// Retourne le numéro de la lettre donnée en paramètre.
int numeroDeLettre(char Lettre) {
    return Lettre - 'A';
}

// Retourne la lettre correspondant au numéro donné en paramètre.
char lettreDeNumero(int NumeroDeLettre) {
    return NumeroDeLettre + 'A';
}

// Retourne un booléen indiquant si le caractère donné correspond à une
// lettre de l'alphabet.
// Par souci de simplification, les lettres accentuées sont ignorées.
bool estUnCaractere(char Caractere) {
    return Caractere >= 'A' && Caractere <= 'Z';
}

// Encode la chaîne passée en paramètre avec le décalage donné.
string encodeCesar(string Phrase, int Decalage) {
    string::iterator it = Phrase.begin();
    // Chaque caractère de la phrase est codé l'un après l'autre
    for(; it != Phrase.end(); it++) {
        if (estUnCaractere(*it)) {
            int NumeroDeLettre = numeroDeLettre(*it);
            int NumeroDeLettreDecalee = (NumeroDeLettre + Decalage) % 26;
            (*it) = lettreDeNumero(NumeroDeLettreDecalee);
        }
    }
    return Phrase;
}

Voici le résultat de ce petit programme :

Phrase a coder : COMMENT ALLEZ-VOUS ?
Decalage : 3

Phrase codee :  FRPPHQW DOOHC-YRXV ?

Press <RETURN> to close this window...

Le décodage, par contre, met en lumière la différence entre le modulo et le reste de la division entière. Si la lettre A (numéro 0) doit être décalée d’une position à gauche (-1), la lettre à obtenir est la lettre Z (numéro 25) et non pas le numéro -1, qui ne correspond à aucune lettre.

Dividende Diviseur Quotient Reste Modulo
25 26 0 25 25
26 26 0 0 0
0 26 0 0 0
-1 26 0 -1 25

C’est donc bel et bien le calcul du modulo qu’il faut utiliser et non pas celui du reste. En C++, il ne faut donc pas utiliser l’opérateur %, mais plutôt la fonction modulo() vue plus haut.

La fonction de décodage peut donc être écrite ainsi :

// Décode la chaîne passée en paramètre avec le décalage donné.
string decodeCesar(string Phrase, int Decalage) {
    string::iterator it = Phrase.begin();
    for(; it != Phrase.end(); it++) {
        if (estUnCaractere(*it)) {
            int NumeroDeLettreCodee = numeroDeLettre(*it);
            int NumeroDeLettreDecodee = modulo(NumeroDeLettreCodee - Decalage, 26);
            (*it) = lettreDeNumero(NumeroDeLettreDecodee);
        }
    }
    return Phrase;
}

Sources :

Wikipédia : modulo informatique

Wikipedia : modulo operation

The math forum : Mod function and Negative Numbers

Accès à distance

September 23rd, 2011

Pour accéder à mon serveur maison depuis l’extérieur, j’ai configuré un compte DynDns.

Une fois le compte créé, un nom de domaine m’est réservé, à laquelle est associée l’adresse IP de mon modem ADSL.

Configuration du serveur

Cette adresse IP va changer régulièrement. Il faut donc installer sur le serveur Mac un petit logiciel (fourni par DynDns) qui va régulièrement communiquer à DynDns la nouvelle adresse IP.

L’installation du logiciel est très simple : il suffit de le copier dans le dossier Applications et de la démarrer.

Ensuite, ajouter un hôte (celui créé chez DynDns), l’activer, et la configuration du serveur est terminée.

Configuration du modem

Il reste encore à configurer le modem, afin qui redirige les données provenant de l’extérieur à la bonne machine, en l’occurrence le Mac mini.

En ce qui me concerne, mon modem (configurable au travers d’un navigateur internet  à l’adresse 192.168.0.1) prend en charge le service DynDns, abrégé DDNS.

Il suffit donc de lui fourni mon nom d’utilisateur, mon mot de passe, le nom de l’hôte (mon_nom.dyndns.org dans mon cas) et le tour est joué !

Convertir une séquence d’images en PDF

August 24th, 2011

Il m’arrive souvent de devoir convertir une séquence d’images en un document PDF.

La solution la plus simple et la plus performante que j’ai trouvé est d’utiliser l’application Combine PDFs de Monkeybread Software.

Il suffit de glisser-déposer la suite d’images à combiner, puis choisir Combiner toutes pages (cmd – S) pour obtenir un fichier PDF.