Développement Mac et iPhone
Après la génération de notre premier image dans l'article précédent, nous allons remanier notre programme pour le rendre plus propre.
Le remaniement (en anglais: Refactoring) est une opération qu'il est bon de faire continuellement. Il s'agit :
Le but est de faciliter les modifications à venir, en gardant le code le plus propre possible tout au long de la vie du logiciel. Notez bien que nous n'ajoutons pas de fonctionnalités.
Les fonctions mathématiques peuvent être réutilisées à divers endroits de notre programme, et pas seulement pour la calcul de l'image fractale, nous allons donc les séparer:
CFRComplexe.c
(menu File > New File > C and C++ > C File).Carre()
dans CFRComplexe.h
.Carre()
dans CFRComplexe.c
.Pendant que nous y sommes, nous créons la fonction ModuleAuCarre()
:
double ModuleAuCarre(Complexe_t z)
{
return z.reel*z.reel + z.imag*z.imag;
}
N'oubliez pas de rajouter son prototype dans le .h.
Les calculs appartenant à la couche Modèle, nous allons créer un objet CFRMandelbrotRender qui ne fait que générer la bitmap:
@interface CFRMandelbrotRender : NSObject {
}
- (NSBitmapImageRep*) bitmapImageRep;
@end
Déplaçons dans CFRMandelbrot.m tout le code qui fait le calcul de la bitmap:
- (NSBitmapImageRep*) bitmapImageRep
{
// Créer la bitmap
NSBitmapImageRep* bitmapRep =
[[NSBitmapImageRep alloc]
initWithBitmapDataPlanes:NULL
pixelsWide:400
pixelsHigh:300
bitsPerSample:8
samplesPerPixel:1
hasAlpha:NO
isPlanar:NO
colorSpaceName:NSDeviceWhiteColorSpace
bytesPerRow:0
bitsPerPixel:8];
// Calculer l'ensemble de Mandelbrot:
// Parcourir tous les points de la bitmap
double x, y;
for(x = 0; x < 400; x++)
{
for(y = 0; y < 300; y++)
{
// Convertir les coordonnées
Complexe_t c;
c.reel = x/100.0 - 2;
c.imag = -y/100.0 + 1.5;
// Initialiser z[0]
Complexe_t z = {0.0, 0.0};
NSUInteger n;
for(n=0; n < MAX_ITERATIONS; n++)
{
// z[n+1] = z[n+1]^2 + c
Complexe_t zCarre = Carre(z);
z.reel = zCarre.reel + c.reel;
z.imag = zCarre.imag + c.imag;
// La suite diverge si |z| > 2
if(ModuleAuCarre(z) > 4.0)
break;
}
// Donner le niveau de gris au pixel
NSUInteger nuance = n * 255 / MAX_ITERATIONS;
[bitmapRep setPixel:&nuance atX:x y:y];
}
}
[bitmapRep autorelease];
return bitmapRep;
}
Les modifications sont les suivantes:
La vue pourrait maintenant servir à afficher autre chose que l'ensemble de Mandelbrot, par exemple celui de Julia. Ceci nous pousse à la renommer. Nous allons utiliser l'outil de Refactoring de XCode pour cela:
@implementation CFRMandelbrotView
, sélectionnez le texte CFRMandelbrotView
Edit > Refactor…
Voilà un outil bien pratique, d'autant plus qu'il renomme la classe y-compris dans le fichier XIB !
Mettre à part le code qui fait le rendu nous impose maintenant de créer un lien pour récupérer la bitmap. Ajoutons une outlet à CFRFractalView:
#import "CFRMandelbrotRender.h"
@interface CFRFractalView : NSView {
IBOutlet CFRMandelbrotRender* render;
}
@end
Basculez sous Interface Builder. Instanciez un exemplaire de CFRMandelbrotRender, et reliez l'outlet render
de la vue à cet objet.
Retournons sous XCode, dans CFRFractalView.m. Ajoutons à la méthode drawRect: le nécessaire pour obtenir la bitmap et l'afficher:
- (void)drawRect:(NSRect)rect
{
if(render) // L'outlet est fixée
{
// Afficher la bitmap
NSBitmapImageRep* bitmapRep = [render bitmapImageRep];
[bitmapRep drawAtPoint:NSMakePoint(0,0)];
}
else // L'outlet "render" n'est pas fixée
{
[[NSColor blueColor] set];
NSRectFill(rect);
}
}
J'ai ici gérer le cas où l'on aurait oublier de relier l'outlet render
. La vue serait alors emplie de bleu.
Nous pouvons à présent lancer le programme: le résultat est très exactement le même. Mission accomplie !
Nous disposons dorénavant d'une bonne base pour poursuivre le développement. À bientôt pour la suite.
Le projet XCode complet à télécharger.
Renaud Pradenc
Céroce.com