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
0°
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.
|