Projet : étape 5 (semaine 7 du semestre)

Buts

Nous allons cette semaine donner un aspect un peu plus complet/unifié à notre projet en créant un « système de simulation » regroupant de façon plus générique tous les composants nécessaire pour coder un exercice de Physique.

Préliminaires :

Je vous conseille une dernière fois de vous assurer avoir bien compris les concepts présentés en cours avant de vous lancer directement dans la réalisation de la nouvelle partie du projet, par exemple en faisant au préalable quelques exercices si nécessaire.

Pensez aussi à relire le descriptif afin de bien savoir ce que vous êtes en train de faire.


[2*] Exercice P8 : La classe «Systeme»

P8.1 - Conception générale

Commençons par la vue générale, la conception globale de nos programmes. J'en donne ici une version minimale. La même démarche est expliquée plus en détail dans le tutoriel sur le graphisme, mais dans un cadre un peu différent (celui du graphisme en général), ce qui fait qu'elle y est un peu plus compliquée, mais plus complète. Cela vaut peut-être la peine d'aller y jeter un œil si la version résumée ici n'est pas assez claire.

L'idée de cette conception générale est d'être très modulaire et de systématiquement séparer d'un coté les simulations physiques et de l'autre leur visualisation (sous forme textuelle, graphique, ou d'autres comme, par exemple, l'écriture dans un fichier, non abordée dans ce projet). On distingue pour cela (au moins) trois choses : le programme principal (le main()), le système à simuler (classe Systeme décrite ci-dessous) et la façon de l'afficher (classes Dessinable et SupportADessin, décrites ici).

Par ailleurs, nous souhaiterions que les objets simulés dans notre système soient de différente nature. On peut imaginer des points matériels, des charges électriques, des solides non déformables (hors projet), des «solides» déformables (encore plus hors projet), etc.

Le but de ce projet étant avant tout de vous faire concrètement travailler les différents aspects de la POO, je vous demande d'imaginer que la classe PointMateriel (ou, encore plus, la classe ObjetMobile) aurait différentes sous-classes, même si vous n'allez peut être pas en implémenter beaucoup.
Plusieurs de ces objets de vos simulations seront «digne d'intérêt» dans ce sens que c'est ce que nous souhaitons observer. Cela nous conduit à l'abstraction suivante décrite ci-dessous: les «objets dessinables» (ou «observables»)
. Pour peut être clarifier mon propos: le but des ObjetMobile est d'être intégrable, mais peut être est-ce une abstraction de trop haut niveau pour que tout ObjetMobile soit intéressant à suivre, à « regarder ». Par contre, il me semble clair que tout PointMateriel dans un exercice de Physique serait intéressant à suivre. C'est cette notion de « je veux voir ce qui se passe avec cet objet » que nous représentons sous l'abstraction Dessinable décrite maintenant.

P8.2 - Objets dessinables

On souhaite pouvoir « interroger l'état » de différents objets, soit en mode texte comme cette semaine, soit de façon graphique comme abordé dans deux semaines, les différents objets qui seront présents dans nos simulations (typiquement les PointMateriel dans le cadre de ce projet-ci). On veut le faire de façon unifiée au moyen d'une méthode dessine_sur(SupportADessin&), laquelle écrira simplement du texte dans la version « mode texte » et dessinera effectivement quelque chose lorsque vous ajouterez du graphisme. Bien sûr, chaque dessin est spécifique à l'objet dessiné !

[Question P8.1] En termes de POO, quelle est donc la nature de la méthode dessine_sur() ?

Répondez à cette question dans votre fichier REPONSES.

Concrètement, je vous demande donc de créer une classe Dessinable contenant une méthode dessine_sur(SupportADessin&).

Pour bien séparer les différents moyens de visualisation, nous introduisons également une classe (abstraite) SupportADessin, qui représentera de façon générique le moyen choisi pour dessiner (écran mode texte, mode graphique avec telle bibliothèque (p.ex. Qt), ou telle autre, ou dans un fichier (non abordé dans ce projet), etc.). Ces moyens possibles de dessiner seront représentés par des sous-classes (à faire plus tard), p.ex. TextViewer pour la « visualisation » en mode texte, VueOpenGL pour la visualisation avec du graphisme en 3D utilisant OpenGL, ou encore FileWritter (non abordé dans ce projet) pour écrire les résultats dans un fichier, etc..

Pour pouvoir être correctement « dessinées », de façon appropriée à chaque SupportADessin, toutes les classes « dessinables » devront posséder la même méthode dessine_sur() , exactement rigoureusement la même (« mot pour mot » ; cette méthode doit être :

  virtual void dessine_sur(SupportADessin& support) override
  { support.dessine(*this); }

ATTENTION ICI ! Pour des raisons techniques dépassant le cadre de ce cours, il ne faut pas que cette méthode soit définie dans la classe Dessinable puis héritée, mais bien que ce même bout de code soit recopié à l'identique (copié-collé, une fois n'est pas coutume !) dans chaque sous-classe de Dessinable (masquage).
[ C'est le prix à payer du fait qu'en C++ il n'y a pas de ce qu'on appelle « double dispatch ». ]

La classe SupportADessin est une classe abstraite qui ne doit contenir que (les méthodes usuelles et) les méthodes virtuelles de dessin pour tous les objets que l'on voudra dessiner. Par exemple (à adapter à votre propre projet et au fur et à mesure de son avancement) :

class SupportADessin
{
 public:
  virtual ~SupportADessin() = default;
  // on suppose ici que les supports ne seront ni copiés ni déplacés

  virtual void dessine(PointMateriel const&) = 0;
  virtual void dessine(Systeme const&) = 0;
  virtual void dessine(Solide const&) = 0; // exemple, non abordé dans ce projet
  // ... autres choses que vous voudriez « dessiner »...
};

Faites déjà tout ceci, puis répercutez sur les classes PointMateriel ou autres, les modifications que vous jugez nécessaires.

P8.3 - Support à dessin textuel

Créez une classe TextViewer qui est un SupportADessin dédié à la « visualisation » en mode texte dans un iostream qu'il aura comme attribut (par référence, bien sûr ! -- on ne peut pas faire de copie d'iostream).

Les méthodes dessine() de cette classe se contentent simplement d'appeler l'opérateur << de leur argument.

Pour plus de détails, voir si nécessaire cette partie du tutoriel graphique.

P8.4 - Le « système »

Avant de commencer, je voudrais attirer plus spécialement votre attention sur un point évoqué en cours :

[Question P8.1] A quoi faut-il faire attention pour les classes contenant des pointeurs ? Quelle(s) solution(s) est/sont envisageable(s) ?

Répondez à cette question dans votre fichier REPONSES.

La classe Systeme à laquelle on s'intéresse ici a pour but de représenter tout ce qui forme le système physique simulé, c'est-à-dire une collection d'objets, de contraintes, de champs de forces et un intégrateur (rien que ça ! ;-)). Un Systeme aura aussi la « maîtrise du temps » (c'est lui qui connaît et décide du temps).

Comme discuté précédemment dans la conception générale : on veillera à clairement dissocier ce qui relève de la simulation du système physique (et qui devra être rattaché à la classe Systeme) de tout ce qui relève de sa représentation graphique, sa « visualisation » au sens large.
En plus clair : il devra être possible, en utilisant la classe Systeme, de faire tourner une simulation sans aucune interface graphique (simulation en mode texte).

De plus, on devra pouvoir visualiser/« dessiner » un Systeme. Son « dessin » consistera simplement à dessiner tous les composants qu'il contient.

[Question P8.2] Comment représentez vous la classe Systeme ?
Expliquez votre conception (attributs, interface, ...).

Répondez à cette question dans votre fichier REPONSES.

Cette classe devra au moins avoir comme méthodes (mais vous pouvez bien sûr en ajouter d'autres) :

  1. un constructeur par défaut initialisant le système à vide ;
  2. toutes les combinaisons de constructeurs que vous souhaitez pour initialiser un systèmes avec autant paramètres que vous souhaitez (collection d'objets, collection de contraintes, etc.) ;
  3. une méthode pour ajouter un objet au système ; c'est à vous de choisir le modèle de « propriété » (qui « possède » les objets du Systeme ; cette remarque s'applique à toutes les collections et tous les attributs du Systeme;
    Note : celles et ceux qui maîtrisent le déplacement ou même la construction sur place (« emplace ») peuvent bien sûr faire de tels construction ; MAIS je déconseille à quiconque de se lancer dans des concepts qu'il/elle ne maîtrise pas !
  4. une méthode pour ajouter une contrainte au système ;
  5. une méthode pour ajouter un champs de forces au système ;
  6. optionnel (si ça fait sens pour vous) : une méthode pour changer l'intégrateur ; (et sinon il faudra alors que celui-ci soit fourni lors de n'importe quelle construction ;
  7. une méthode pour ajouter la contrainte i à l'objet j du système ;
    il est donc clair que les « objet du système » dont je parle ici ont nécessairement au moins une contrainte et au moins un champ de forces ;
  8. une méthode pour ajouter un champs de force i à l'objet j du système ;
  9. le moyen d'être affiché par l'opérateur <<, indiquant toutes les informations relatives au système (exemple ci-dessous) ;

Exemple d'affichage :

Systeme : à t = 0 :
Objet no 1 : Point Matériel :
0 0 0 # parametre
0 0 0 # vitesse 
0 0 0 # position physique
0 0 0 # vitesse  physique
5.972e+24 # masse
contrainte : contrainte Libre

Objet no 2 : P:
6.37101e+06 0 0 # parametre
0 0 0 # vitesse 
6.37101e+06 0 0 # position physique
0 0 0 # vitesse physique
0.1  # masse
contrainte : contrainte Libre

Champ no 1 : champ newtonien, centre : 0 0 0, masse : 5.972e+24 
Champ no 2 : champ newtonien, centre : 6.37101e+06 0 0, masse : 0.1

Contrainte no 1 : contrainte Libre

Créez un fichier testSystem.cc pour y tester votre nouvelle classe en reproduisant la sortie ci-dessus.

On ne s'est pour l'instant intéressé qu'à la conception générale du système, pas à son évolution. Ceci est l'objet du prochain exercice.


[2*] Exercice P9 : Premières simulations (en mode texte)

P9.1 - Le retour de la pomme

On veut ici créer notre première simulation d'un système complet (et peut être quelques autres). Pour cela, on va commencer par reproduire le résultat de la chute d'une pomme, mais dans un Systeme.

Pour cela, implémentez dans une méthode evolue(double dt) de la classe Systeme, une boucle sur tous les objets (pouvant évoluer) qu'il contient. Cette boucle fait avancer (grâce au même intégrateur, composant interne du système) chacun de ces objets du pas de temps dt fourni.

Dans un fichier exerciceP9.cc, créez puis faîtes évoluer un système ayant les mêmes caractéristiques que celles de l'exemple de la chute d'une pomme de la semaine passée, et vérifiez que vous obtenez les mêmes résultats

Note : la méthode dessine_sur() d'un objet en mode texte (sur un TextViewer, donc) peut très bien être différente de son affichage (avec <<). On peut par exemple vouloir que l'affichage (avec <<) soit plus complet, avec plus d'informations, alors que la méthode dessine_sur() serait plus simple, n'affichant que le strict nécessaire (si cela vous aide pour dessiner avec gnuplot, Excel ou tout autre logiciel de dessin externe).
Vous êtes libres de faire ces affichages comme bon vous semble (même si cela (le résultat de dessine_sur()) n'est plus très lisible par un humain).
Après, vous pouvez aussi faire plusieurs SupportADessin textuels différents suivant vos besoin (p.ex. GnuplotViewer, DebugViewer, PositionOnlyViewer qui sont des TextViewer).

P9.2 - Autres exercices (de Physique)

Si vous avez le temps, vous pouvez maintenant créer d'autres exercices de Physique, par exemple (références à vérifier SVP -- pas sûr de mes sources ;-)) :

(Note: on a sélectionné ici que des exercices avec champ gravitationnel constant ou champ newtonien; nous aborderons des exercices plus compliqués dans le sujet P11, en semaine 10.)

Pour chaque nouvel exercice, développez le dans un fichier C++ séparé, de nom exerciceP9-SUFFIXE.cc où le SUFFIXE est assez clair, et indiquez dans votre fichier README plus précisément de quel exercice de Physique il s'agit (et en deux mots sur quoi porte cet exercice; comme fait ci-dessus). Vous pouvez, bien sûr, choisir d'autres exercices de Physique qui vous semblent pertinents.


Dernière mise à jour le 7 février 2025
Last modified: Fri Feb 7, 2025