Buts: Mettre en place l'environnement dans lequel évolueront les bactéries.
Il s'agit lors de cette étape d'aboutir à un premier programme graphique nous permettant de visualiser des boites de culture et d'y placer des sources de nutriments capables de croître en fonction de la température.
Nous allons donc dans ce qui suit procéder au codage des classes CultureDish et Laboratory.
Les bactéries que nous simulerons seront confinées dans une boite de culture. Les conditions dans cette boite, comme la température ou la quantité de nutriments, impacteront l'évolution des bactéries qui y vivent.
Une classe CultureDish s'impose et voici quelques attributs qu'il est naturel d'y placer:
Build > Run Cmake
dans QtCreator, si l'on souhaite qu'il soit correctement pris en compte lors d la prochaine compilation.
Pour modéliser un ensemble (de bacteries ou de sources de nutriments) vous pourrez utiliser un tableau dynamique et y stockerez des pointeurs sur les objets. Rappelons que le parcours d'un tableau dynamique peut se faire au moyen d'itérations sur ensemble de valeurs :
for (const auto& bacterie : lesBacteries)ou
for (auto& bacterie : lesBacteries)
Les méthodes décrites ci-dessous sont à prévoir pour la classe CultureDish :
//faire évoluer les bactéries ici:ou
// code pour ajouter les nutriments ici :pour vous rappeler de la tâche à coder plus tard
À sa création, une boite de culture aura pour température la valeur retournée par la tournure getAppConfig()["culture dish"]["temperature"]["default"].toDouble() qui vous sera expliquée à l'étape suivante (l'inclusion de Application.hpp est nécessaire).
[Question Q2.1] Pour pouvoir représenter graphiquement la boite de culture et pour pouvoir en délimiter le pourtour, par exemple pour empêcher les bactéries d'en sortir, nous souhaitons voir la boite comme étant un contour circulaire (qui aura une position dans l'environnement en deux dimensions servant de support à nos simulations et bien sûr). Comment utiliser la classe CircularBoundary pour modéliser cela ? Répondez à cette question dans votre fichier REPONSES, puis dotez la classe CultureDish d'un constructeur prenant en paramètre une position (un Vec2d) et un rayon (double).
[Question Q2.2] Quelles méthodes vous semble t-il judicieux de déclarer comme const? Répondez à cette question, en justifiant vos choix, dans votre fichier REPONSES.
[Question Q2.3] On souhaite ne pas permettre la copie d'une CultureDish ni l'affectation. Quelle(s) solution(s) proposeriez-vous pour satisfaire cette contrainte? Réfléchissez et répondez à cette question dans votre fichier REPONSES puis implémentez votre code en conséquence.
[Question Q2.4] La question Q2.3 suggère que chaque simulation s'intéressera à des boites disposant chacune de leur propre ensemble de bactéries et de nutriments. Il n'y a par ailleurs pas beaucoup de sens à faire vivre les bactéries sans les rattacher à une boite dans le contexte de ce projet. Une CultureDish peut donc être considérée comme responsable de la durée de vie des bactéries et des nutriments amenés à être créés dans la simulation. Quelle incidence cela a t-il sur la destruction d'une boite de culture ? La destruction peut-elle se faire en utilisant une méthode existante de la classe CultureDish. Répondez à ces questions dans votre fichier REPONSES puis codez le destructeur de CultureDish.
Maintenant, que notre boite de culture a une rayon et une position, il est possible de revenir à la méthode CultureDish::drawOn pour lui faire faire quelque chose. Complétez le code de cette méthode pour lui faire dessiner le contour de la boite.
auto border = buildAnnulus(position, rayon, couleur, epaissseur); target.draw(border);La fonction buildAnnulus est à disposition dans Utility.[hpp][cpp]
Avant de pouvoir tester ces nouveaux développements, il va être nécessaire de pousser notre conception un peu plus loin, dans le sens suggéré par le préambule.
La classe Laboratory va modéliser le support sur lequel sont posées des boites de culture. On part de l'idée qu'une seule boite de culture sera visible à la fois et que l'on pourra par la suite passer d'une boite à l'autre au moyen de touches de contrôle.
Pour commencer, un Laboratory aura comme caractéristiques principales un ensemble de CultureDish (vector), ainsi que l'indice de la boite courante : celle visible. Il ne doit pas pouvoir être copié.
Pour cette classe particulère, les méthodes principales vous sont dictées de façon assez détaillée et précise. Le but est d'assurer la compatibilité avec le noyau de simulation fourni. Souvenez-vous en effet que c'est par le biais d'un attribut de type Laboratory que se fait le lien entre votre code et le noyau de simulation (Application). Il vous faudra donc prévoir les méthodes suivantes :
[Question Q2.5] Pour le moment, faire évoluer un Laboratory c'est simplement faire évoluer ses boites de culture et le dessiner c'est dessiner la boite d'indice courant car il est inutile de dessiner ce que l'on ne voit pas. Comment proposez-vous de coder le corps des méthodes Lab::drawOn et Lab::update ? Répondez à cette question dans votre fichier REPONSES.
Dotez ensuite votre classe Laboratory d'un constructeur permettant de positionner la boite de culture d'indice courant au centre de la fenêtre graphique associée au Laboratory et avec un diamètre occupant les 95% de la largeur de cette fenêtre. Ce constructeur dotera le Laboratory d'un nombre fixe de boites et l'indice courant pointera sur la première boite (celle d'indice zéro). Le nombre de boites est donné par la tournure getShortConfig().culture_dishes_number (nécessitant l'inclusion de Config.hpp). Cette tournure vous sera expliquée en détail à l'étape suivante et pour le moment il suffit de savoir qu'elle retourne la valeur de la constante définie à la ligne 78 de Config.hpp; c'est à dire 3. Cette valeur peut être changée à votre guise.
Pour tester vos développements, une application graphique est fournie dans src/Tests/GraphicalTests/NutrientTest.[hpp][cpp].
Le fichier CMakeLists.txt fourni permet de lancer la compilation du test par le biais de la cible nutrientTest
Faites le nécessaire pour la touche 'R'. Si vous avez correctement codé les choses jusqu'ici, le lancement de ce test devrait vous permettre de voir se dessiner la boite de culture (anneau blanc) dans la partie de l'application graphique réservée à cet usage :
Si vous ouvrez le fichier Application.cpp, vous pourrez en effet observer que les mécanismes nécessaires sont déjà en place. Par exemple, les méthodes nextDish et previousDish y sont bel et bien appelées par la méthode handleEvent. D'autres paramètres que la boite courante sont aussi contrôlables via l'interface; la température de l'assiette courante par exemple.
Lorsque vous lancez nutrientTest, les éléments qui s'affichent dans le menu en haut à droite sont les paramètres contrôlables et l'on peut passer de l'un à l'autre au moyen de la touche Tab ou de la touche Q. Le paramètre s'affichant en rouge est celui sur lequel on peut agir depuis l'interface graphique. Le bandeau explicatif en bas à droite, indique que les touche 'PgUp' ou X ainsi que 'PgDn' /Y permettent d'augmenter ou diminuer la valeur du paramètre sélectionné (celui en rouge).
Utilisez ces touches pour vous positionner sur le paramètre Dish id. Vérifiez alors que vos méthodes nextDish et previousDish ont été correctement codées. Pour chacune de valeurs possibles d'identifiant, une boite vide doit s'afficher.