WOW !! MUCH LOVE ! SO WORLD PEACE !
Fond bitcoin pour l'amélioration du site: 1memzGeKS7CB3ECNkzSn2qHwxU6NZoJ8o
  Dogecoin (tips/pourboires): DCLoo9Dd4qECqpMLurdgGnaoqbftj16Nvp


Home | Publier un mémoire | Une page au hasard

 > 

Badora


par Stéphane Clerc
UPMF - Grenoble - IUT II 2003
  

Disponible en mode multipage

Bitcoin is a swarm of cyber hornets serving the goddess of wisdom, feeding on the fire of truth, exponentially growing ever smarter, faster, and stronger behind a wall of encrypted energy

Copyright (c) Stphane Clerc

Permission is granted to copy, distribute and/or modify this document under the terms of the GNU Free Documentation License, Version 1.2 or any later version published by the Free Software Foundation;

with no Invariant Sections, no Front-Cover Texts, and no Back-Cover Texts. A copy of the license is included in the section entitled "GNU

Free Documentation License".

DEPARTEMENT INFORMATIQUE - IUT 2 GRENOBLE

Année universitaire 2002-2003 MEMOIRE DE STAGE

ACTUALISATION DES BASES DE DONNEES BADORA, PORTAGE
DES APPLICATIONS ASSOCIEES ET REALISATION D'UN
PROGRAMME DE VISUALISATION D'IMAGES RADAR

Laboratoire LTHE

(Stage du 7 Avril 2003 au 16 Juin 2003)

Présenté par
Stéphane CLERC
Jury

IUT : M. CHEVAL
IUT : Mme CARAVEL
Société : M. CAZENAVE

Remerciements

Je tiens tout d'abord à remercier M. Frédéric CAZENAVE, mon tuteur au laboratoire, qui m'a permis de réaliser ce stage au sein de l'équipe du LTHE. Il m'a suivi tout au long de ce projet et m'a beaucoup aidé dans ma tâche par ses conseils techniques et ses compétences en Hydrologie qui m'ont permis de mieux comprendre le cadre dans lequel se situait mon stage.

Je remercie également tous les autres stagiaires et les autres personnes du LTHE pour leur accueil et leurs conseils ainsi que mes camarades de l'IUT m'ayant fournis de précieux conseils techniques.

Enfin je voudrais remercier M. Jean-Louis CHEVAL, mon tuteur de l'IUT qui m'a suivi lors de ce stage, ainsi que l'IUT 2 de Grenoble pour l'enseignement qu'il m'a apporté.

Sommaire

Introduction . 4

I. Analyse de l'existant.. 6

1) Présentation . 6

1.1) Le projet EPSAT-Niger .. 6

1.2) La base de données Radar (BADORA) .. 6

2) Analyse des besoins 8

2.1) Attentes des utilisateurs .. 8

2.2) Point sur les programmes existants 8

3) Cahier des charges 8

3.1) Compilation et reprise des programmes existants .. 8

3.2) Mise en ligne du site de consultation de la base de données 9

3.3) Réalisation d'un programme de visualisation des données 9

4) Environnement 9

4.1) Matériel et outils à maîtriser .. 9

4.2) Langages de programmation 10

4.3) Contraintes 10

II. Conception et réalisations 11

1) Refonte et portage des programmes existants 11

1.1) Présentation des différents programmes 11

1.2) Compilation et problèmes 12

1.3) Modifications apportées 13

2) Site Internet 13

2.1) Conception et architecture du site 13

2.2) Réalisation et mise en ligne 15

3) Programme de visualisation . 15

3.1) Choix du langage et conception 15

3.2) Transfert et organisation de la nouvelle base de données 17

3.3) Interface graphique : architecture, fonctionnalités 22

3.4) Codage des images et animations radar 25

III. Résultats .. 28

1) Tests et résultats 28

2) Problèmes rencontrés 29

2.1) Compréhension du système C-ISAM de gestion de BD 29

2.2) Organisation d'une BD de taille importante 29

2.3) Réalisation des images radar 29

3) Améliorations possibles 30

Conclusion .. 31

Glossaire . 33

Bibliographie - Webographie . 34

Annexes . 35

1) Description des classes Java . 36

2) Listings des classes principales 36

3) Listing de la classe Evénement . 47

4) Extrait de la classe Jimage 49

Introduction

Mon stage s'est déroulé au sein du laboratoire LTHE (Laboratoire d'étude des Transferts en Hydrologie et Environnement) de l'ENSHMG (Ecole Nationale Supérieure d'Hydraulique et de Mécanique de Grenoble) qui fait partie de l'INPG. Ce laboratoire effectue des études dans plusieurs domaines de l'Hydrologie, ainsi trois équipes de recherche travaillent dans les domaines suivants :

- l'Hydraulique et l'Hydrologie de Bassin : étude de la phase continentale du cycle de l'eau et des flux à l'échelle régionale (rivières, nappes,...).

- les Poreux et Processus Hydrologiques : étude des couplages entre processus hydrologiques de surface et de sub-surface.

- l'Hydrométéorologie : étude des précipitations.

En particulier plusieurs études ont été menées en Afrique de l'Ouest par l'équipe Hydrométéorologie sur le régime pluviométrique, comme celle qui concerne le projet sur lequel j'ai travaillé. Le projet AMMA-CATCH (Analyses Multidisciplinaires de la Mousson Africaine - Couplage de l'Atmosphère Tropicale et du Cycle Hydrologique) initié par l'IRD (Institut Français de Recherche pour le Développement) et sous tutelle du LTHE mène des études sur les précipitations au Bénin et au Niger et est dans la continuité du projet EPSATNIGER qui concerne mon stage.

Le service dans lequel je travaillais est la salle informatique du laboratoire où sont à disposition une vingtaine d'ordinateurs (PC Windows et Linux). Mon tuteur de stage M. Frédéric CAZENAVE de l'équipe Hydrométéorologie est ingénieur radariste au LTHE et a notamment travaillé sur le projet EPSAT-NIGER qui concerne le sujet du stage, il fait également parti du projet CATCH.

Le projet EPSAT-NIGER a permis de rassembler des données radar acquises au Niger sur les précipitations et a conduit à la création d'une banque de données BADORA (BAnque de DOnnées RAdar). Cette banque de données regroupe donc quatre années de données et certains programmes, réalisés il y a déjà quelques années, permettent de l'exploiter. Ces programmes ont été réalisés sous l'environnement UNIX et offrent la possibilité de visualiser des images radar à partir de la banque de données.

Le problème est que ces programmes développées sous SUN OS sont maintenant assez anciens et ne sont pas portables sous d'autres systèmes qu'UNIX. L'intérêt de ce stage est donc d'assurer la persistance de cette base de données et de la diffuser à plus grande échelle. Pour cela on peut diviser le travail à réaliser en trois parties successives.

Tout d'abord pour récupérer la banque de données BADORA, il faut actualiser et porter les programmes déjà existants sous un système plus récent tel que Linux. Ainsi cela permettrait d'assurer la sauvegarde de ces données et rendrait l'utilisation des programmes d'exploitation de la base plus accessible.

Mais se limiter à diffuser ces données ainsi avec des programmes fonctionnant sous Linux, restreindrait le nombre d'utilisateurs possible. C'est pourquoi une mise en ligne des données a été envisagée pour rendre la consultation de la base plus accessible. La deuxième

partie du travail est donc de mettre en ligne un site Internet proposant de consulter la base et de visualiser les images radar. En plus des images, des animations radar pourraient être réalisées et visionnées sur le site. Ainsi la diffusion des données serait assurée puisque Internet est un médium de plus en plus utilisé et de nombreuses personnes pourraient donc avoir accès aux observations faites durant l'expérience EPSAT-NIGER.

Enfin, la troisième partie du stage est d'étendre encore plus cette diffusion en réalisant un nouveau programme de visualisation des images et des animations radar de BADORA qui serait portable sur toute machine. Puisque tout le monde n'a tout de même pas accès à Internet, ce programme serait diffusé sur un CD-Rom et permettrait alors d'être utilisé partout.

Ce stage a donc pour but d'aider à la pérennisation et à la diffusion de la banque de données BADORA et cela pour permettre la consultation d'archives et d'effectuer des comparaisons sur les précipitations en Afrique de l'Ouest.

I] Analyse de l'existant

Le travail qui est à réaliser pour ce stage s'inscrit dans le cadre du projet EPSATNIGER et concerne des programmes de traitement et de visualisation d'images radar.

1) Présentation :

1.1) Le projet EPSA T-Niger :

L'expérience EPSAT-Niger (Estimation des Précipitations par Satellite - expérience Niger) a été menée de 1990 à 1993 par le groupe PRAO (Précipitations Afrique de l'Ouest de l'IRD (Institut de Recherche pour le Développement). Cette expérience avait pour but d'étudier les systèmes précipitants de l'Afrique soudano-sahélienne et pour cela elle disposait d'un réseau d'une centaine de pluviomètres et d'un radar météorologique (1) situé à Niamey au Niger. Les données enregistrées par ce radar ont été acquises grâce au système SANAGA (Système d'Acquisition Numérique pour l'Analyse des Grains Africains) qui numérise les informations venant du radar.

1.2) La base de données radar (BADORA) :

A partir des données acquises par le système SANAGA, il fallait pouvoir extraire ces données et les gérer. C'est pourquoi la banque de données BADORA (BAnque de DOnnées RAdar) a été mise en place ainsi que plusieurs programmes permettant de l'exploiter et par exemple de visionner des images radar. Les données que l'on peut consulter dans cette base sont les relevés des précipitations durant la période d'observation, ces données étant regroupées par événement pluvieux (1) . Le logiciel BADORA constitue donc des images à partir des radiales (1) données par SANAGA et les regroupe en événements.

Pour chaque événement on peut obtenir l'ensemble des images radar (1) dont les données ont été obtenues. Une image radar est issue d'un regroupement de données acquises par le radar (1) et les différents pluviomètres, elle représente un tour complet du radar et donne la situation météorologique à un moment donné. Le radar se situe au centre de l'image et les cercles concentriques sont distants de 50 Km chacun. L'échelle des couleurs qui est sur 16 niveaux symbolise le degré de réflectivité (1) des précipitations (exprimé en DBz (1)).

Sur le schéma (Figure 1) on peut voir comment sont construites ces images à partir des données acquises par le radar et les différents pluviomètres :

(1) Cf. définition dans le Glossaire page 33

Figure 1 : Schéma d'une image radar

Le radar se trouve au centre (le rond jaune) et a une portée de 350 km au maximum . Le cercle d'observation qu'il représente est découpé en radiales (en rouge) de 1,6° et chaque radiale est divisée en 512 portes (en vert). Les données que nous possédons dans la base sont la réflectivité (1) pour chacune de ces portes.

1

1..*

Année

Image

date angleCouvert site

résolution ppiRhi

1..*

1

1

Evénement

Saison

1 512

Radiale

Porte

azimut site

réflectivité

1..225

dateDébut dateFin

Figure 2 : Schéma relationnel de la banque de données

Le schéma relationnel (Figure 2) donne une idée sur l'organisation des données, ainsi pour une saison (année) on a un ensemble d'événements pluvieux qui eux-mêmes regroupent plusieurs images. Ces images sont constituées au maximum de 225 radiales (225 = 360° (tour complet) divisé par 1.6° (angle pour 1 radiale)) qui chacune compte 512 portes.

(1) Cf. définition dans le Glossaire page 33

2) Analyse des besoins :

2.1) Attentes des utilisateurs :

BADORA est une base de données regroupant les données acquises de 1990 à 1993 au Niger. Il n'est cependant pas possible de consulter les données brutes si l'on veut étudier les précipitations et pouvoir faire des comparaisons. C'est pourquoi il fallait réaliser plusieurs programmes permettant d'extraire les données et de créer des images radar, ainsi que des animations radar à partir de ces images pour retracer un événement pluvieux par exemple.

2.2) Point sur les programmes existants :

Des programmes avaient déjà été réalisés il y a quelques années qui permettaient d'exploiter la base de données et de visualiser les images sous le système d'exploitation UNIX. Ces programmes ne sont cependant pas portables car ils ont été développés d'une part en utilisant le gestionnaire de base de données C-ISAM d'Informix, il faut donc pour les utiliser posséder cette librairie. D'autre part, la librairie graphique qui a servi pour les programmes de visualisation est la librairie X11 qui ne fonctionne que sous un environnement UNIX. L'intérêt du stage est donc de rendre ces données accessibles à tous et avec des moyens de diffusion plus actuels pour assurer la conservation de ces données. Pour réaliser ceci, le travail a été divisé en trois distinctes dont les objectifs sont décrits dans le cahier des charges suivant.

3) Cahier des charges :

3.1) Compilation et reprise des programmes existants :

Tous les programmes déjà existants ont été développés sur des machines fonctionnant sous Unix avec la librairie graphique X11 et la librairie C-ISAM permettant de gérer la base de données. Ils ont été pendant longtemps non utilisés et le but de ce stage est tout d'abord de les recompiler pour les porter sous un système tel que Linux et si besoin est de mettre à jour les fonctions des librairies.

Les tâches pour cette partie du stage sont donc de :

- recompiler les anciens programmes - corriger les erreurs à la compilation

- comprendre leur fonctionnement et vérifier qu'ils marchent correctement

- mettre à jour les fonctions des librairies

3.2) Mise en ligne du site web de consultation de la base de données :

Pour offrir la possibilité à tout le monde de consulter la base de données BADORA et les images radar, il fallait également mettre en ligne un site Internet. Un programme CGI (1) avait déjà été créé pour répondre à cette attente, mais il n'était pas tout à fait terminé et l'interface du site devait être mise à jour. Ce site doit permettre de consulter pour chaque année l'ensemble des événements pluvieux qui ont été enregistrés et pour chacun de ces événements, de visualiser les images radar ainsi que les animations de ces images.

Donc pour que le site soit prêt à être mis en ligne il faut :

- corriger les liens et les rendre relatifs pour une meilleure portabilité du site - terminer le programme CGI et le faire fonctionner

- refaire la mise en page et mettre à jour les informations du site - corriger les animations radar

3.3) Réalisation d'un programme de visualisation des données :

De plus, pour permettre l'exploitation de cette base de données, il m'est demandé de réaliser un programme portable qui sera mis sur un CD-ROM et offrira alors la possibilité de consulter la base de données de n'importe où et sans avoir besoin de connexion à Internet.

En particulier, ce logiciel devra proposer la visualisation des images et des animations radar et sera distribué en Afrique aux personnes travaillant sur des études concernant les précipitations, en correspondance avec l'expérience EPSAT-Niger.

Les fonctionnalités demandées pour ce programme sont à peu près les mêmes que pour le site Internet à savoir :

- la possibilité de lister tous les événements pour une saison et pour chaque événement de lister toutes les images radar

- la visualisation des images radar

- la visualisation des animations radar pour un événement donné

4) Environnement :

4.1) Matériel et outils à maîtriser :

Le travail devait être effectué tout d'abord sous l'environnement Linux pour la 1ère partie du stage, puisque les programmes à reprendre avaient été développés avec la librairie graphique X11 qui ne fonctionne que sous un environnement UNIX. Pour gérer la base de données, le gestionnaire de base de données qui avait été choisi est C-ISAM (gestionnaire par des fichiers indexés que l'on peut utiliser dans un programme en C). Il a donc fallu se familiariser avec un nouvel environnement qui est Linux et avec la librairie C-ISAM.

(1) Un programme CGI s'exécute sur un serveur, effectue des traitements de données et génère des pages HTML.

Au niveau de la deuxième partie du travail qui est de mettre en ligne les données, il est nécessaire de comprendre le mode de fonctionnement d'un programme CGI, mais sinon il n'y a pas de nouveau langage ou de nouveau logiciel à découvrir.

Enfin pour la dernière partie, il aurait pu être possible d'utiliser un logiciel comme SunOne Studio pour construire l'interface graphique en Java sans avoir à taper tout le code. Cependant si l'on veut mieux comprendre comment les interfaces graphiques sont programmées et pour pouvoir faire vraiment ce que l'on veut, il est préférable de coder soimême le programme. Cela peut être plus long mais offre plus de libertés d'action et le programme qu'il y a à réaliser n'est pas très complexe au niveau de l'interface puisqu'il doit être très simple d'utilisation et accessible à tous.

4.2) Langages de programmation :

Les langages de programmation utilisés étaient variés, puisque premièrement les anciens programmes à reprendre étaient développés en C. Ensuite, il a fallu employer le HTML pour les pages du site Internet et également le langage C pour le programme CGI. Pour le dernier programme, le langage utilisé était le Java pour assurer une meilleure portabilité et pour pouvoir facilement programmer une interface graphique.

4.3) Contraintes :

Les contraintes pour ce projet étaient tout d'abord de maîtriser les nouveaux outils tels que l'environnement Linux et la librairie C-ISAM, mais aussi les nombreuses librairies de Java. Etant donné que ces outils sont au départ inconnus pour moi, la difficulté principale est d'arriver à gérer son temps. Avant de commencer pleinement le travail à réaliser pour ce stage, il faut d'abord apprendre à utiliser tous ces outils. La principale contrainte et risque est finalement le temps qu'il faut gérer quand on ne connaît pas à l'avance le temps qu'il faudra pour maîtriser le sujet, les outils nécessaires à sa réalisation et les problèmes qu'il faudra surmonter.

II] Conception et réalisations

La conception a été divisée selon les trois parties du projet à effectuer qui sont la mise à jour des programmes existants, la mise en ligne d'un site Internet de consultation de BADORA et la réalisation d'un programme de visualisation.

1) Refonte et portage des programmes existants :

La première tâche a été de reprendre tous les programmes d'exploitation de la banque de données pour les porter sous Linux et mettre à jour les librairies.

1.1) Présentation des différents programmes :

Certains programmes ont déjà été réalisés il y a quelques années lors de précédents stages, voici une rapide présentation de ces programmes déjà existants :

· bdrinst.exe :

Ce programme permet d'installer la banque de données et de créer les répertoires dont l'utilisateur aura besoin pour l'exploiter.

· bdrbatch.exe :

Il sert à lire des fichiers de type SANAGA (*.im) qui regroupent les données acquises par le radar.

Commande en ligne : ./bdrbatch. exe <repSanaga> <fichSanaga. im>

· bdrmenu.exe :

C'est l'application Badora avec un système de menus permettant d'accéder au paramétrage de l'application, à la mise à jour de la banque de données, à l'archivage et à l'édition des données.

· sanbdr.exe : Ce programme permet de créer des fichiers de type SANAGA à partir de la base de données.

Commande en ligne : ./sanbdr. exe <fichSanaga. im> <dateMin> <dateMax>

· bdrmini.exe :

C'est une version limitée de bdrmenu.exe, on ne peut accéder seulement qu'aux menus de consultation et d'impression des données.

· bdrim.exe :

Il permet la visualisation de tout le catalogue-images pour une saison, c'est-à-dire la liste de toutes les images acquises pour une année donnée.

Commande en ligne : ./bdrim.exe <repSaison199x>

· bdrsg.exe :

De même que bdrim.exe, il donne la liste de tous les segments (radiales) pour une saison donnée.

· visuim.exe : Ce programme permet d'afficher une image dans une fenêtre sous UNIX avec la libraire X11.

Commande en ligne : ./visuim <dateImage>

· visuev.exe :

Fonctionnant sur le même modèle que visuim.exe, ce programme affiche l'ensemble des images composant un événement pluvieux.

Commande en ligne : ./visuev.exe <dateDeb> <site> <résolution> <pas>

· visuimd2.exe :

Même fonction que visuim.exe mais affiche seulement le degré carré (1) d'une image.

· visuevd2.exe :

Visualisation des images d'un événement dans le degré carré.

1.2) Compilation et problèmes rencontrés :

Le passage des programmes qui ont été développés sous UNIX à l'environnement Linux a été plutôt simple puisque Linux est basé sur UNIX, il n'y a donc pas eu de problème de changement d'environnement. Par ailleurs, les fonctions utilisées pour les librairies X11 et C-ISAM n'avaient pas évoluées depuis le développement de ces programmes, il n'y a donc pas eu besoin non plus de mettre à jour les fonctions appelées. Les problèmes rencontrés lors de la compilation ont alors surtout été du fait de la prise en main de ces librairies et de l'environnement Linux.

(1) Cf. définition dans le Glossaire page 33

1.3) Modifications apportées :

Peu de changements ont finalement été effectués sur ces programmes, à part quelques corrections, mises à jour des variables d'environnement et des fichiers de compilation (Makefile) pour pouvoir les faire fonctionner.

Pratiquement tous ces programmes s'exécutent donc correctement, sauf par exemple bdrbatch.exe mais il n'était pas nécessaire de le corriger puisque ce programme a servi à lire des fichiers SANAGA et ne devrait plus servir puisque toutes les données ont été récupérées et stockées.

D'autres problèmes sont survenus pour les programmes de visualisation des images car toutes les fonctionnalités proposées par les menus n'étaient pas effectives. Cependant étant donné que la dernière partie du stage était de réaliser un programme plus portable permettant de visualiser ces images, il était plus judicieux de privilégier le temps du stage pour développer ce nouveau programme plutôt que de corriger les anciens, étant donné que ce dernier remplira les mêmes fonctions mais sera d'une diffusion plus grande.

Dans le prolongement de ce travail, la deuxième partie du stage concerne la mise en ligne d'un site Internet permettant à tous de consulter les données de BADORA.

2) Site Internet :

2.1) Conception et architecture du site :

L'architecture du site est très simple mais fonctionnelle. Le site se décompose comme suivant (Figure 3) :

Accueil

Saison 1993

Evénement s

Images

Saison 1992

Evénements

Images

Evénements

Saison 1990

Images

Saison 1991

Evénements

Images

Figure 3 : Structure globale du site Internet

La page d'accueil propose de choisir l'année pour laquelle on souhaite consulter la base de données, puis pour chaque saison le découpage est identique. Après avoir sélectionné une année, une page donne tous les événements de cette année sous forme d'une liste de liens qui conduise chacun à une page listant toutes les images pouvant être visualisées.

La page qui permet de visualiser une image (Figure 4) comporte plusieurs boutons permettant de naviguer parmi les images d'un événement et de passer d'un événement à un autre, mais aussi de visionner l'animation des images pour un événement.

Figure 4 : Interface du site Internet

Chaque page du site se découpe en 2 frames (1) : une frame en haut de la fenêtre qui contient l'en-tête de la page ("entete.html") et qu'on retrouve à l'identique sur toutes les pages du site, la deuxième frame qui comprend le reste de la page est le corps même de la page ("bdrcgi.cgi").

Au départ les pages du site n'étaient pas divisées en plusieurs frames, mais du fait que l'on retrouvait partout la même en-tête, il était plus intéressant de faire 2 frames pour que l'affichage des pages soit plus rapide, ainsi l'en-tête ne serait pas à chaque fois rechargée.

De plus, la nouvelle mise en page du site permet d'avoir à l'écran toute la page du site sans avoir à la faire défiler à l'aide d'un ascenseur ce qui est beaucoup plus pratique. En effet, les boutons de navigation étaient auparavant disposés en dessous de l'image et il fallait à chaque fois faire défiler la page jusqu'à ces boutons pour les atteindre. Alors si par exemple on souhaite faire défiler les images une par une à l'aide de ces boutons, la manoeuvre était assez pénible. Maintenant que les boutons sont disposés sur la gauche de l'image, tout est accessible directement.

(1) Une frame (cadre en français) est une partie d'une fenêtre.

2.2) Réalisation et mise en ligne :

Un programme CGI (Common Gateway Interface (1) ) avait déjà été écrit en langage C pour générer les pages HTML du site. Ce programme permet d'utiliser les fonctions déjà écrites dans les programmes de consultation de la base de données et d'exécuter les requêtes de l'utilisateur sur le serveur où est hébergé le site, ce qui n'aurait pas pu être réalisé avec seulement le langage HTML.

Le programme CGI comporte une fonction Main() qui selon les actions de l'utilisateur va afficher les différentes pages demandées.

Pour qu'il soit possible d'installer ce programme et l'ensemble du site sur n'importe quel serveur, il fallait que les liens soient relatifs et qu'ils puissent s'adapter à n'importe quelle configuration. Ainsi au début de l'exécution du programme CGI, une variable récupère le nom de la machine sur laquelle il se situe grâce à la fonction "gethostent()" et ensuite tous les liens sont créés par rapport à cette variable. Il est donc possible de porter le site sur un autre serveur sans que cela implique de modifications du code.

D'autre part, on peut consulter sur le site des animations radar qui sont la succession des images radar composant un événement pluvieux. Les images sont créées à la volée grâce aux données stockées dans la base et affichées au format Gif. Pour réaliser les animations, on fait une boucle parcourant la liste des images à afficher et entre chaque image une pause de quelques millisecondes permet d'attendre qu'une image soit finie de charger avant d'afficher la suivante. Cependant le temps de cette pause étant fixe alors que le temps de chargement d'une image peut être variable, il persiste des dérèglements dans les animations car les images n'ont pas touj ours le temps de se charger entièrement.

Une solution aurait été d'utiliser une fonction qui vérifie qu'une image a bien finie de se charger avant d'afficher la suivante, mais rien de tel n'a été trouvé. C'est pourquoi la pause entre deux images est gérée par la fonction "sleep" du langage C qui attend un certain temps avant de continuer l'exécution du programme.

Une fois le programme CGI compilé, il faut le mettre sur le serveur dans un répertoire "cgi-bin" et lui donner les bonnes permissions pour que les utilisateurs puissent l'exécuter. Il doit donc avoir "chmod 755" (sous Unix), c'est-à-dire les droits de lecture et d'exécution. Le reste des pages et des images se trouve dans un répertoire "public-html" sur le serveur.

3) Programme de visualisation :

3.1) Choix du langage et conception :

La partie la plus importante du stage était de créer un nouveau programme permettant de visualiser les images radar de la base et qui pourrait être mis et distribué sur un CD-Rom.

(1) Un programme CGI s'exécute sur un serveur, effectue des traitements de données et génère des pages HTML.

Après réflexion, il s'est avéré que le langage Java était le mieux adapté à ce projet pour plusieurs raisons :

- Tout d'abord Java est portable sur tout type de machine puisqu'une fois compilé il pourra fonctionner aussi bien sous une station Unix que sous Windows ou autre, c'est un de ses grands avantages par rapport aux autres langages et comme nous ne pouvons savoir à l'avance sur quel type de machine le programme serait utilisé il fallait absolument un langage portable.

- De plus son API (Application Programming Interface) est très complète et permet d'accéder à de nombreuses fonctionnalités. Ainsi Java possède plusieurs packages pour programmer une interface graphique adaptable selon le système d'exploitation de la machine sur laquelle on utilise le programme.

- Java est un langage orienté objet ce qui permet une programmation plus efficace et plus organisée qu'avec un langage procédural (comme le C) et programmation objet était plus adaptée à la tâche.

Les cas d'utilisation possibles pour ce programme sont représentés par le schéma suivant (Figure 5) :

Lister les événements d'une saison

Lister les images d'un événement

Visualiser une image radar

Visionner les animations radar

utilisateur

Enregistrer une image

Figure 5 : Diagramme des cas d'utilisation

Lister les événements d'une saison : proposer à l'utilisateur de choisir une année parmi celles disponibles dans la base de données et en fonction de la saison choisie, donner la liste des événements enregistrés.

Lister les images d'un événement : de même que pour le cas d'utilisation précédent, l'utilisateur doit pouvoir obtenir pour un événement choisi, la liste de toutes les images le concernant.

Visualiser une image radar : à partir de la liste des images, il est doit être possible de visualiser l'image correspondante dans l'interface.

Visionner les animations radar : pour chaque événement, l'utilisateur peut visionner l'animation qui correspond, c'est-à-dire la succession des images composant un événement et formant donc une animation.

Enregistrer une image : l'image visualisée à l'écran doit pouvoir être enregistrée par l'utilisateur dans un fichier image (ici au format PNG).

3.2) Transfert et organisation de la nouvelle base de données :

a) Programme de transfert en C :

Pour pouvoir utiliser la base de données avec le programme qui allait être réalisé en Java, il fallait tout d'abord trouver une nouvelle forme d'organisation de la base et la transférer car la librairie C-Isam qui permettait de la gérer jusqu'à maintenant ne peut être accéder qu'avec le langage C. Afin d'effectuer ce transfert deux solutions ont été examinées et après une étude approfondie c'est la deuxième qui a finalement été choisie ce qui est expliqué ciaprès.

La première solution envisagée fut d'utiliser JNI (Java Native Interface) pour effectuer ce transfert. Le package JNI de Java permet de coupler du code Java et du code C ou C++ en respectant cinq étapes de programmation :

- codage de la partie du programme en Java (classes .java) : déclarations des méthodes natives et compilation avec l'exécutable "javac".

- génération d'un fichier *.h grâce à l'exécutable "javah" qui crée l'en-tête du fichier C de manière automatique.

- codage de la partie C : implémentation des méthodes natives

- génération d'une librairie (*.so sous un environnement UNIX et *.dll sous Windows) qui contient les fichiers *.h et *.c

- exécution du programme avec la commande "java"

Ainsi il était possible de réutiliser les fonctions déjà écrites en C pour consulter la base et récupérer les données avec un programme Java qui se chargerait de les organiser d'une nouvelle façon. Puis après étude de cette solution et quelques essais, il s'est avéré que les possibilités de ce système étaient assez restreintes et qu'il était difficile de la mettre en place.

C'est pourquoi une deuxième solution pour transférer la base de données a été envisagée : le plus simple était de passer par un fichier intermédiaire entre un programme C et un programme Java. Ainsi un premier programme en C a été réalisé pour lire l'ensemble des données stockées dans la base et les écrire dans un fichier texte qui pourrait donc être relu de

n'importe quelle manière. Quatre fichiers textes ont donc été construits par ce programme et représentent les 4 années de données. Ces fichiers étaient seulement destinés à être relus une fois par un autre programme en Java qui lui se chargerait de les organiser autrement.

Le programme de transfert en Java lit donc chaque fichier texte de façon séquentielle et ordonne les données dans un fichier binaire. On aurait pu conserver les fichiers textes obtenus à la suite de l'exécution du programme de transfert en C, cependant ces fichiers sont très volumineux puisqu'ils font chacun entre 200 et 300 Mo. Cela rendrait les recherches très longues puisque l'accès à un fichier texte ne peut se faire que de manière séquentielle. Il fallait alors trouver une autre façon de stocker les données qui seraient exploitées par le programme de visualisation en Java. Examiné

Après le transfert des données dans un fichier texte intermédiaire, il a fallu trouver un moyen de stocker et de structurer ces données qui seront utilisées par le programme en Java.

b) Nouvelle organisation de la base :

Afin d'organiser la nouvelle base de données plusieurs méthodes ont été considérées. La première qui est présentée ici est la sérialisation. Après quelques tests cette solution n'a finalement pas été retenue au profit de la deuxième méthode examinée détaillée ensuite.


· Etude d'une méthode : la sérialisation :

Etant donné que Java est un langage orienté objet et permet donc d'exploiter pleinement les avantages d'une structure avec des classes et des objets, le plus simple était de relire chaque fichier texte et de construire des objets à partir de ces données. Les objets seraient ensuite enregistrés dans un fichier et pourraient être réutilisés ultérieurement.

Pour réaliser ceci Java propose la sérialisation d'objets. L'interface "Serializable" permet de stocker des objets dans un fichier qui sont accédés séquentiellement. Quand on sérialise un objet dans un fichier, toutes ses dépendances et les objets avec lesquels il a des liens sont également sérialisés. C'est pourquoi il était intéressant de créer une classe "Base" qui regrouperait l'ensemble des objets de la base de données et cet objet "Base" serait seul sérialisé dans un fichier. Alors tous les autres objets seraient également enregistrés dans le fichier et pourraient être retrouvés par la suite.

Tableau de comparaison avantages / inconvénients pour la sérialisation :

Avantages

Inconvénients

Permet la persistance des objets et des liens entre objets de manière très simple.

Très long si l'on a beaucoup d'objets ou des objets de grande taille.

Format indépendant du système d'exploitation, donc possibilité d'utiliser les objets avec d'autres systèmes par la suite.

 

Système applicable à tous les objets.

 

Enregistre tous les objets référencés par l'objet sérialisé.

 
 

Cependant il existe un énorme inconvénient à cette méthode : puisque la base de données est d'une taille très importante, l'objet "Base" aurait fait plusieurs centaines de Mo également et il fallait plusieurs heures pour le sérialiser ou le désérialiser, car en effet on est obligé de lire (désérialiser) l'objet en une seule fois et avec tous les objets qui en dépendent. La sérialisation est donc très utile et très pratique dans certains cas, en particulier quand on ne possède pas d'importants objets à mémoriser mais pour ce projet elle n'était pas du tout envisageable.


· Choix d'une autre méthode :

Les autres méthodes pour stocker des données dans des fichiers en Java sont les fichiers textes et les fichiers binaires à accès séquentiel, ce qui aurait été beaucoup trop long ici. Il restait donc une solution qui est l'utilisation de fichiers binaires à accès direct ("RandomAccessFile" pour Java). La classe RandomAccessFile permet de créer et de lire des fichiers binaires à accès direct grâce à la fonction "seek" qui place le "pointeur du fichier" où l'on veut dans le fichier.

Cependant il faut indiquer à cette fonction à quel octet on veut aller dans le fichier et non pas en lui indiquant une clé comme dans les fichiers indexés. Cela implique de connaître l'endroit exact où est stockée une donnée si on veut la retrouver. Le programme Java servant au transfert de la base construit un fichier binaire pour les données de chaque année (donc 4 saisons) et organise les données de manière ordonnée. Ainsi il relit les données dans le fichier texte de manière chronologique et les retranscrit dans le fichier binaire de la façon suivante (Figure 6) :

Enregistrements

Champs

Total

Evénement1

jd md ad hd mind sd jf mf af hf minf sf nbim

15 octets

Image1

j m a h min s seco site reso nbrad ppirhi

19 octets

Radiale1 1

azi site p1 p2 p3 p4 ... p512

520 octets

Radiale12

azi site p1 p2 p3 p4 ... p512

520 octets

...

...

...

Radiale1Max

azi site p1 p2 p3 p4 ... p512

520 octets

Image2

j m a h min s seco site reso nbrad ppirhi

19 octets

Radiale21

azi site p1 p2 p3 p4 ... p512

520 octets

...

...

...

Evénement2

jd md ad hd mind sd jf mf af hf minf sf nbim

15 octets

...

...

...

 

Figure 6 : Structure du fichier binaire

Les enregistrements et les champs sont les suivants : Evénement :

Champs :

- jd : jour de la date de début de l'événement (byte : 1 octet)

- md : mois de début (byte : 1 octet)

- ad : année de début (short : 2 octets) - hd : heure de début (byte : 1 octet) - mind : minute de début (1 octet) - sd : seconde de début (1 octet)

- jf : jour de la date de fin de l'événement (byte : 1 octet)

- mf : mois de fin (1 octet)

- af : année de fin (short : 2 octets) - hf : heure de fin (byte : 1 octet)

- minf : minute de fin (byte : 1 octet) - sf : seconde de fin (byte : 1 octet)

- nbim : nombre d'images composant l'événement (byte : 1 octet) -

Taille totale : 15 octets

Image :

Champs .
·

- j : jour de la date de l'image (byte : 1 octet)

- m : mois (byte : 1 octet)

- a : année (short : 2 octets) - h : heure (byte : 1 octet)

- min : minute (byte : 1 octet) - s : seconde (byte : 1 octet)

- seco : secteur couvert (2) (float : 4 octets)

- site : site (1) (float : 4 octets)

- reso : résolution de l'image (byte : 1 octet)

- nbrad : nombre de radiales composant l'image (short : 2 octets)

- ppirhi : indique si l'image est PPI ou RHI (1) (byte : 1 octet)

Taille totale : 19 octets

Radiale :

Champs .
·

- azi : azimut (1) de la radiale (float : 4 octets)

- site : site (float : 4 octets)

- p1, p2... p512 : portes composant la radiale (512 portes par radiale) : valeur en DBz (1) (byte : 1 octet)

Taille totale : 520 octets

(1) Cf. définition dans le Glossaire page 33

Pour réduire le plus possible la taille des fichiers binaires il fallait bien choisir les types de chaque donnée pour que de la place ne soit pas gaspillée. Les différents types primitifs proposés par Java sont les suivants (Figure 7) :

Primitive

Signification

Taille

Valeurs acceptées

char

Caractère

2 octets

Valeur du jeu de caractères Unicode (65 000 caractères possibles).

byte

Entier très court

1 octet

-128 à 127

short

Entier court

2 octets

-32768 à 32767

int

Entier

4 octets

-2 147 483 648 à 2 147 483 647

long

Entier long

8 octets

-9223372036854775808 à 9223372036854775807

float

Flottant (réel)

4 octets

-1.4* 1 0-45 à 3.4* 1038

double

Flottant double

8 octets

4.9* 10-324 à 1.7* 1 0308

boolean

Booléen

1 octet

0 ou 1 (en réalité, toute autre valeur que 0 est considérée égale à 1)

 

Figure 7 : Types primitifs en Java

Etant donné que la plupart des valeurs des données que l'on a à stocker sont inférieures à 256 du fait de la conversion des données depuis le système SANAGA (où elles étaient sur 8 bits), il était préférable de privilégier l'utilisation du type byte pour réduire la taille du fichier. Ainsi toutes les petites valeurs ne dépassant pas 127 ont été enregistrées comme des bytes. Le problème était que la plupart des valeurs stockées dans la base et qui occupent la majeure partie des fichiers sont les valeurs des portes de chaque radiale.

Or la valeur d'une porte peut varier entre 0 et 255, il n'est donc pas possible de la coder sur un byte. Cependant toutes les valeurs négatives n'étaient pas utilisées car une porte ne peut pas avoir une réflectivité négative. C'est pourquoi le système adopté pour coder les valeurs des portes a été d'utiliser des bytes de la manière suivante :

- pour les portes de valeur comprise entre 0 et 127 : codage normal sur un byte.

- pour les portes de valeur comprise entre 128 et 255 : on soustrait 256 à la valeur initiale de façon à obtenir un nombre négatif compris entre -128 et -1. Lors de la relecture du fichier il faut donc rajouter 256 pour avoir la bonne valeur. Ce système permet de gagner de la place en codant toutes les portes sur un byte, la taille des fichiers est alors pratiquement divisée par 2, ce qui était nécessaire pour qu'ils tiennent tous un CD-Rom.

Grâce à cette organisation on connaît la taille de chaque donnée ce qui permet de calculer le nombre d'octets que l'on veut sauter pour accéder à un certain champ. Par exemple, si l'on recherche un événement dans la base pour une date donnée, il faut consulter la date du 1 er événement puis si ce n'est pas celui qu'on recherche, on peut se placer directement au début de l'événement suivant.

Ainsi si l'on recherche un événement pour une date donnée il faut faire la boucle

suivante (1) :

- ouverture du fichier et placement du pointeur en début de fichier (position 0).

(1) Cf. Annexe 3 page 47 pour le détail du code

- lecture du 1er champ du 1er événement (c'est-à-dire le jour).

Si le jour est identique à celui de la date recherchée on lit les autres champs pour voir si c'est le bon événement, si c'est effectivement le bon on récupère les autres données relatives à l'événement, sinon on reprend la boucle de recherche.

- Si le jour est différent on doit se placer au début du prochain événement. Pour cela il faut connaître le nombre d'octets (et donc d'images enregistrées) à sauter. Le champ "nbim" de l'événement nous indique le nombre d'images qui sont enregistrées pour celui-ci (et pour chaque image le champ "nbrad" indique le nombre de radiales enregistré).

- Il faut donc pour accéder à l'événement suivant se placer à l'octet de rang égal à : octet n° = 15 + 19*nbim + 520*nbrad*nbim (sachant que le nombre de radiales nbrad est différent pour chaque image).

L'accès n'est donc pas tout fait direct puisqu'il faut faire un parcours séquentiel pour trouver l'événement recherché. Cependant cet accès est très rapide puisqu'il ne faut consulter qu'un seul champ de l'événement pour savoir si c'est le bon, c'est-à-dire si la date correspond. Il en est exactement de même si l'on recherche une image pour une date donnée.

Maintenant que la banque de données est organisée dans de nouveaux fichiers lisibles par le programme en Java, la suite de la programmation est la réalisation de l'interface graphique du programme.

3.3) Interface graphique : architecture et fonctionnalité

a) Paquetages :

Pour réaliser une interface graphique en Java, on dispose de plusieurs API qui sont AWT et SWING. AWT est la 1ère API développée en Java pour faire des interfaces graphiques et bien que très puissante, l'API SWING a apporté ensuite de nombreuses fonctionnalités qui font que les possibilités offertes sont très importantes.

La particularité des interfaces graphiques en Java est que les composants sont dessinés par le système d'exploitation de la machine sur laquelle on utilise le programme, ce qui entraîne des différences quant à l'apparence suivant les systèmes. Les composants de SWING sont eux dessinés directement par Java mais dérivent de AWT ce qui revient à les faire dessiner par l'OS. (1)

Les composants et fonctionnalités offerts par SWING sont nombreux et variés : on peut utiliser toutes sortes de composants tels que des boutons, des menus déroulant, des boites de dialogue,.. .et SWING permet de gérer les événements clavier, souris ou autres.

Après une étude de ces paquetages et quelques essais, l'étape suivante est de concevoir l'architecture du programme et ensuite de programmer l'interface.

(1) L'OS est le système d'exploitation d'une machine, c'est-à-dire le logiciel de base d'un ordinateur.

b) Architecture du programme :

Avant toute chose il est nécessaire de présenter rapidement le fonctionnement des interfaces graphiques en Java pour comprendre comment le programme a pu être organisé et donc comment les fenêtres sont dessinées.


· Présentation :

Le système pour créer une interface graphique avec l'API SWING de Java est assez complexe. Il faut tout d'abord construire une fenêtre principale de la classe "JFrame" puis si l'on veut ajouter des composants dessus il faut lui appliquer un "panneau", c'est-à-dire une instance de la classe "JPanel". Puis pour contrôler la disposition des composants sur ce panneau il faut lui ajouter un "layout" (1) qui détermine de quelle manière les composants seront ajoutés dans la fenêtre.

Il existe 5 layout différents en Java que l'on peut choisir, mais le plus utilisé est le "BorderLayout" qui a d'ailleurs servi pour la fenêtre principale du programme. Ce layout découpe la fenêtre et dispose les composants de la façon suivante :

Nord

Ouest Centre Est

Sud

Barre d'outils

Listes Image
de choix

Dans la fenêtre principale (Figure 8) du programme Badora ne sont utilisées que trois de ces cinq zones :

- Au "Nord" se trouve la barre d'outils avec les raccourcis et une liste déroulante permettant de choisir la saison à consulter.

- A "l'Ouest" se trouvent deux listes déroulantes pour choisir un événement et une image pour une saison donnée.

- Au "Centre" s'affiche l'image ou l'animation radar demandée.

(1) Un layout en Java est un gestionnaire de positionnement qui permet de disposer les composants dans une fenêtre d'une certaine manière.

Figure 8 : Capture d'écran de la fenêtre principale


· Organisation :

A l'ouverture du programme, une petite fenêtre de bienvenue (Figure 9) s'ouvre où apparaissent : le nom du logiciel, les logos des laboratoires concernés par ce projet et des boutons permettant de choisir directement la saison que l'on veut consulter. A partir de cette fenêtre on accède directement à la fenêtre principale.

Figure 9 : Capture d'écran de la fenêtre d'accueil

La fenêtre principale (Figure 6) permet de consulter toutes les images radar de la base en naviguant grâce aux menus déroulants sur la gauche de l'écran. Une première liste déroulante permet de choisir une année et en fonction de la sélection effectuée les deux autres listes déroulantes sont modifiées et proposent l'une la liste des événements pour cette année et l'autre la liste des images pour l'événement sélectionné.

Une barre d'outils est également à la disposition de l'utilisateur en haut de la fenêtre avec des boutons raccourcis permettant de faire défiler les images d'un événement dans l'ordre chronologique sans avoir à choisir dans la liste déroulante. D'autres boutons sont aussi disponibles, par exemple pour enregistrer une image sans aller dans le menu Fichier ou bien pour démarrer et arrêter une animation.

Enfin, la barre de menus tout en haut de la fenêtre contient deux menus : le menu "Fichier" avec deux options (enregistrer une image dans un fichier et quitter le programme) et le menu "Aide" qui pour l'instant ne propose qu'une seule option (informations sur le programme).

Tous les composants d'une interface graphique sont des objets et l'organisation des classes d'une interface graphique est assez complexe en Java (1) . La principale fonctionnalité de l'interface est ici d'afficher les images et animations radar, cela va donc être détaillé plus amplement.

3.4) Codage des images et animations radar :

Avant de pouvoir afficher les images à l'écran, il faut d'abord les construire à partir des données de la banque BADORA.

a) Passage du repère polaire au repère cartésien :

Les données qui sont stockées dans la base permettent de construire des images dans un repère polaire c'est-à-dire dans un cercle autour du radar. Etant donné que le repère dans une interface graphique en Java est cartésien il fallait transformer les coordonnées des points à afficher (Figure 10).

Repère polaire Repère cartésien en Java

Figure 10 : Représentation des deux repères graphiques

90°

y

x

On passe donc d'un repère polaire où les points sont dessinés grâce à l'angle de la radiale et la distance du point par rapport au centre du cercle à un repère cartésien où les coordonnées d'un point sont exprimées avec un x et un y (abscisse et ordonnée).

Pour passer du repère polaire au repère cartésien, il faut alors effectuer les transformations suivantes :

- transformer les coordonnées des points pour les exprimer avec une abscisse et une ordonnée.

- translation des points pour qu'ils aient tous des coordonnées positives.

(1) Pour plus de détails sur l'architecture du programme et les différentes classes crées voir la description des classes en Annexe 1 page 36

b) Création et affichage des images :

Une fois les coordonnées des points transformées, les images sont dessinées grâce à la fonction "paintComponent". Cette fonction de la classe Jpanel permet de dessiner directement sur le panneau et gère le rafraîchissement de la fenêtre. Chacun des points dessinés représente une porte de l'image et suivant la réflectivité enregistrée pour cette porte, la couleur du point sera différente. Ainsi chaque point est dessiné sur le panneau suivant ses coordonnées et sa couleur.

Ensuite sont rajoutés des cercles concentriques qui permettent d'évaluer les distances sur l'image, chaque cercle étant distant de 50 Km. Trois résolutions d'image sont possibles : rayon représentant 100 Km (Figure 11), 250 Km ou 350 Km (Figure 12).

Figure 11 : Image radar avec une Figure 12 : Image radar avec une

résolution sur 100 Km résolution sur 350 Km

Les images radar sont donc dessinées à la volée dans un buffer (1) (classe BufferedImage en Java) puis affichées à l'écran ce qui permet d'aller plus vite que si on les dessinait directement à l'écran. Il est ensuite possible d'enregistrer ces images au format PNG grâce à l'option "Enregistrer image" du menu Fichier.

La librairie "PngEncoder" permet de fabriquer une image PNG à partir de l'image stockée dans le buffer grâce à un algorithme d'encodage. La conversion d'une image au format PNG est un peu plus longue que le fait d'afficher une image créée à la volée à l'écran mais cela n'est pas très gênant puisque l'utilisateur ne va pas enregistrer chaque image mais une image de temps en temps s'il en a besoin.

(1) Un "buffer" est un tampon dans la mémoire vive et permet de stocker temporairement des données.

c) Animations radar :

La réalisation des animations radar est en cours de programmation et elle devrait se faire à l'aide d'un "thread" (1). Il s'agit de créer et de faire défiler les images radar d'un événement dans l'ordre chronologique pour retracer l'évolution de cet événement. L'utilisation d'un thread ici permet de ne pas ralentir l'exécution du reste du programme, en effet les animations demandent beaucoup de ressources et il est préférable qu'elles soient gérées parallèlement.

Il est possible dans un thread d'utiliser la fonction "pause" qui peut servir à indiquer un temps d'arrêt entre chaque chargement d'image. A part cela, il n'y a pas vraiment de différence avec l'affichage des images puisque que les fonctions de dessin seront ensuite exactement les mêmes.

(1) Un "thread" est une tâche exécutée en parallèle du programme principal.

III] Résultats

1) Tests et résultats :

En ce qui concerne la 1ère partie du stage qui était de porter les programmes développés sous UNIX, il ne persiste a priori pas de problèmes puisque les différents programmes qui auront encore une utilité fonctionnent correctement sous Linux comme cela était demandé. De plus, le principal objectif qui était ici de sauvegarder des données qui avaient failli être perdues a été atteint et la persistance de cette base de données est assurée.

Pour le site Internet tout fonctionne également correctement à part un problème concernant l'affichage des images radar pour le dernier événement d'une saison. En effet, la liste des images disponibles pour ce dernier événement est bien accessible quand on clique sur un des liens pour visualiser une image, cette dernière ne s'affiche pas. Après plusieurs relecture du code du programme CGI, aucune solution n'a pu être trouvée à ce problème. Cependant tout le reste des liens du site fonctionnent correctement.

Concernant la dernière partie du stage, c'est-à-dire la réalisation d'un programme de visualisation en Java qui a été la plus longue et la plus importante au niveau de la programmation, les principales fonctions qui étaient demandées sont maintenant réalisées à part la visualisation des animations radar. Mais cela sera normalement terminé pour la fin du stage car l'affichage des images qui étaient le plus difficile est désormais réalisé. Il suffit donc pour les animations de faire défiler les différentes images radar.

Ce programme a été développé et tout d'abord testé sur un PC fonctionnant sous Linux moyennement puissant (Pentium II 400), ce qui rendait l'exécution du programme très lente. Après des tests sur d'autres PC plus puissants, il s'est avéré que cela ne venait pas que de la machine mais surtout du code du programme. Il a donc fallu optimiser la programmation et notamment revoir l'affichage des images.

Le programme s'exécute maintenant rapidement même si l'affichage des images radar n'est pas instantané mais cela est dû à la quantité importante d'informations à traiter. En effet pour chaque image il y a environ 100 000 lignes à dessiner (au maximum 225 radiales * 512 portes = 115200).

La principale fonctionnalité de ce programme est la visualisation des images radar et après réflexion, j'ai pensé qu'il serait intéressant de rajouter la possibilité de sauvegarder les images ainsi créées si l'utilisateur veut en conserver une copie et l'utiliser pour autre chose. La barre de menu se trouvant en haut de la fenêtre principale propose dans le menu "Fichier" une option "Enregistrer image" qui ouvre une fenêtre de dialogue (Figure 11) permettant de choisir un nom et de sauver l'image au format PNG.

Figure 11 : Fenêtre pour enregistrer une image

2) Problèmes rencontrés :

2.1) Compréhension du système C-ISAM de gestion de BD :

La librairie C-ISAM d'Informix qui avait été utilisée pour gérer la banque de données fonctionne avec un système de fichiers indexés grâce à des clés. Il existe peu de documentation sur cette librairie à part le manuel utilisateur qui est très technique et en anglais, c'est pourquoi il a été assez dur de bien comprendre son mode de fonctionnement ce qui était nécessaire pour corriger les anciens programmes et aussi pour transférer la banque de données.

2.2) Organisation d'une BD de taille importante :

Il a été assez difficile de trouver un moyen de gérer la nouvelle base de données utilisée par le programme en Java, en effet à cause de la taille importante de la base Java ne proposait pas de solution vraiment satisfaisante. Une solution aurait pu être d'utiliser une base de données orientée objet grâce à JDBC (Java DataBase Connectivity) mais cela aurait impliqué soit que l'utilisateur se connecte à la base de données sur un serveur distant, et ici on voulait développer un programme n'ayant pas besoin de connexion Internet. Soit on aurait pu se connecter à une base de données locale, mais à ce moment-là l'utilisateur aurait du avant d'utiliser le programme installer la base sur sa machine, c'est-à-dire installer un serveur, le configurer et installer la base de données, ce qui aurait été très pénible et aurait sûrement découragé plus d'un utilisateur.

C'est pourquoi il fallait forcément opter pour la solution de stocker les données dans des fichiers, mais là encore ce n'était pas vraiment satisfaisant. En effet, Java ne propose pas d'utiliser directement de fichiers indexés ce qui aurait été très pratique dans notre cas. La solution finalement adoptée d'écrire les données dans des fichiers à accès direct en se plaçant à un certain point du fichier est donc un bon compromis et nécessite la mise en place d'algorithmes pour rechercher un enregistrement précis.

2.3) Réalisation des images radar :

Au niveau de la création et de l'affichage des images radar plusieurs problèmes se sont posés. Tout d'abord il a fallu transformer l'image dont les points étaient exprimés avec des coordonnées polaires pour qu'ils aient des coordonnées cartésiennes, ce qui n'a pas été très

simple. Heureusement Java possède une classe "Math" qui permet de convertir des angles exprimés en degrés en radians et vice-versa, ainsi que des variables prédéfinies telle que la valeur de PI. Cela a déjà simplifié la programmation mais il a fallu un certain temps avant d'afficher des images radar correctes ce qui est maintenant presque terminé.

Il a aussi été difficile de trouver une méthode de dessin des images qui soit assez rapide car ne connaissant pas la programmation des interfaces graphiques en Java au départ, il n'était pas évident de savoir quelle méthode utiliser. Finalement l'exécution du programme a pu être accélérée petit à petit et le temps d'affichage d'une image est désormais raisonnable.

3) Améliorations possibles :

Je ne pense pas que les programmes déjà existants qu'il fallait porter sous Linux vont être encore modifiés par la suite ou qu'il soit intéressant d'y apporter de nouvelles fonctionnalités. Si des modifications peuvent être faites sera plutôt sur le site Internet pour ajouter des informations par exemple ou bien pour améliorer encore l'interface graphique.

Les principales améliorations qui pourraient être réalisées portent sur le nouveau programme de visualisation auquel on peut ajouter de nouvelles possibilités. Ces améliorations pourront être effectives si j'ai le temps de les faire avant la fin de ce stage, sinon elles pourront être proposées pour de futurs stages. Sur le site Internet il est par exemple possible quand on visualise une image radar de cliquer dessus et de visualiser juste le degré carré de cette image. Cela n'est pour l'instant pas encore disponible sur le programme en Java mais pourra assez facilement être réalisé.

On peut aussi envisager d'étendre la portée du programme à d'autres années d'observation et donc d'agrandir la base de données. Mais cela implique d'enregistrer les nouvelles données dans des fichiers binaires de la manière que pour les quatre saisons déjà enregistrées, et cela peut être un travail plus long.

Conclusion

Le stage que j'ai effectué peut se décomposer en trois parties principales se rapportant toutes trois au même projet, c'est-à-dire l'exploitation de la banque de données BADORA qui regroupe les données acquises lors de l'expérience EPSAT-NIGER.

Tout d'abord la première partie du travail a été de porter les programmes servant à la gestion de cette base sur des machines plus récentes fonctionnant sous Linux. Dans la deuxième partie du stage qui est dans la continuité de la première, il s'agissait de mettre les données à la disposition de tout le monde grâce au site Internet. Enfin la troisième partie a été de créer un nouveau programme pour BADORA en Java pour qu'il soit possible de le diffuser sur un CD-Rom. Tous ces programmes ont pour but d'extraire les données de la banque pour créer des images et des animations radar permett ant de visualiser les précipitations enregistrées.

Pour l'ensemble de ce stage, mon principal problème a été la gestion du temps. En effet, il était difficile au départ d'estimer le temps nécessaire pour chaque partie du travail puisque c'était la première fois que l'on devait gérer soi-même un projet de telle envergure. La difficulté était donc d'arriver à bien planifier et découper le travail pour être sûr d'atteindre les objectifs prévus mais ceci est d'autant plus difficile quand on ne sait pas à l'avance quels seront les problèmes à résoudre.

En outre, ce stage m'a permis de mettre en pratique les connaissances que j'avais apprises à l'IUT et de les approfondir en particulier au niveau de la programmation en Java. J'ai pu ainsi passer de la théorie à la pratique et comprendre que l'expérience d'un stage est absolument indispensable d'une part pour voir l'utilité des enseignements théoriques que l'on a suivi et d'autre part pour que l'insertion professionnelle soit plus aisée par la suite.

Avant je ne voyais pas forcément l'utilité d'un stage et je pensais qu'il était préférable de faire encore plusieurs années d'études afin d'acquérir plus de connaissances avant d'avoir une expérience professionnelle. Mais j'ai maintenant compris qu'il valait mieux mener les deux de front, c'est-à-dire d'enrichir ses connaissances théoriques tout en faisant le parallèle avec le monde professionnel, les deux sont nécessaires à mon avis pour une meilleure insertion ensuite et une plus grande efficacité dans son travail.

Ce stage était pour moi la première expérience professionnelle et je n'avais pas pensé au départ le faire dans un laboratoire mais plutôt dans une entreprise pour découvrir le monde du travail. Je pense en effet que l'ambiance de travail n'est pas du tout la même dans une entreprise où ce sont les contraintes financières qui souvent obligent les gens à travailler alors que dans un laboratoire les gens travaillent par une véritable motivation du résultat, par passion. Je pensais que l'adaptation au monde du travail serait difficile car très différent du milieu scolaire, mais finalement je n'ai pas eu trop de mal à m'adapter et je n'ai pas observé de si grande différence à part qu'il fallait trouver soi-même les informations et au bon endroit.

Je suis donc très heureuse d'avoir fait ce stage au LTHE puisque d'une part cela m'a permis de découvrir le mode de travail dans un laboratoire et cela m'a aidé à réaliser que c'était ce genre de travail que je voulais faire plus tard plutôt que de travailler dans une entreprise. D'autre part, si j'ai choisi spécialement ce laboratoire pour y effectuer mon stage c'est parce qu'il mène des études dans le domaine de l'environnement et c'est justement dans ce domaine que je souhaite travailler plus tard. Au fur et à mesure du stage, j'ai été confortée dans cette idée et j'ai pu ainsi avoir une expérience me permettant de confirmer que c'était bien l'orientation vers laquelle je voulais aller.

Ma motivation pour ce stage était d'autant plus grande qu'il concernait une étude réalisée en Afrique, j'ai donc pu rencontrer et travailler avec des gens dont la motivation est la même que la mienne, c'est-à-dire de mettre à profit mes compétences informatiques pour l'étude, la compréhension et la protection de l'environnement. Au final ce stage a été pour moi très enrichissant et m'a permis de savoir vraiment quel était mon projet professionnel pour le futur.

Glossaire

Azimut : Le radar peut pivoter sur 2 axes différents : soit verticalement, soit horizontalement. Quand la rotation est horizontale, le balayage du radar se fait dans le sens des aiguilles d'une montre et à chaque intervalle de tir on peut déterminer l'azimut (en degrés) qui est l'angle entre la ligne de visée du radar et le Nord géographique.

DBz : Unité de mesure de la réflectivité radar.

Degré carré : carré de 1° de latitude et 1° de longitude.

Evénement : Un événement pluvieux est l'ensemble des images qui correspondent à un même phénomène météorologique. Cela peut durer de quelques heures à quelques jours environ.

PPI / RHI : Il existe deux modes d'observation du radar. En mode PPI, le radar effectue un balayage horizontal avec un site constant et l'azimut qui peut varier sur les 360 degrés. En mode RHI, c'est l'azimut qui est fixe et le site lui varie de 0 à 90 degrés.

Radiale : Une radiale correspond à un tir du radar.

Réflectivité (en DBz) : Le radar envoie dans l'atmosphère des impulsions électromagnétiques qui sont renvoyées en partie lorsque le signal rencontre une cible. Cette cible peut être un nuage ou des précipitations. Cela permet de déterminer la réflectivité suivant le volume de l'impulsion retourné.

Secteur couvert : Différence entre l'azimut de la dernière radiale et l'azimut de départ.

Site : L'inclinaison du radar donne la valeur du site (en degrés). Lors d'une rotation horizontale, le site doit donc être constant si l'on veut obtenir une image juste de la situation météorologique présente.

Bibliographie - Webographie

· Banque de données BADORA : "Manuel utilisateur de BADORA"

· Programmation générale en Java :

"Programmer en Java" de Claude Delannoy aux Editions Eyrolles

"Le programmeur Java 2" de Laura Lemay et Rogers Cadenhead aux Editions CampusPress

http://www.infini-fr.com/Sciences/Informatique/Langages/Imperatifs/Java/java.html http://www.eteks.com/coursjava/tdm.html

http://java.sun.com/

http://www.commentcamarche.net/java/

· La sérialisation : http://www.club-java.com/Public/articles/articleCJ.html

· Interfaces graphiques : "Java 2D Graphics" de Jonathan Knudsen aux Editions O'Reilly

· Programmes CGI : http://members.aol.com/martpopuo/cgi.htm

· PNG Encoder : http://catcode.com/pngencoder/

Annexes

Annexe 1 p. 36 : Description des différentes classes Java

Annexe 2 p. 38 : Code commenté des classes principales du programme Java (Badora.java) :

- page 38 : Classe Interface

- page 40 : Classe dialogDeb - page 42 : Classe listEV - page 46 : Classe Badora

Annexe 3 p. 47 : Code commenté de la classe Evénement avec la recherche d'un événement dans un fichier de la banque de données.

Annexe 4 p. 49 : Extrait de la Classe JImage avec la création et l'affichage d'une image radar.

Annexe 1 : Description des classes Java

· Badora (1) :

Badora est la classe appelée pour exécuter le programme puisqu'elle ne comporte que le Main() qui construit une nouvelle interface en créant une instance de la classe Interface.

· Interface (2) :

Cette classe est la plus importante du programme et gère toute l'interface graphique. Elle construit tout d'abord la fenêtre de bienvenue puis affiche la fenêtre principale. C'est elle qui gère tous les événements déclenchés par les clics de l'utilisateur dans la fenêtre et qui créé les images (objets de la classe JImage) à afficher à l'écran.

· dialogDeb (3) :

Il s'agit de la fenêtre d'accueil du programme avec les logos des laboratoires et des boutons pour choisir une saison à consulter. Cette classe possède quatre classes internes qui sont les quatre panneaux servant à afficher les logos. Une fois que l'utilisateur a cliqué sur un des boutons, la fenêtre principale s'ouvre à la place et affiche la 1ère image du 1er événement pour l'année sélectionnée. Si l'on ferme cette fenêtre sans cliquer sur un des boutons, le programme est alors arrêté.

· listEv (4) :

C'est le panneau se trouvant à gauche de l'écran avec les listes déroulantes permettant de choisir un événement et une image. Selon l'image sélectionnée dans la liste il renvoit à la fenêtre principale la nouvelle image à afficher.

· JImage (5) :

Cette classe est un panneau comportant l'image radar à afficher. Elle dessine à l'écran l'image suivant les données d'un objet de la classe ImageRadar. Si l'utilisateur demande à enregistrer

l'image à afficher, elle gère la conversion en PNG (en appelant des fonctions de la librairie PNG Encoder) et sauve le fichier sur le disque.

· Evénement (6) :

Classe qui comporte les attributs propres à un événement et possède une fonction de recherche d'un événement dans un des fichiers de la base à partir d'une date donnée.

(1) Cf. Annexe 2 page 46 pour le code commenté

(2) Cf. Annexe 2 page 38 pour le code commenté

(3) Cf. Annexe 2 page 40 pour le code commenté

(4) Cf. Annexe 2 page 42 pour le code commenté

(5) Cf. Annexe 4 page 49 un extrait de code commenté

(6) Cf. Annexe 3 page 47 pour le code commenté

· ImageRadar :

De même que la classe Evènement elle contient les attributs d'une image radar et possède des fonctions de recherche d'images dans les fichiers binaires. Elle a en plus une fonction qui permet de créer l'image à afficher, c'est-à-dire qu'elle crée un vecteur d'objets de la classe Radiale. Le traitement des points à afficher se fait dans cette dernière classe.

· Radiale :

Cette classe traite chaque porte d'une radiale et transforme les coordonnées polaires en coordonnées cartésiennes. De plus elle affecte une couleur par porte suivant la réflectivité de celle-ci. Ainsi elle crée un tableau d'objets de la classe Ligne qui sont en fait les lignes à afficher à l'écran.

· Ligne :

La classe Ligne possède cinq attributs qui sont : l'abscisse d'origine de la ligne, l'ordonnée d'origine, l'abscisse de destination, l'ordonnée de destination et la couleur de la ligne. Une ImageRadar est en fait constituée de plusieurs Radiale comportant un ensemble de Ligne et c'est la classe JImage (qui est le panneau d'affichage) qui va finalement parcourir l'ensemble des lignes et les dessiner selon les coordonnées et la couleur données.

· Anim :

Cette classe qui n'est pas encore achevée est un panneau où sera affiché une animation radar. Elle implémente l'interface "Runnable" c'est-à-dire qu'elle peut utiliser des "threads".

Badora.java

import javax. swing.*; import j avax. swing. event. *;

import java.awt.*; import java.awt.event.*;

import java.io.*; import java.util.*; import java.text.*;

// +++++++++++++++++++++++++ // ++ Classe Interface ++ // +++++++++++++++++++++++++

class Interface extends JFrame implements ActionListener {

77 Attributs privés

private JImage jim;

private JMenuBar barreMenus = new JMenuBar(); private JMenuItem enrImage, quitter, apropos; private JToolBar barreOutils = new JToolBar(); private JButton ok = new JButton("OK");

private JButton enreg = new JButton (new ImageIcon ("disquette.gif"));

private JButton precedent = new JButton (new ImageIcon ("left.gif"));

private JButton suivant = new JButton (new ImageIcon ("right.gif"));

private JButton anim = new JButton (new ImageIcon ("anim.gif"));

private JComboBox saisons = new JComboBox(); private JLabel choix = new JLabel ("Saison : "); private JPanel contenu;

private listEv listev;

private short saisonEnCours;

77 ************************ 77 * Méthodes publiques * 77 ************************

77
77 *** Constructeur ***

77

public Interface ()

{

// Fenêtre d'ouverture

dialogDeb fenDeb = new dialogDeb (this); modifSaisonEnCours (fenDeb. saison ());

// Initialisation de la fenêtre principale setBounds (20, 20, 800, 600);

setTitle(" --== B A D O R A ==-- ");

setDefaultCloseOperation (JFrame.EXIT _ON _CLOSE); contenu = (JPanel)getContentPane();

contenu.setLayout (new BorderLayout ());

// Barre de menus

setJMenuBar (barreMenus);

JMenu mFichier = new JMenu ("Fichier"); barreMenus.add (mFichier);

JMenuItem enrImage = new JMenuItem ("Enregistrer image");

JMenuItem quitter = new JMenuItem ("Quitter");

mFichier.add (enrImage);

mFichier.add (quitter);

enrImage.addActionListener (this); quitter.addActionListener (this); JMenu mAide = new JMenu ("Aide"); barreMenus.add (mAide);

JMenuItem apropos = new JMenuItem ("A propos de");

mAide.add (apropos);

apropos.addActionListener (this);

// Barres d'outils

barreOutils.add (enreg);

enreg.addActionListener (this); barreOutils.add (precedent);

precedent.addActionListener (this); barreOutils.add (suivant);

suivant.addActionListener (this); barreOutils.add (anim);

anim.addActionListener (this);

// Panneaux

JPanel nord = new JPanel (new FlowLayout(FlowLayout.LEFT)); nord.add (choix);

nord.add(saisons);

nord.add (ok);

nord.add (barreOutils);

String[] sais = { "Saison 1990", "Saison 1991", "Saison 1992", "Saison 1993" };

for (int i=0; i < 4; i++) saisons.addItem(sais[ i]);

ok.addActionListener (this);

switch (saisonEnCours)

{

case 1991 : saisons.setSelectedIndex(1);

jim = new JImage(7, 6, saisonEnCours, 6, 50, 2);

break;

case 1992 : saisons.setSelectedIndex(2);

jim = new JImage(20, 6, saisonEnCours, 4, 20, 35);

break;

case 1993 : saisons.setSelectedIndex(3);

jim = new JImage(6, 6, saisonEnCours, 2, 50, 50);

break;

default : saisons.setSelectedIndex(0);

jim = new JImage(8, 6, saisonEnCours, 0, 7, 40);

}

jim.setPreferredSize (new Dimension(100, 100)); listev = new listEv (this, saisonEnCours);

contenu.add ("North", nord); contenu.add ("West", listev); contenu.add("Center", jim);

} // fin Constructeur

//
// *** Méthodes de mise à jour ***

//

public void update (JImage jimage)

{

// met à jour l 'image à afficher

contenu.remove (jim);

jim = jimage;

jim.setPreferredSize (new Dimension(100, 100));

contenu.add ("Center", jim);

contenu . repaint ();

}

public void actionPerformed (ActionEvent ev)

{

if (ev.getSource() == ok)

{

// Modification de la saison en cours choisie Object annee = saisons.getSelectedItem(); if ((String) annee == "Saison 1990")

modifSaisonEnCours((short)1990);

else if ((String) annee == "Saison 1991")
modifSaisonEnCours ((short) 1991);

else if ((String) annee == "Saison 1992") modifSaisonEnCours((short)1992);

else if ((String) annee == "Saison 1993") modifSaisonEnCours((short)1993);
contenu.remove (listev);

listev = new listEv (this, saisonEnCours);

contenu.add ("West", listev);

setVisible (true);

}

else if (ev.getSource() == precedent)

{

if (listev.listim().getSelectedIndex() != 0)

{

// recule d'une image et met à jour l'interface ImageRadar im = new ImageRadar();

im = jim.image().getImagePrec();

jim = new JImage (im);

update (jim);

listev. reculListim();

}

}

else if (ev.getSource() == suivant)

{

// avance d'une image et met à jour l'interface

if (listev.listim().getSelectedIndex() != (listev.listim() .getItemCount()-1)) {

ImageRadar im = new ImageRadar();

im = jim.image().getImageSuiv();

contenu . remove (this. jim);

jim = null;

jim = new JImage (im);

if (jim.imRadar() == null) System.out.println("null imrad");

listev. avanceListim(); update (jim);

}

}

else if (ev.getSource() == anim)

{

// création d'une animation pour un événement Object dat = listev.listev() .getSelectedItem(); String d = (String) dat;

int jour = Integer.parseInt (d.charAt(0) + "" + d.charAt(1));

int mois = Integer.parseInt (d.charAt(3) + "" + d.charAt(4));

int annee = Integer.parseInt (d.charAt(6) + "" + d.charAt(7) + "" + d.charAt(8) + "" + d.charAt(9));

int heure = Integer.parseInt (d.charAt(11) + "" + d.charAt(12)); int min = Integer.parseInt (d.charAt(14) + "" + d.charAt(15)); int sec = Integer.parseInt (d.charAt(17) + "" + d.charAt(18));

Evenement evt = new Evenement();

evt = evt.getEvenement (jour, mois, annee, heure, min, sec); Anim anim = new Anim (this, evt);

}

// gestion des événements liés aux menus

if (ev.getSource()instanceof JMenuItem |ev.getSource() == enreg) {

String ChoixOption = ev.getActionCommand();

if (ChoixOption.equals("Quitter"))

{

dispose(); // destruction de la fenêtre principale
System.exit (0);

}

else if (ChoixOption.equals("Enregistrer image") || ev.getSource() == enreg)

{

FileDialog fenEnr = new FileDialog (this, "Enregistrer image", FileDialog. SAVE);

fenEnr.setFile(".png");

fenEnr.show();

String nomFich = fenEnr.getFile();

if(nomFich!=null)

{

File fichier=new File(fenEnr.getDirectory()+nomFich); jim. saveImage (fichier);

}

}

else if (ChoixOption.equals("A propos de"))

{

JOptionPane.showMessageDialog (this, "A propos de Badora\n\n Auteur : Stéphane Clerc\n. .2003", "A propos de B A D O R A",

JOptionPane. INFORMATION _MESSAGE);

}

}

}

public void modifSaisonEnCours (short annee)

{

saisonEnCours = annee;

System.out.println("New saison : " + saisonEnCours);

}

} // fin Classe Interface

// ++++++++++++++++++++++++ // ++ Classe dialogDeb ++ // ++++++++++++++++++++++++

class dialogDeb extends JDialog implements ActionListener {

private short saison;

JButton sais90 = new JButton ("Saison 1990"); JButton sais91 = new JButton ("Saison 1991"); JButton sais92 = new JButton ("Saison 1992"); JButton sais93 = new JButton ("Saison 1993");

private JLabel choix = new JLabel ("Choisissez une saison : ");

private Toolkit kit = Toolkit.getDefaultToolkit(); private Image logoLthe = kit.getImage ("logo _lthe.gif"); private Image logoIrd = kit.getImage ("logo _ird.gif"); private Image logoCatch = kit.getImage ("logo _catch.gif");

private Image logoAmma = kit.getImage ("logo _amma.gif");

private LogoLthe panLthe = new LogoLthe (); private LogoIRD panIRD = new LogoIRD(); private LogoCatch panCatch = new LogoCatch(); private LogoAmma panAmma = new LogoAmma();

// ********************** // * Méthodes publiques * // **********************

//
// *** Constructeur ***

//

public dialogDeb (JFrame parent)

{

// configuration de la fenêtre et des différents panneaux super (parent, "Bienvenue sur BADORA", true);

setBounds (300, 300, 500, 330);

JPanel contenu = (JPanel) getContentPane();

contenu . setLayout (new BorderLayout ()); contenu.setBackground (new Color (255, 218, 185));

JPanel center = new JPanel(); center.setBackground (new Color (255, 218, 185));

panLthe.setPreferredSize (new Dimension(116, 107)); panIRD.setPreferredSize (new Dimension(120, 100)); panCatch.setPreferredSize (new Dimension(100, 100)); panAmma.setPreferredSize (new Dimension(100, 100));

GridBagLayout grille = new GridBagLayout();

GridBagConstraints constraints = new GridBagConstraints(); center. setLayout (grille);

buildConstraints (constraints, 0, 0, 1, 1, 20, 20); grille.setConstraints (choix, constraints);

buildConstraints (constraints, 0, 1, 1, 1, 20, 20); grille.setConstraints (sais90, constraints);

buildConstraints (constraints, 0, 2, 1, 1, 20, 20); grille.setConstraints (sais91, constraints);

buildConstraints (constraints, 0, 3, 1, 1, 20, 20); grille.setConstraints (sais92, constraints);

buildConstraints (constraints, 0, 4, 1, 1, 20, 20); grille.setConstraints (sais93, constraints);

center.add (choix);

contenu.add ("West", panLthe);

contenu.add ("East", panIRD);

center.add (sais90); sais90.addActionListener (this); center.add (sais91); sais91.addActionListener (this); center.add (sais92); sais92.addActionListener (this); center.add (sais93); sais93.addActionListener (this); contenu.add ("Center", center);

contenu.add ("South", panCatch);

contenu.add ("South", panAmma);

setVisible (true);

}

//
// *** Méthodes de mise à jour ***

//

public void actionPerformed (ActionEvent ev)

{

// Mise à jour de la saison en cours

if (ev.getSource() == sais90) saison = 1990;

else if (ev.getSource() == sais91) saison = 1991; else if (ev.getSource() == sais92) saison = 1992; else if (ev.getSource() == sais93) saison = 1993; setVisible (false);

}

public void buildConstraints (GridBagConstraints gbc, int gx, int gy, int gw, int gh, int wx, int

wy)

{

// Mise à jour des contraintes de la grille du panneau central

gbc.gridx = gx; gbc.gridy = gy; gbc.gridwidth = gw; gbc.gridheight = gh; gbc.weightx = wx; gbc.weighty = wy;

}

//
// *** Méthodes de consultation ***

//

public short saison()

{

return saison;

}

// +++++++++++++++++++++++++ // ++ Classes Logos ++ // +++++++++++++++++++++++++

// Classes internes à dialogDeb gérant les panneaux des logos

class LogoLthe extends JPanel

{

public void paintComponent (Graphics g) {

Graphics2D g2D = (Graphics2D)g;
g2D.drawImage (logoLthe, 0,0, this);

}

}

class LogoIRD extends JPanel

{

public void paintComponent (Graphics g) {

Graphics2D g2D = (Graphics2D)g; g2D.drawImage (logoIrd, 0,0,this);

}

}

class LogoCatch extends JPanel

{

public void paintComponent (Graphics g)

{

Graphics2D g2D = (Graphics2D)g; g2D.drawImage (logoCatch, 0,0,this);

}

}

class LogoAmma extends JPanel

{

public void paintComponent (Graphics g)

{

Graphics2D g2D = (Graphics2D)g;

g2D.drawImage (logoAmma, 0,0,this);

}

}

} // fin Classe dialogDeb

// +++++++++++++++++++++++++ // ++ Classe listEv ++ // +++++++++++++++++++++++++

class listEv extends JPanel implements ActionListener {

// Attributs privés

private JLabel choixEv = new JLabel ("Choisissez un événement : ",JLabel.LEFT); private JLabel choixIm = new JLabel ("Images : ",JLabel.LEFT);

private JComboBox listev = new JComboBox(); private JComboBox listim = new JComboBox(); private Interface fen;

// ********************** // * Méthodes publiques * // **********************

//
// *** Constructeur ***

//

public listEv (Interface parent, int annee)
{

// Configuration du panneau de gauche de l 'interface setPreferredSize (new Dimension (180,170)); setLayout (new FlowLayout(FlowLayout.LEFT));

setBorder (BorderFactory. createLineBorder (Color. yellow));

fen = parent;

Vector datesEv = getListEvt (annee); Vector datesIm = new Vector();

int i=0;

int j = 0, m = 0, a = 0, h = 0, min = 0, sec = 0; DecimalFormat df = new DecimalFormat("00");

// Création de la liste des événements

for (Enumeration enum = datesEv.elements(); enum.hasMoreElements();) {

GregorianCalendar date = (GregorianCalendar) enum.nextElement(); j = date.get(Calendar.DAY _OF _MONTH);

m = date.get(Calendar.MONTH);

a = date.get(Calendar.YEAR);

h = date.get(Calendar.HOUR_OF _DAY);

min = date.get(Calendar.MINUTE);

sec = date.get(Calendar.SECOND);

listev.addItem (df.format(j) + "/" + df.format(m) + "/" + df.format(a) + " " + df.format(h) + ":" + df.format(min) + ":" + df.format(sec));

if (i == 0)

{

datesIm = getListIm (j, m, a, h, min, sec); System.out.println("date : " + j + m + a + h + min + sec);

} i++;

}

listev.setMaximumRowCount (10);

// Création de liste des images

for (Enumeration enum = datesIm.elements(); enum.hasMoreElements();)

{

GregorianCalendar date = (GregorianCalendar) enum.nextElement();

j = date.get(Calendar.DAY _OF _MONTH); m = date.get(Calendar.MONTH); a = date.get(Calendar.YEAR); h = date.get(Calendar.HOUR_OF _DAY); min = date.get(Calendar.MINUTE); sec = date.get(Calendar.SECOND);

listim.addItem (df.format(j) + "/" + df.format(m) + "/" + df.format(a) + " " + df.format(h) + ":" + df.format(min) + ":" + df.format(sec));

}

add (choixEv);

add(Box.createRigidArea(new Dimension(180,5))); add (listev);

add(Box.createRigidArea(new Dimension(180,5))); add (choixIm);

add(Box.createRigidArea(new Dimension(180,5))); add (listim);

listev.addActionListener (this);

listim.addActionListener (this);

}

//
// *** Méthodes de mise à jour ***

//

public void actionPerformed (ActionEvent evt)

{

if (evt.getSource() == listev)

{

// Mise à jour de la liste des événements et de la liste des images Object dat = listev.getSelectedItem();

String d = (String) dat;

listim.removeAllItems ();

int jour = Integer.parseInt (d.charAt(0) + "" + d.charAt(1)); int mois = Integer.parseInt (d.charAt(3) + "" + d.charAt(4));

int annee = Integer.parseInt (d.charAt(6) + "" + d.charAt(7) + "" + d.charAt(8) + "" + d.charAt(9));

int heure = Integer.parseInt (d.charAt(11) + "" + d.charAt(12)); int min = Integer.parseInt (d.charAt(14) + "" + d.charAt(15)); int sec = Integer.parseInt (d.charAt(17) + "" + d.charAt(18)); DecimalFormat df = new DecimalFormat("00");

Vector datesIm = getListIm (jour, mois, annee, heure, min, sec);

for (Enumeration enum = datesIm.elements(); enum.hasMoreElements ();)

{

GregorianCalendar date = (GregorianCalendar) enum.nextElement();

jour = date. get (Calendar. DAY_OF_MONTH); mois = date.get(Calendar.MONTH); annee = date.get(Calendar.YEAR); heure = date.get(Calendar.HOUR_OF _DAY); min = date.get(Calendar.MINUTE); sec = date.get(Calendar.SECOND);

listim.addItem (df.format(jour) + "/" + df.format(mois) + "/" + df.format(annee) + " " + df.format(heure) + ":" + df.format(min) + ":" + df. format (sec));

}

add(listim);

setVisible (true);

}

if (evt.getSource() == listim)

{

// Mise à jour de la liste des images et de l 'affichage de l 'image // en cours Object dat = listim.getSelectedItem();

String d = (String) dat;

int jour = Integer.parseInt (d.charAt(0) + "" + d.charAt(1)); int mois = Integer.parseInt (d.charAt(3) + "" + d.charAt(4));

int annee = Integer.parseInt (d.charAt(6) + "" + d.charAt(7) + "" + d.charAt(8) + "" + d.charAt(9));

int heure = Integer.parseInt (d.charAt(11) + "" + d.charAt(12)); int min = Integer.parseInt (d.charAt(14) + "" + d.charAt(15)); int sec = Integer.parseInt (d.charAt(17) + "" + d.charAt(18));

JImage jim = new JImage (jour, mois, annee, heure, min, sec); fen.update (jim);

}

}

public void reculListim()

{

listim.setSelectedIndex (listim.getSelectedIndex() - 1);

}

public void avanceListim()

{

listim.setSelectedIndex (listim.getSelectedIndex() + 1);

}

//
// *** Méthodes de consultation ***

//

public JComboBox listim()

{

return listim;

}

public JComboBox listev()

{

return listev;

}

public Vector getListEvt (int annee)

{

// Création d'un vecteur avec la liste des événements Evenement ev = new Evenement();

int nbevts = 0;

Vector dates = new Vector();

System.out.println("ListEvt : " + annee);

try

{

RandomAccessFile fbase = null;

switch (annee)

{

case 1990 : fbase = new RandomAccessFile (". ./. . /bdr90.dat", "r"); nbevts = 22; break;

case 1991 : fbase = new RandomAccessFile (". ./. . /bdr91.dat", "r"); nbevts = 27; break;

case 1992 : fbase = new RandomAccessFile("../../bdr92.dat", "r"); nbevts = 39; break;

case 1993 : fbase = new RandomAccessFile("../../bdr93.dat", "r"); nbevts = 32; break;

default : System.out.println ("ERREUR : Année non valide");

}

byte jd = 0, jf, md = 0, mf, hd, hf, mind, minf, sd, sf, nbim = 0; short ad, af, nbrad;

boolean trouve = false;

int num = 0; fbase. seek (num);

for (int e=0; e < nbevts; e++)

{

jd = fbase.readByte(); md = fbase.readByte(); ad = fbase.readShort(); hd = fbase.readByte(); mind = fbase.readByte(); sd = fbase.readByte(); jf = fbase.readByte();

mf = fbase.readByte(); af = fbase.readShort(); hf = fbase.readByte(); minf = fbase.readByte(); sf = fbase.readByte(); nbim = fbase.readByte();

GregorianCalendar dateDeb = new GregorianCalendar (ad, md, jd, hd, mind, sd);

GregorianCalendar dateFin = new GregorianCalendar (af, mf, jf, hf, minf, sf);

ev = new Evenement (dateDeb, dateFin, nbim, num);

dates. add (dateDeb);

fbase.seek (num += 15);

for (int i=0; i < nbim; i++)

{

fbase.seek (num += 16);

nbrad = fbase.readShort();

fbase.seek (num += 3);

fbase.seek (num += (nbrad*520)); } // fin Boucle des images d'un événement

} // fin Boucle des Evenements fbase.close();

} // fin du Try

catch (Exception e)

{

System.out.println (e.toString());

}

return dates; } // fin getListEvt

public Vector getListIm (int jour, int mois, int annee, int heure, int minute, int seconde)

{

// Création d'un vecteur avec la liste des images

Evenement ev = new Evenement();

ev = ev.getEvenement (jour, mois, annee, heure, minute, seconde);

int num = ev.positionFich(); Vector dates = new Vector();

try

{

RandomAccessFile fbase = null;

if (annee == 1990) fbase = new RandomAccessFile("../../bdr90.dat", "r");

else if (annee == 1991) fbase = new RandomAccessFile("../../bdr91.dat", "r"); else if (annee == 1992) fbase = new RandomAccessFile("../../bdr92.dat", "r"); else if (annee == 1993) fbase = new RandomAccessFile("../../bdr93.dat", "r"); else System.out.println ("ERREUR : Année non valide");

byte j, m, h, min, sec; short a, nbrad;

fbase.seek (num);

for (int i=0; i < ev.nbImages(); i++) {

j = fbase.readByte(); m = fbase.readByte(); a = fbase.readShort(); h = fbase.readByte(); min = fbase.readByte(); sec = fbase.readByte();

GregorianCalendar date = new GregorianCalendar (a, m, j, h, min, sec); dates.add (date);

fbase.seek (num += 16); nbrad = fbase.readShort(); fbase.seek (num += 3); fbase.seek (num += (nbrad*520));

}

fbase.close();

} // fin du Try

catch (Exception e)

{

System.out.println (e.toString());

}

return dates; } // fin getListIm

} // fin Classe listEv

// ++++++++++++++++++++++++++++ // ++ Classe Badora : Main ++ // ++++++++++++++++++++++++++++

public class Badora {

public static void main (String[] args)

{

Interface fen = new Interface(); fen. setVisible (true);

}

} // fin Classe Badora

Evenement.j ava

import java.util.*; import java.io.*;

public class Evenement {

// Attributs privés

private GregorianCalendar dateDeb; private GregorianCalendar dateFin; private int nbImages;

private int positionFich; // octet de position du début de l'événement dans le fichier

77 ************************ 77 * Méthodes publiques * 77 ************************

77
77 *** Constructeurs ***

77

public Evenement ()

{

dateDeb = null; dateFin = null; nbImages = 0; positionFich = 0;

}

public Evenement (GregorianCalendar dd, GregorianCalendar df, int nbim , int pos)

{

dateDeb = dd; dateFin = df; nbImages = nbim; positionFich = pos;

}

77
77 *** Méthodes d'affichage ***

77

public void afficheInfos()

{

System.out.println("-= Evenement : =-");

System.out.print("Date début: " + dateDeb.get(Calendar.DAY _OF _MONTH) + "7" + dateDeb.get(Calendar.MONTH) + "7" + dateDeb.get(Calendar.YEAR)); System.out.println (" " + dateDeb.get(Calendar.HOUR_OF _DAY) + ":" + dateDeb.get(Calendar.MINUTE) + ":" + dateDeb.get(Calendar.SECOND)); System.out.print ("Date fin : " + dateFin.get(Calendar.DAY _OF _MONTH) + "7" + dateFin.get(Calendar.MONTH) + "7" + dateFin.get(Calendar.YEAR)); System.out.println (" " + dateFin.get(Calendar.HOUR_OF _DAY) + ":" + dateFin.get(Calendar.MINUTE) + ":" + dateFin.get(Calendar.SECOND)); System.out.println("Nombre d'images : " + nbImages);

}

public void ajoutImage(GregorianCalendar date, ImageRadar im)

{

images.put (date, im);

}

77
77 *** Méthodes de consultation ***

77

public int nbImages()

{

return nbImages;

}

public int positionFich()

{

return positionFich;

}

public Evenement getEvenement(int jour, int mois, int annee, int heure, int minute, int sec) {

// Recherche d'un événement pour une date donnée

Evenement ev = new Evenement();

try

{

// Ouverture du fichier selon l'année

RandomAccessFile fbase = null;

if (annee == 1990) fbase = new RandomAccessFile("..7..7bdr90.dat", "r");

else if (annee == 1991) fbase = new RandomAccessFile("../../bdr91.dat", "r"); else if (annee == 1992) fbase = new RandomAccessFile("../../bdr92.dat", "r"); else if (annee == 1993) fbase = new RandomAccessFile("../../bdr93.dat", "r"); else System.out.println ("ERREUR : Année non valide");

byte jd = 0, jf, md = 0, mf, hd = 0, hf, mind = 0, minf, sd = 0, sf, nbim = 0; short ad = 0, af, nbrad;

boolean trouve = false;

// Début du fichier int num = 0;

fbase. seek (num);

while (!trouve)

{

// lecture du jour du 1er événement jd = fbase.readByte();

while (jd != jour)

{

// on saute jusqu'à l'événement suivant

fbase.seek (num += 14); nbim = fbase.readByte(); fbase.seek (num += 17);

for (int i=0; i < nbim; i++) {

nbrad = fbase.readShort();

fbase.seek(num += 3);

fbase.seek (num += (nbrad*520));

fbase.seek (num += 5);

fbase.seek (num += 11);

}

fbase.seek (num -= 16); jd = fbase.readByte();

}

if (jd == jour)

{

// on vérifie que c'est bien l'événement recherché

md = fbase.readByte(); ad = fbase.readShort(); hd = fbase.readByte(); mind = fbase.readByte(); sd = fbase.readByte();

if (md == mois && hd == heure && mind == minute && sd == sec)

trouve = true;

}

}

if (trouve)

{

// si le bon événement : lecture de tous ses champs

jf = fbase.readByte(); mf = fbase.readByte(); af = fbase.readShort(); hf = fbase.readByte(); minf = fbase.readByte(); sf = fbase.readByte(); nbim = fbase.readByte(); num += 15;

sd); sf);

GregorianCalendar dateDeb = new GregorianCalendar (ad, md, jd, hd, mind, GregorianCalendar dateFin = new GregorianCalendar (af, mf, jf, hf, minf,

ev = new Evenement (dateDeb, dateFin, nbim, num);

}

fbase.close();

} // fin du Try

catch (Exception e)

{

System.out.println (e.toString());

}

ev.afficheInfos ();

return ev;

} // fin getEvenement

} // fin Classe Evenement

{

case

0 :

g.setColor

(new Color(221, 160, 221)); break;

case

1 :

g.setColor

(Color.magenta); break;

case

2 :

g.setColor

(new Color(255, 20, 147)); break;

case

3 :

g.setColor

(Color.blue); break;

case

4 :

g.setColor

(new Color(0, 0, 139)); break;

case

5 :

g.setColor

(new Color(34, 139, 34)); break;

case

6 :

g.setColor

(new Color(50, 205, 50)); break;

case

7 :

g.setColor

(new Color(0, 255, 0)); break;

case

8 :

g.setColor

(new Color(255, 140, 0)); break;

case

9 :

g.setColor

(new Color(205, 133, 63)); break;

case

10 :

g.setColor

(new Color(199, 21, 133)); break;

JImage.java

import java.awt.*;

import java.awt.image.*; import java.awt.event.*; import javax. swing.*; import java.util.*;

import java.io.*;

import java.lang.*;

import com. keypoint.*;

// +++++++++++++++++++++++++ // ++ Classe JImage ++ // +++++++++++++++++++++++++

public class JImage extends JPanel

{

// Attributs privés

private Image imRadar = null;

private ImageRadar image = new ImageRadar();

// ************************ // * Méthodes publiques * // ************************

//
// *** Constructeurs ***

//

public JImage (int jour, int mois, int annee, int heure, int min, int sec)

{

super();

image = image.getImage(jour, mois, annee, heure, min, sec);

image. afficheInfos ();

setBackground (Color.black);

setBorder (BorderFactory. createLineBorder (Color. red));

repaint();

}

public JImage (ImageRadar im)

{

super();

image = im;

image. afficheInfos ();

setBackground(Color.black);

setBorder (BorderFactory. createLineBorder (Color.red));

repaint();

}

//

// *** Méthodes de mise à jour ***

//

public void drawImageRadar (Vector pixels) {

// dessin de l'image radar

Graphics g0 = getGraphics(); Graphics2D g =(Graphics2D) g0;

// création d'un buffer image pour stocker temporairement l'image

Buf feredImage imTemp = new BufferedImage(450, 450,BufferedImage. TYPE _INT _RGB); g = imTemp.createGraphics();

g.setBackground (Color.black);

// parcours des lignes à dessiner avec attribution de la couleur (tableau pixels) for (Enumeration enum = pixels.elements(); enum.hasMoreElements();)

{

case 11 : g.setColor (Color.red); break;

case 12 : g.setColor (new Color(220, 220, 220)); break; case 13 : g.setColor (Color.black); break; case 14 : g.setColor (Color.white); break; default : g.setColor (getBackground()); break;

}

// dessin de la ligne

g.drawLine (jpix.xOrigine(), jpix.yOrigine(), jpix.xDestin(),

jpix.yDestin());

}

g.setColor (Color.white);

// dessin des cercles concentriques donnant la distance

int[ ] reso = { 250, 500, 750};

int nbkm = (reso[ image.resolution()] * 512) / 1000;

int nbcercles = (int) nbkm / 50;

int hauteur = (int) (50 * 450 / nbkm / 1.5);

int hautinit = hauteur;

for (int i=0; i < nbcercles; i++)

{

g.drawOval (225-(hauteur/2) ,225-(hauteur/2) , hauteur, hauteur); hauteur = hauteur + hautinit;

}

g.rotate(Math.toRadians (90)); imRadar = imTemp;

} // fin de drawImageRadar

public void paintComponent (Graphics g)

{

// Méthode qui affiche l'image à l'écran

Graphics2D g2D = (Graphics2D)g;

g2D.clearRect(0,0,getSize() .width,getSize() .height); g2D. setColor (Color. lightGray); g2D.fillRect(0,0,getSize().width,getSize().height);

setBorder (BorderFactory. createLineBorder (Color. red));

if (imRadar == null)

{

// création de l 'image

imRadar = createImage(getWidth() ,getHeight ());

Vector pixels = new Vector();

pixels = image.afficheImageMatrice (256);

drawImageRadar (pixels);

}

// affichage de l 'image au centre l 'écran

g2D.drawImage(imRadar, (getWidth()/2)-(imRadar.getWidth(this) /2), (getHeight() /2)- (imRadar . getHeight (this) /2) ,this);

if (message != null)

{

g2D.drawString( message, 10, 10 );

}
} // fin de paint

} // fin Classe Jimage

GNU Free Documentation License Version 1.2 November 2002

Copyright (C) 2000,2001,2002 Free Software Foundation, Inc.

59 Temple Place, Suite 330, Boston, MA 02111-1307 USA Everyone is permitted to copy and distribute verbatim copies of this license document, but changing it is not allowed.

0. PREAMBLE

The purpose of this License is to make a manual, textbook, or other functional and useful document "free" in the sense of freedom: to assure everyone the effective freedom to copy and redistribute it, with or without modifying it, either commercially or noncommercially. Secondarily, this License preserves for the author and publisher a way to get credit for their work, while not being considered responsible for modifications made by others.

This License is a kind of "copyleft", which means that derivative

works of the document must themselves be free in the same sense. It complements the GNU General Public License, which is a copyleft license designed for free software.

We have designed this License in order to use it for manuals for free software, because free software needs free documentation: a free program should come with manuals providing the same freedoms that the software does. But this License is not limited to software manuals; it can be used for any textual work, regardless of subject matter or whether it is published as a printed book. We recommend this License principally for works whose purpose is instruction or reference.

1. APPLICABILITY AND DEFINITIONS

This License applies to any manual or other work, in any medium, that contains a notice placed by the copyright holder saying it can be distributed under the terms of this License. Such a notice grants a world-wide, royalty-free license, unlimited in duration, to use that work under the conditions stated herein. The "Document", below, refers to any such manual or work. Any member of the public is a licensee, and is addressed as "you". You accept the license if you copy, modify or distribute the work in a way requiring permission under copyright law.

A "Modified Version" of the Document means any work containing the Document or a portion of it, either copied verbatim, or with

modifications and/or translated into another language.

A "Secondary Section" is a named appendix or a front-matter section of the Document that deals exclusively with the relationship of the publishers or authors of the Document to the Document's overall subject (or to related matters) and contains nothing that could fall directly within that overall subject. (Thus, if the Document is in part a textbook of mathematics, a Secondary Section may not explain any mathematics.) The relationship could be a matter of historical connection with the subject or with related matters, or of legal, commercial, philosophical, ethical or political position regarding them.

The "Invariant Sections" are certain Secondary Sections whose titles are designated, as being those of Invariant Sections, in the notice that says that the Document is released under this License. If a section does not fit the above definition of Secondary then it is not allowed to be designated as Invariant. The Document may contain zero Invariant Sections. If the Document does not identify any Invariant Sections then there are none.

The "Cover Texts" are certain short passages of text that are listed,

as Front-Cover Texts or Back-Cover Texts, in the notice that says that the Document is released under this License. A Front-Cover Text may be at most 5 words, and a Back-Cover Text may be at most 25 words.

A "Transparent" copy of the Document means a machine-readable copy, represented in a format whose specification is available to the general public, that is suitable for revising the document

straightforwardly with generic text editors or (for images composed of pixels) generic paint programs or (for drawings) some widely available drawing editor, and that is suitable for input to text formatters or for automatic translation to a variety of formats suitable for input to text formatters. A copy made in an otherwise Transparent file

format whose markup, or absence of markup, has been arranged to thwart or discourage subsequent modification by readers is not Transparent. An image format is not Transparent if used for any substantial amount of text. A copy that is not "Transparent" is called "Opaque".

Examples of suitable formats for Transparent copies include plain ASCII without markup, Texinfo input format, LaTeX input format, SGML or XML using a publicly available DTD, and standard-conforming simple HTML, PostScript or PDF designed for human modification. Examples of transparent image formats include PNG, XCF and JPG. Opaque formats

include proprietary formats that can be read and edited only by proprietary word processors, SGML or XML for which the DTD and/or processing tools are not generally available, and the

machine-generated HTML, PostScript or PDF produced by some word processors for output purposes only.

The "Title Page" means, for a printed book, the title page itself,

plus such following pages as are needed to hold, legibly, the material this License requires to appear in the title page. For works in

formats which do not have any title page as such, "Title Page" means the text near the most prominent appearance of the work's title, preceding the beginning of the body of the text.

A section "Entitled XYZ" means a named subunit of the Document whose title either is precisely XYZ or contains XYZ in parentheses following text that translates XYZ in another language. (Here XYZ stands for a specific section name mentioned below, such as "Acknowledgements", "Dedications", "Endorsements", or "History".) To "Preserve the Title"

of such a section when you modify the Document means that it remains a section "Entitled XYZ" according to this definition.

The Document may include Warranty Disclaimers next to the notice which states that this License applies to the Document. These Warranty Disclaimers are considered to be included by reference in this License, but only as regards disclaiming warranties: any other implication that these Warranty Disclaimers may have is void and has no effect on the meaning of this License.

2. VERBATIM COPYING

You may copy and distribute the Document in any medium, either commercially or noncommercially, provided that this License, the copyright notices, and the license notice saying this License applies

to the Document are reproduced in all copies, and that you add no other conditions whatsoever to those of this License. You may not use technical measures to obstruct or control the reading or further copying of the copies you make or distribute. However, you may accept compensation in exchange for copies. If you distribute a large enough number of copies you must also follow the conditions in section 3.

You may also lend copies, under the same conditions stated above, and you may publicly display copies.

If you publish printed copies (or copies in media that commonly have printed covers) of the Document, numbering more than 100, and the Document's license notice requires Cover Texts, you must enclose the copies in covers that carry, clearly and legibly, all these Cover Texts: Front-Cover Texts on the front cover, and Back-Cover Texts on the back cover. Both covers must also clearly and legibly identify you as the publisher of these copies. The front cover must present the full title with all words of the title equally prominent and visible. You may add other material on the covers in addition. Copying with changes limited to the covers, as long as they preserve the title of the Document and satisfy these conditions, can be treated as verbatim copying in other respects.

If the required texts for either cover are too voluminous to fit legibly, you should put the first ones listed (as many as fit reasonably) on the actual cover, and continue the rest onto adjacent pages.

If you publish or distribute Opaque copies of the Document numbering more than 100, you must either include a machine-readable Transparent copy along with each Opaque copy, or state in or with each Opaque copy a computer-network location from which the general network-using public has access to download using public-standard network protocols a complete Transparent copy of the Document, free of added material. If you use the latter option, you must take reasonably prudent steps, when you begin distribution of Opaque copies in quantity, to ensure that this Transparent copy will remain thus accessible at the stated location until at least one year after the last time you distribute an Opaque copy (directly or through your agents or retailers) of that edition to the public.

It is requested, but not required, that you contact the authors of the Document well before redistributing any large number of copies, to give them a chance to provide you with an updated version of the Document.

4. MODIFICATIONS

You may copy and distribute a Modified Version of the Document under the conditions of sections 2 and 3 above, provided that you release the Modified Version under precisely this License, with the Modified Version filling the role of the Document, thus licensing distribution and modification of the Modified Version to whoever possesses a copy of it. In addition, you must do these things in the Modified Version:

A. Use in the Title Page (and on the covers, if any) a title distinct from that of the Document, and from those of previous versions (which should, if there were any, be listed in the History section of the Document). You may use the same title as a previous version if the original publisher of that version gives permission.

B. List on the Title Page, as authors, one or more persons or entities responsible for authorship of the modifications in the Modified Version, together with at least five of the principal authors of the Document (all of its principal authors, if it has fewer than five), unless they release you from this requirement.

C. State on the Title page the name of the publisher of the Modified Version, as the publisher.

D. Preserve all the copyright notices of the Document.

E. Add an appropriate copyright notice for your modifications adjacent to the other copyright notices.

F. Include, immediately after the copyright notices, a license notice giving the public permission to use the Modified Version under the terms of this License, in the form shown in the Addendum below.

G. Preserve in that license notice the full lists of Invariant Sections and required Cover Texts given in the Document's license notice.

H. Include an unaltered copy of this License.

I. Preserve the section Entitled "History", Preserve its Title, and add to it an item stating at least the title, year, new authors, and publisher of the Modified Version as given on the Title Page. If there is no section Entitled "History" in the Document, create one stating the title, year, authors, and publisher of the Document as given on its Title Page, then add an item describing the Modified Version as stated in the previous sentence.

J. Preserve the network location, if any, given in the Document for public access to a Transparent copy of the Document, and likewise the network locations given in the Document for previous versions it was based on. These may be placed in the "History" section. You may omit a network location for a work that was published at least four years before the Document itself, or if the original publisher of the version it refers to gives permission.

K. For any section Entitled "Acknowledgements" or "Dedications", Preserve the Title of the section, and preserve in the section all the substance and tone of each of the contributor acknowledgements and/or dedications given therein.

L. Preserve all the Invariant Sections of the Document, unaltered in their text and in their titles. Section numbers or the equivalent are not considered part of the section titles.

M. Delete any section Entitled "Endorsements". Such a section may not be included in the Modified Version.

N. Do not retitle any existing section to be Entitled "Endorsements" or to conflict in title with any Invariant Section.

O. Preserve any Warranty Disclaimers.

If the Modified Version includes new front-matter sections or

appendices that qualify as Secondary Sections and contain no material copied from the Document, you may at your option designate some or all of these sections as invariant. To do this, add their titles to the list of Invariant Sections in the Modified Version's license notice. These titles must be distinct from any other section titles.

You may add a section Entitled "Endorsements", provided it contains nothing but endorsements of your Modified Version by various parties--for example, statements of peer review or that the text has been approved by an organization as the authoritative definition of a standard.

You may add a passage of up to five words as a Front-Cover Text, and a passage of up to 25 words as a Back-Cover Text, to the end of the list of Cover Texts in the Modified Version. Only one passage of Front-Cover Text and one of Back-Cover Text may be added by (or through arrangements made by) any one entity. If the Document already includes a cover text for the same cover, previously added by you or by arrangement made by the same entity you are acting on behalf of, you may not add another; but you may replace the old one, on explicit permission from the previous publisher that added the old one.

The author(s) and publisher(s) of the Document do not by this License give permission to use their names for publicity for or to assert or imply endorsement of any Modified Version.

5. COMBINING DOCUMENTS

You may combine the Document with other documents released under this License, under the terms defined in section 4 above for modified versions, provided that you include in the combination all of the Invariant Sections of all of the original documents, unmodified, and list them all as Invariant Sections of your combined work in its license notice, and that you preserve all their Warranty Disclaimers.

The combined work need only contain one copy of this License, and multiple identical Invariant Sections may be replaced with a single copy. If there are multiple Invariant Sections with the same name but different contents, make the title of each such section unique by adding at the end of it, in parentheses, the name of the original author or publisher of that section if known, or else a unique number. Make the same adjustment to the section titles in the list of

Invariant Sections in the license notice of the combined work.

In the combination, you must combine any sections Entitled "History" in the various original documents, forming one section Entitled "History"; likewise combine any sections Entitled "Acknowledgements", and any sections Entitled "Dedications". You must delete all sections Entitled "Endorsements".

6. COLLECTIONS OF DOCUMENTS

You may make a collection consisting of the Document and other documents released under this License, and replace the individual copies of this License in the various documents with a single copy that is included in the collection, provided that you follow the rules of this License for verbatim copying of each of the documents in all other respects.

You may extract a single document from such a collection, and distribute it individually under this License, provided you insert a copy of this License into the extracted document, and follow this License in all other respects regarding verbatim copying of that document.

7. AGGREGATION WITH INDEPENDENT WORKS

A compilation of the Document or its derivatives with other separate and independent documents or works, in or on a volume of a storage or distribution medium, is called an "aggregate" if the copyright resulting from the compilation is not used to limit the legal rights of the compilation's users beyond what the individual works permit. When the Document is included in an aggregate, this License does not apply to the other works in the aggregate which are not themselves derivative works of the Document.

If the Cover Text requirement of section 3 is applicable to these copies of the Document, then if the Document is less than one half of the entire aggregate, the Document's Cover Texts may be placed on covers that bracket the Document within the aggregate, or the electronic equivalent of covers if the Document is in electronic form. Otherwise they must appear on printed covers that bracket the whole aggregate.

8. TRANSLATION

Translation is considered a kind of modification, so you may

distribute translations of the Document under the terms of section 4. Replacing Invariant Sections with translations requires special permission from their copyright holders, but you may include translations of some or all Invariant Sections in addition to the original versions of these Invariant Sections. You may include a translation of this License, and all the license notices in the

Document, and any Warranty Disclaimers, provided that you also include the original English version of this License and the original versions of those notices and disclaimers. In case of a disagreement between the translation and the original version of this License or a notice or disclaimer, the original version will prevail.

If a section in the Document is Entitled "Acknowledgements", "Dedications", or "History", the requirement (section 4) to Preserve its Title (section 1) will typically require changing the actual title.

9. TERMINATION

You may not copy, modify, sublicense, or distribute the Document except as expressly provided for under this License. Any other attempt to copy, modify, sublicense or distribute the Document is void, and will automatically terminate your rights under this License. However, parties who have received copies, or rights, from you under this License will not have their licenses terminated so long as such parties remain in full compliance.

10. FUTURE REVISIONS OF THIS LICENSE

The Free Software Foundation may publish new, revised versions

of the GNU Free Documentation License from time to time. Such new versions will be similar in spirit to the present version, but may differ in detail to address new problems or concerns. See http://www.gnu.org/copyleft/.

Each version of the License is given a distinguishing version number. If the Document specifies that a particular numbered version of this License "or any later version" applies to it, you have the option of following the terms and conditions either of that specified version or of any later version that has been published (not as a draft) by the Free Software Foundation. If the Document does not specify a version number of this License, you may choose any version ever published (not as a draft) by the Free Software Foundation.






Bitcoin is a swarm of cyber hornets serving the goddess of wisdom, feeding on the fire of truth, exponentially growing ever smarter, faster, and stronger behind a wall of encrypted energy








"Qui vit sans folie n'est pas si sage qu'il croit."   La Rochefoucault