Générateur d'images fractales (1)

03022009 Dans: Pas à pas

Cet article est le premier d'une série consacrée à la réalisation d'une application complète: un générateur d'images fractales.

Les fractals

Broccoli fractal

Les fractals sont des objets géométriques qui présentent des motifs similaires lorsqu'ils sont observés à des échelles différentes. On ne peut les évoquer sans parler de l'incontournable Benoît Mandelbrot, polytechnicien français, qui ne les a certes pas inventé, mais leur a donné leur nom, et fut le premier à leur trouver des applications: calculs du périmètres des côtes bretonnes, statistiques, et surtout — ce qui a vraiment permis leur exposition au grand public — l'imagerie informatique.

Quelques rappels sur les nombres complexes

Le calcul de l'image s'appuyant sur les nombres complexes, je vais vous rappeler les principes nécessaires ici.

Nombres complexes

Un nombre complexe est de la forme:

z = a + ib
avec i^2 = -1

  • a est appelé partie réelle
    quand z représente les coordonnées d'un point, a est l'abscisse de ce point.

  • b est appelé partie imaginaire
    b représente l'ordonnée du point

Mise au carré

Mettons z au carré:
z * z = (a+ib)(a+ib) = a^2 + 2iab - b^2

Module

Le module de z est noté |z|.

|z|=√(a^2 + b^2).

L'ensemble de Mandelbrot

Beaucoup de gens ont déjà programmé des générateurs d'images fractales; le nôtre n'aura rien de révolutionnaire. On retrouve habituellement dans ces programmes deux ensembles: celui de Julia et celui de Mandelbrot, tous deux faciles à implémenter. Nous allons nous concentrer sur ce dernier.

Je suis bien incapable de vous expliquer le principe mathématique, mais peu importe, ce qui nous intéresse est le résultat !

La méthode de calcul

L'ensemble se calcule grâce à la suite:

z[n+1] = z[n]^2 + c
Avec z[0] = 0

z et c sont des nombres complexes:

  • c représente les coordonnées du point du plan en cours de calcul.

  • la suite z diverge après un certain nombre d'itérations — ou pas. Ce qui nous intéresse est le nombre n d'itérations nécessaire pour diverger, sachant que la suite diverge quand |z| > 2.
    Il sera nécessaire de limiter le calcul à un certain nombres d'itérations.

Conversions des coordonnées

Nous utiliserons une bitmap pour composer l'image. Une bitmap est une grille de pixels. Pour notre premier exemple, j'ai choisi d'adopter des dimensions de 400 par 300 pixels.
Le calcul de l'ensemble de Mandelbrot se fait lui sur un plan mathématique. J'ai choisi de faire évoluer ses abscisses entre -2 et +2. Par conséquent ses ordonnées évolueront entre -1,5 et +1,5 pour conserver les mêmes proportions que la bitmap.

Conversion des coordonnées

Grâce à la figure, on peut déterminer que les coordonnées se convertissent ainsi:

c.réelle = bitmapX/100 - 2  
c.imaginaire = -bitmapY/100 + 1,5

La couleur

Tous les exemples d'images que vous avez dû voir sont très colorés, cependant, c'est uniquement le nombre d'itérations n qui nous donne la teinte. Pour commencer nous allons donc produire une image en niveaux de gris, 256 niveaux exactement (de 0 à 255).

nuance = (n/MaxIterations) * 255

MaxIterations est le nombre maximal d'itération. J'ai choisi après plusieurs essais que MaxIterations = 18.

La suite

Dans le prochain billet, nous mettrons au point la première version du générateur. Ne zappez pas !

Renaud Pradenc
ceroce.com

Créer des jeux en Lua avec Löve

01022009 Dans: Liens, Mac OS X

L'équipe de développement de Löve vient de sortir une version Mac de son moteur de jeux 2D en Lua. Lua est un langage de script qu'il est facile d'intégrer dans un programme, ce qui le rend particulièrement utilisé dans les jeux pour rendre le développement de certaines parties du jeu plus rapide. Un des jeux les plus connu l'utilisant est World of Warcraft.

Vous pourrez trouvez sur le site du projet des exemples et de la documentation pour commencer à faire des petits jeux :

En plus d'être un succès commercial, l'iPhone semble visiblement être aussi un succès en édition, avec pour preuve la sortie d'un nouveau livre le concernant chez O'Reilly. Il s'agit cet fois de iPhone SDK Application Development écrit par Jonathan Zdziarski.

Ce nom ne vous dit peut être rien, mais il s'agit de la personne ayant créer le SDK officieux avant qu'Apple se décide à lancer le sien. Il avait d'ailleurs à cette occasion écrit un livre sur le développement iPhone avec ce SDK Open Source (iPhone Open Application Development). Pour avoir eux l'occasion de parcourir ce livre, je dois dire qu'il est intéressant, mais peu utile pour les gens voulant développer des applications destinées à l'AppStore. Il reste donc plus destiné aux hackers de l'iPhone.

Si l'on trouve beaucoup de ressources techniques concernant le développement sur iPhone, les ressources orientées business et entrepreneuriat sont beaucoup plus rare. Le problème est maintenant résolu avec un document sur l'écosystème iPhone d'une manière générale d'une part et sur l'application Coffee Buzz d'autre part :

IBM vient de mettre en ligne un article sur l'utilisation conjointe de l'iPhone et de Google AppEngine, la plate-forme d'hébergement d'applications web de Google. Les auteurs de l'articles proposent de plus le code source associé à l'article sous la forme d'un projet open source :

Après quelques jours sans billets de ma part, voici une grosse sélection des dernières actualités utiles pour les développeur Mac :

  • Cocoa for Scientists est une série d'article pour apprendre àutiliser Cocoa dans des applications scientifiques. Cela va de la présentation de données en 2D ou 3D, à la gestion du réseau avec Bonjour, en passant par la gestion des threads.
  • pysmell est un outil qui propose de l'auto-complétion du code Python dans différents logiciels dont TextMate.
  • Si vous pouvez vous rendre en Angleterre le 16 et 17 Avril 2009, essayer de faire à tour à MacDev 2009, la conférence pour les indépendants sur le développement Mac. En tout cas, la liste des conférenciers est particulièrement intéressante.

Et parce que Cocoa c'est aussi l'iPhone, voici quelques liens en provenance de Mobile Orchad qui peuvent vous être utiles :

Pour finir, je voudrais juste signaler que je vais dans la journée migrer le site sur un nouveau serveur. Les commentaires seront désactivés sur l'ancien serveur. Si vous pouvez ajouter des commentaires, c'est que vous voyez la nouvelle version.

Les bogues ne sont pas une fatalité: ce sont des défauts dus à des erreurs d'êtres humains:

  1. Trop grande complexité
  2. Méconnaissance des API ou du langage
  3. Étourderies
  4. Laxisme !

Comme vous êtes comme moi et détestez passer vos après-midi sur un débogueur, voici quelques stratégies éprouvées pour les réduire.

10. Documentez

Je vais ici seulement insister sur les aspects de la doc qui permettent de limiter les bogues :

  • Rédigez une partie de la description d'une méthode avant de la coder
    Vous devez réfléchir aux cas particuliers du déroulement, aux valeurs possibles des arguments d'entrée (notamment comment gérer les gammes de valeurs inattendues), et quelles erreurs peuvent subvenir pendant l'exécution. Inspirez-vous de la programmation par contrat.

  • Faites des commentaires utiles
    Ils ne doivent pas paraphraser le code, ni expliquer chaque appel de méthode. Expliquez le cheminement du code, et soulignez ce qui est le moins évident. C'est très utile au débogage, quand on revient au code quelques semaines plus tard.

  • Nommez vos variables avec grand soin
    Je suis toujours étonné qu'à notre époque, les gens nomment encore leurs variables i,j, tab[] ou ptr, dans la plus pure tradition du Kernighan & Ritchie. Il m'est arrivé de rendre des bogues évidents rien qu'en renommant.

9. Relisez-vous

D'expérience, la moitié des bogues pourraient être évités lors de l'écriture du code. Je ne parle pas des erreurs de syntaxes (signalées par le compilateur), mais utiliser une variable à la place d'une autre, effectuer les opérations dans le mauvais ordre, etc.

Si vous programmez seul, pensez à relire — avec un œil critique s'entend — votre nouveau code systématiquement avant de compiler.

8. Corrigez les bogues dès qu'ils apparaissent

Il arrive fréquemment de découvrir un bogue, et de le laisser à plus tard. Comme vous êtes un programmeur consciencieux, vous y reviendrez. Mon expérience dicte de corriger le bogue immédiatement, parce qu'il arrive souvent de commettre encore et encore la même erreur. Mieux vaut donc la corriger au plus tôt, pour ne faire l'erreur qu'une fois.

7. Testez les codes d'erreur et gérez les exceptions

À moins que cela n'alourdisse exagérément le code, il est sage de vérifier les résultats des fonctions. Gérez aussi les exceptions. Ces deux tâches triviales ne doivent pas être laissées à plus tard — c'est à dire jamais.

6. Créez des projets d'essai

Bien que je travaille sur un gros projet, je crées de nombreux petits projets annexes. Le dernier en date était destiné à vérifier sur mon site web si une nouvelle version de l'appli est disponible. Je n'avais aucune expérience du téléchargement d'un fichier texte. Sur ce petit programme de vingt lignes, j'avais tout de même commis deux bogues. Avoir un programme léger permet de les cerner rapidement.

Si j'avais intégré la fonction directement dans mon appli, je me serais demandé si les problèmes venaient du nouveau code ou de l'ancien. J'aurais peut être modifié du code valide. Enfin, maîtriser une technologie permet de savoir comment l'intégrer au mieux au reste de l'application.

5. Ayez des scénarios de test sous la main

D'expérience, il arrive que les bogues apparaissent dans des circonstances déjà rencontrées. Lorsque vous avez trouvé une procédure pour reproduire un bogue à coup sûr, notez-là et déroulez cette procédure à chaque version. Si possible, automatisez les tests. Par exemple, les tests de l'interface utilisateur peuvent être automatisés avec Instruments.

4. Écrivez des tests unitaires

Les tests unitaires s'appliquent essentiellement aux classes de la couche modèle. Ma première expérience fut une classe que je n'arrivais pas à mettre au point pour un programme de musique, qui devait renvoyer les notes faisant partie d'une gamme. J'étais capable de trouver ces notes sur le papier, mais je m'y suis repris à trois fois avant d'avoir un algorithme… qui ne marchait pas dans certains cas particuliers.

Après avoir écrit les tests unitaires, les erreurs apparaissaient de façon évidente dans la couche modèle, plutôt que de manière indirecte dans l'interface utilisateur. J'ai gagné du temps, et j'étais enfin sûr de mon code.
Nous reviendrons sur les tests unitaires, à la mode, et ceci pour d'autres très bonnes raisons.

3. Réduisez les contraintes

Comme dit plus haut, la cause principale des bugs est la complexité. En effet, des scientifiques ont mesuré que les individus les plus doués étaient capables de prendre en compte simultanément sept contraintes. Pour la plupart des gens, c'est plutôt quatre (<- c'est là que je me situe).

L'idée est donc de limiter la complexité du logiciel:

  • en ajoutant de l'abstraction
    pour pouvoir se concentrer sur la tâche présente au lieu des détails d'implémentation.

  • en limitant le couplage
    c'est à dire les interdépendances entre objets.

Et cela est difficile. Très. Beaucoup de gens se disent programmeur ("oui, j'ai étudié un peu le langage C pendant mes études de biologie"), mais peu ont déjà travaillé sur un projet conséquent, un où les bogues deviennent difficiles à résoudre et semblent réapparaître sans cesse.

Je n'ai pas de secret, il faut se forger une expérience: étudier les patrons de conception, savoir comment fonctionne la machine et le système d'exploitation, étudier d'autres langages de programmation ou d'autres bibliothèques…

2. Ne construisez que les infrastructures nécessaires maintenant

Ce point est un peu en contradiction avec le précédent. En effet, quand on commence à ajouter de l'abstraction, on a ensuite tendance à vouloir rendre tout réutilisable et générique. Imaginons que vous vouliez écrire un texte en rouge. Il est tentant d'écrire une méthode générique qui prend la couleur en paramètre, pour le jour où vous voudriez écrire en vert.

Pourtant, la méthode générique sera forcément plus difficile à écrire et à tester. Pourquoi passer du temps sur quelque chose d'inutile aujourd'hui ? Attendez un jour prochain que le besoin soit réel. De plus, une méthode simple sera une bonne base de départ pour écrire une méthode plus complexe.

1. Codez moins

Aucun code n'est plus flexible que pas de code.

Il existe souvent une méthode qui rend 80% du service avec seulement 20% du travail que demanderait une méthode parfaite. Ne visez pas la perfection. La vie est trop courte ! Demandez-vous si vos utilisateurs préfèrent une fonction parfaite dans un an ou une fonction correcte aujourd'hui.

Moins de code = moins de bogues
Travaillez le cœur de métier de votre logiciel. Les détails seront réglés plus tard (voire jamais).

Pour finir

Voilà les méthodes que j'utilise — avec plus ou moins de rigueur — pour conserver mes applis stables. Auriez-vous d'autres techniques à proposer ?

L'indépendance de la résolution

20012009 Dans: Cocoa, Mac OS X

La résolution

Commençons par rappeler ce qu'est la résolution. On l'exprime habituellement en points par pouce. C'est à dire qu'il s'agit du nombre de points — pour un écran, des pixels — alignés sur un pouce de longueur (1 pouce = 2,54 cm).
L'abréviation ppp (points par pouce) se rencontre, mais l'abréviation anglaise dpi (Dots per Inch) est la plus courante.

Paradoxe: "Plus les pixels sont nombreux, et moins on les voit".

Des pixels aux centimètres

Si vous avez bien suivi, vous pourrez tenter de répondre à cette question: combien faut-il aligner de pixels pour tracer un segment d'un centimètre de long ? Réfléchissez.

En fait il vous manque quelques données pour répondre. Alors, prenons l'exemple de l'écran de mon iMac: il affiche 1440 x 900 pixels. Sa diagonale mesure 17 pouces. Les pixels sont carrés.

Calcul des dimensions physiques de l'écran

Commençons par calculer les dimensions physiques de l'écran, grâce au théorème de Pythagore:
largeur^2 + hauteur^2 = diagonale^2

Sachant que
largeur = (1440/900) x hauteur = 1,6 x hauteur

Vous devez trouver:
hauteur = 9 pouces
largeur = 14,41 pouces

Calcul de la résolution

L'écran a donc une résolution de 900 pixels / 9 pouces = 100 points/pouce.

La réponse à la question de départ

En divisant par 2,54, on trouve que 100 ppp correspond à 39,37 points/cm. Il faudra donc aligner 39 pixels pour tracer un segment d'un centimètre de long.

Où veux-tu en venir, Renaud ?

Ça vient ! Prenons l'exemple de votre traitement de texte habituel. Le format d'impression est un A4 et le zoom est réglé à 100%. Comment se fait-il alors que lorsque je superpose une feuille A4, la feuille à l'écran est plus petite ?

Réponse: parce que le traitement de texte part du principe que la résolution de votre écran est de 72 ppp. Pourquoi 72 ppp ? C'est historique; dans les années 90, c'était une résolution courante pour un écran. Sous Windows, il me semble qu'on utilise 85 ppp, ce qui est un peu plus proche de la réalité. Tout ça n'est tout de même pas très WYSIWYG.

Donc, si je veux voir la page à la taille réelle sur mon iMac, il faut que je règle le zoom à (100 / 72) = 139%.

Pourquoi ce problème n'est pas encore résolu en 2009 ?

Notez bien que la résolution de chaque écran est différente, elle est plus dense encore pour l'écran de mon MacBook. Des API existent pour connaître la définition (en pixels) de l'écran. On peut sans doute également obtenir sa diagonale (en pouces) et procéder au calcul vu plus haut. Et le problème sera résolu: le traitement de texte fera le calcul de la résolution et affichera sur l'écran de mon MacBook la feuille A4 avec une largeur mesurant très exactement 21 cm.

Bien. Imaginons que j'ai maintenant l'idée saugrenue de brancher à mon MacBook un écran externe d'une résolution de 100 ppp, et que je place la fenêtre à cheval entre les deux écrans: ça ne va plus du tout ! La page est maintenant trop grosse sur l'écran externe !

Ce problème est insoluble au niveau applicatif. La seule possibilité est que le Window Server fasse les adaptations.

Les réflexions d'Apple sur le sujet

L'indépendance de la résolution était annoncée pour Mac OS 10.5 et ne fut finalement pas présente. Il est possible qu'elle fasse son apparition dans 10.6. Il existe pourtant déjà quelques API:

Resolution Independence Guidelines

Je vous fait un petit résumé:

  • Les ingés d'Apple ont l'air de s'embrouiller avec tout ça.
  • Il faudra dessiner à 72 ppp. Quartz effectuera ensuite les conversions pour avoir les coordonnées en pixels.
  • Il est pour l'instant possible de changer le facteur d'agrandissement à l'aide de l'application Quartz Debug, dans le menu Tools > Show User Interface Resolution. Essayez, c'est marrant.

Ce petit essai devrait vous faire comprendre la complexité de la chose: c'est moche, on voit plein de gros pixels. Il va donc falloir rendre l'interface utilisateur entièrement vectorielle. C'est un énorme travail, et il est donc compréhensible qu'Apple ne l'ait pas encore complètement implémenté.

Il n'est pas toujours simple lorsque l'on commence le développement sous Mac ou sous iPhone de savoir où se trouve la documentation, les exemples de code et comment utiliser tout ça. Le blog Inside iPhone nous propose un article très intéressant sur les différentes ressources disponibles pour le développements iPhone. Cela va des exemples de code aux vidéos en passant par la documentation :

En vrac autour du web

08012009 Dans: En vrac, Liens

Parce qu'il n'y a pas que Cocoa, l'iPhone et le Mac, aujourd'hui, un "En vrac" concernant le web :


Sponsors