Source: http://capsis.cirad.fr/capsis/documentation/doc_reference_v1_0
Timestamp: 2020-05-25 21:25:02+00:00

Document:
documentation:doc_reference_v1_0 [Capsis]
Capsis 4 - Documentation de Référence
v 1.0 - F. de Coligny - avril 2001
DRAFT - 30 avr 01
2.2 Le noyau - capsis.kernel
2.2.1 Structure de données générique
2.2.1.1 Niveau organisationnel
a. La Session - capsis.kernel.Session
b. Le Projet - capsis.kernel.Scenario
c. L'étape - capsis.kernel.Step
2.2.1.2 Niveau fonctionnel
a. Peuplement générique - capsis.kernel.GStand, GTCStand
b. Arbre - capsis.kernel.GTree, GMaddTree, GMaidTree
c. Terrain - capsis.kernel.GPlot, GCell
d. Modèle générique - capsis.kernel.GModel
e. Ensoleillement - capsis.kernel.GBeamSet, GBeam
2.2.2 Démarrage - capsis.kernel.Main
2.2.3 Paramétrage - capsis.kernel.CapsisSettings
2.2.4 Moteur Capsis4 - capsis.kernel.Engine
2.2.4.1 Design Pattern « Singleton »
2.2.4.2 Gestion des sessions
2.2.4.3 Gestion des projets
2.2.4.4 Gestion des étapes
2.2.4.5 Détection et chargement des modules
2.2.5 Sauvegarde par sérialisation
2.2.6 Les groupes - capsis.kernel.AbstractGroup, DynamicGroup, StaticGroup, GroupManager
2.2.7 Le mécanisme d'extensions - capsis.kernel.ExtensionManager - compatibilité
2.3 Le pilote générique
2.3.2 Les contrats du pilote générique
2.3.4 Reconstruction lors de l'ouverture d'un projet
2.4 Structure d'un module
2.4.2 Classes modèle - module.model
2.4.3 Classes pilote - ex: module.gui
2.4.4 Paramétrage - module.model.modSettings
2.4.5 Peuplement initial
2.4.6 Initialisation du modèle
2.4.7 Procédure d'évolution
2.4.8 Actions avant et après intervention
2.4.9 Fournisseurs de méthodes - MethodProvider
2.5 Architecture sur disque - Fichiers spéciaux
3 Les pilotes
3.1 Le pilote graphique - capsis.gui
3.1.1 La classe principale - MainInterface
3.1.2 La fenêtre principale - MainFrame
3.1.3 Les commandes de l'interface - capsis.gui.command
3.1.4 Le gestionnaire de scénarios - ScenarioManager
3.1.5 Le gestionnaire de visualisateurs - ViewerMediator
3.1.6 Le gestionnaire de sorties graphiques - OutputMediator
3.1.7 Le sélecteur d'interventions - DIntervention
3.1.8 Le constructeur de groupes - DGroupDefiner
3.2 Le pilote console
4 Les extensions
4.2 Les interventions
4.3 Les visualisateurs de peuplement
4.4 Les extracteurs/metteurs en forme de données
4.4.1 Les extracteurs de données - capsis.extension.DataExtractor
4.4.2 Les rendeurs de données - capsis.extension.DataRenderer
4.5 Les outils génériques
4.6 Les filtres
4.7 Les formats d'import/export
5 Formation Modélisateurs
5.1 Utilisation de Capsis4.
5.1.1 Lancement.
5.1.2 Modèles disponibles.
5.1.3 Création d'un projet.
5.1.4 Gestionnaire de scénario.
5.1.5 Configuration projet.
5.1.6 Visualisateurs.
5.1.7 Evolution.
5.1.8 Intervention.
5.1.9 Sorties graphiques.
5.1.10 Groupes.
5.1.11 Sauvegardes.
5.1.12 Impression.
5.2 TD Construction d'un Modèle.
5.3 TD Construction d'un Intervener.
5.4 TD Construction d'un StandViewer.
5.5 TD Construction d'un MethodProvider et d'un DataExtractor.
Capsis4 est une plate-forme de simulation pour l'étude de la production et de la dynamique des peuplements forestiers. Elle héberge des modèles dendrométriques de dynamique forestière et propose des outils pour procéder à des interventions sur les peuplements.
Les modèles sont de plusieurs types (modèles de peuplement, modèles arbre indépendants des distances - MAID, modèles arbre dépendants des distances - MADD, modèles mixtes...) et s 'appliquent sur des structures de données plus ou moins détaillées (l'arbre peut être individualisé et même spatialisé).
Ainsi, certains modèles considèrent un peuplement équienne mono-spécifique dans son ensemble pour calculer des grandeurs générales relatives à son évolution (densité, facteur d'espacement, caractéristiques de l'arbre dominant ou moyen), quand d'autres modèles s'intéressent à chaque arbre d'un peuplement hétérogène et calculent ses propriétés en tenant compte de la gène que peut lui occasionner son voisinage pour l'accès aux ressources (eaux, lumière...).
Ces modèles ont en commun de calculer l'évolution d'un peuplement forestier (au minimum la croissance des arbres existants, mais aussi parfois la mortalité, la régénération, l'élagage, les déformations...) et d'être utilisés dans une démarche d'établissement de scénarios sylvicoles alternant des phases d'évolution et des interventions (éclaircie, fertilisation...).
Pour répondre à ces besoins, Capsis4 adopte la structure modulaire des versions précédentes (Capsis2 [Dreyfus96] et Capsis3) : un module par modèle.
Capsis4 gère une structure de données « légère » axée sur l'organisation des données (session, projet, étape). Le logiciel a peu d'exigences sur la structure du peuplement sur lequel on travaille. Il considère un « peuplement générique » (GStand) dont il ignore par exemple s'il comporte une liste d'arbres ou s'il est associé à un objet de type terrain.
Pour ce qui est des structures de données fonctionnelles, des propositions sont faites au modélisateur en terme de base de description des objets de son modèle (arbre générique spatialisé ou non, terrain générique découpé en cellules...). Capsis4 propose des outils travaillant sur ces structures de données générales. Ces outils sont utilisables par les modèles qui s'appuient sur les structures en question.
Les objets génériques proposés ont une description minimale pour être peu contraignante (ex: GTree - identifiant, age, diamètre, hauteur). Cette description est complétée dans chaque module par le jeu de l'héritage de la Programmation Orientée Objets (POO) (ex: arbre du modèle A : GTree + hauteur et rayon de la base du houppier).
Le modélisateur peut choisir de s'appuyer sur les objets génériques proposés, ou bien de reconstruire tout ce dont il a besoin. La seule exigence de Capsis4 envers ses modules est de pouvoir faire évoluer un objet peuplement dérivé de GStand (le « peuplement générique ») pour qu'il soit possible d'associer ses états successifs à des étapes de scénario sylvicole.
L'architecture de Capsis4 est de type noyau/modules avec pilote séparé. Elle est également extensible.
L'un des principes fondateurs de l'architecture de Capsis4 est la possibilité de spécialisation dans des modules de structures de données génériques décrites dans un noyau applicatif. Ce mécanisme requiert l'emploi d'un langage de Programmation Orientée Objets (POO) pour disposer de la notion essentielle d'héritage. Capsis4 est développé en langage Java1 [Gosling96].
Le noyau applicatif est le coeur de Capsis4. Il fournit les opérations de base du logiciel, tels que la gestion de la structure de données et le chargement des modules. Les fonctionnalités du noyau sont accessibles par tous les composants de Capsis4, modules et extensions compris.
Capsis4 est utilisé au moyen d'un pilote. C'est un ensemble de classes permettant de conduire des simulations en tirant parti des possibilités offertes par le noyau. Deux pilotes au moins sont prévus : un pilote interactif graphique permettant le dialogue avec l'utilisateur au travers d'une interface graphique, et un pilote en mode console, fonctionnant automatiquement à partir de fichiers de paramètres et de scripts de scénarios préalablement construits. Dans ce document, il n'est fait référence qu'au pilote interactif.
Un module Capsis4 est l'implémentation concrète d'un modèle de dynamique forestière au moyen de structures de données, de méthodes et d'algorithmes dans des classes dites fonctionnelles. Ces classes contiennent en quelque sorte la connaissance du modélisateur.
Les modules sont accompagnés d'un ensemble de classes pilotes pour compléter ou remplacer certaines classes du pilote générique. Le pilote interactif du modèle comporte notamment des boites de dialogues pour l'acquisition de paramètres nécessaires au fonctionnement propre du modèle.
Le mécanisme d'extensions permet de rajouter des fonctionnalités à Capsis4. L'externalisation de certains traitements sous forme d'extensions permet la réutilisation d'outils par plusieurs modèles, le partage de méthodes et l'évolution ultérieure de la plate-forme par construction de nouvelles extensions.
Il existe plusieurs types d'extensions pour extraire ou représenter les données calculées, filtrer des collections d'objets (arbres, placeaux...) ou encore permettre l'importation et l'exportation des données vers d'autres logiciels.
Capsis4 se charge de gérer la compatibilité des extensions entre elles ou avec les modules. La typologie des extensions est ouverte et susceptible d'évolutions.
Les principales fonctionnalités proposées par le noyau Capsis4 sont décrites ici. Elles sont prévues pour être accessibles par tous les pilotes Capsis4, qu'ils soient interactifs ou non.
Les classes évoquées dans ce chapitre appartiennent au package capsis.kernel sauf mention contraire. Elles peuvent être regroupées en plusieurs catégories.
La structure de données de Capsis4 est décrite à deux niveaux : organisationnel et fonctionnel.
Au niveau organisationnel, Capsis4 gère des scénarios sylvicoles (ou Projets) regroupés dans une session de travail et composés d'étapes successives. A chaque projet est associé un modèle avec un paramétrage déterminé lors d'une phase initiale (lors de la création du projet).
Le projet comporte une étape racine, supportant un peuplement initial fourni par le modèle (chargement d'un inventaire, génération virtuelle...).
Il est ensuite possible de créer d'autres étapes en demandant au modèle de faire évoluer le peuplement initial ou en procédant à une intervention (ex: une éclaircie).
Un projet peut contenir plusieurs scénarios sylvicoles ayant en commun une même étape racine, mais reflétant des sylvicultures différentes.
La classe Session comporte une collection de projets. Il est possible d'ajouter des projets ou d'en supprimer avec les méthodes prévues à cet effet. La session est caractérisée par un nom et peut donner des indication sur son statut de sauvegarde (sauvée, déjà sauvée une fois...).
Le projet est décrit dans le noyau par la classe Scenario. Le projet peut en effet être considéré comme un scénario à options ayant une particularité forte : toutes les branches de sous-scénario ont la même étape racine. Le projet (Scenario) est donc un arbre général (chaque noeud a plusieurs fils) dont le noeud est une étape (voir ci-après Step).
La superclasse de Scenario est capsis.util.NTree (arbre général). Cette classe est caractérisée principalement par la gestion d'une étape racine (« root »). NTree peut renvoyer un iterateur (Iterator Java) qui contient la liste des noeuds de l'arbre parcouru en préordre. Cette liste peut se limiter aux noeuds « visibles » (voir Step).
La classe Step décrit l'étape Capsis4, dont la fonction est de porter un peuplement calculé par un modèle donné à une date donnée. Cette entité est un noeud d'arbre général (NTree) par héritage de la classe capsis.util.Node.
Node est la base d'une implémentation d'arbre général de type « left-son, right-brother » [Cormen90] qui s'appuie sur la connaissance par chaque noeud de son « père », son « fils gauche » et son « frère droit ». Cette implémentation est économique en place parce qu'elle évite une liste de fils pour chaque noeud.
De plus, chaque noeud porte une propriété qui le définit comme « visible » ou invisible » dans les projets Capsis4. Cette notion de visibilité sert à marquer les noeuds charnière lors de l'établissement d'un projet. Elle est modifiable à loisir. Il en résulte des représentations simplifiées des projets, ne faisant état que des noeuds visibles.
Node possède des méthodes pour insérer un n?ud après un noeud donné, supprimer un n?ud, supprimer tous les n?uds père d'un n?ud donné jusqu'au précédent noeud visible non compris, rendre le père visible d'un n?ud donné, déterminer si un n?ud est racine ou feuille de l'arbre.
Node implante en outre le Design Pattern « Visitor » [Gamma95] qui permet à un objet quelconque de parcourir l'arbre pour effectuer une tâche sur chaque noeud sans que le noeud ne soit conçu pour cette tâche a priori.
La classe Step hérite donc des fonctionnalités de Node, auxquelles elle ajoute des méthodes pour connaître le scénario auquel elle est rattachée et le peuplement qu'elle porte.
Au niveau fonctionnel, Capsis4 décrit un peuplement générique (GStand). Cette description est volontairement « légère » pour ne pas contraindre le modélisateur, mais elle prévoit néanmoins le minimum requis pour un peuplement Capsis4 :
Récupération de l'étape portant le peuplement et d'un élément de datation dans le projet (qui peut être par exemple une année ou un nombre d'années (de mois...) depuis l'étape racine).
Possibilité d'associer un objet terrain (GPlot). Ce terrain est facultatif. Il peut comporter un découpage en cellules de terrain individualisées connaissant les arbres qu'elles contiennent. Ce mécanisme peut permettre d'implémenter des traitements au niveau cellule (ex: régénération).
Mécanisme pour l'évolution : on peut demander au peuplement qu'il renvoie une base pour l'évolution. Cette base doit être une copie de lui même (mais sans arbres pour les modèles à arbre individualisé), que le processus d'évolution va compléter pour donner le peuplement évolué. Pour les implémentations lourdes de GStand (ex : beaucoup d'arbres détaillés et association d'un terrain avec de nombreuses cellules), ce mécanisme peut choisir de renvoyer une copie « légère » de lui même (ex: copie sans arbres avec une référence vers son propre terrain non cloné). Cette précaution peut permettre d'accélérer les traitements mais implique des précautions d'usage par la suite.
Mécanisme pour l'intervention. Renvoie une copie du peuplement complet (avec arbres dans le cas d'un modèle spatialisé) sur lequel le dispositif d'intervention va travailler, par exemple pour supprimer ou marquer des arbres.
Des éléments d'identification (légende, source initiale des données...)
Une implémentation par défaut de GStand est fournie : GTCStand (pour « Generic Tree Collection Stand »). GTCStand est un peuplement générique qui possède une collection d'arbres de type GTree (ou une de ses sous-classes).
L'implémentation de la collection d'arbres est laissée à la discrétion du modélisateur qui décide d'utiliser (sous-classer) GTCStand dans son module. Une implémentation par défaut est fournie (sur la base d'une java.util.Hashtable). L'implémentation doit respecter le contrat fixé par l'interface capsis.util.TreeCollection, implantée par GTCStand par l'intermédiaire de TreeCollectionHandler. Cette interface prévoit en particulier l'ajout et la suppression d'un arbres, mais aussi la récupération d'un arbre à partir de son identifiant.
Par le jeu de la redéfinition de la méthode créant la TreeCollection, le modélisateur peut choisir de créer une collection propre implémentant l'interface TreeCollection, mais basée sur une structure de données qui favorise les opérations qu'il prévoit sur ses arbres (ex: recherche de voisins).
GTree est une description d'arbre générique. Son utilisation par les modèles avec arbre individuel n'est pas requise, mais elle permet l'emploi d'outils qui reconnaissent les objets de ce type. Cette remarque est généralisable à beaucoup de classes génériques dont l'usage est recommandé mais pas obligatoire.
GTree définit un identifiant pour l'arbre unique dans le peuplement, un âge, une hauteur (en mètres), un diamètre à 1.3 m. (en cm.), une propriété « marqué » utilisable pour marquer les arbres morts ou éclaircis sans les retirer du peuplement. L'arbre générique GTree connaît sa cellule de terrain (cette référence peut être nulle si le terrain n'est pas utilisé) et le peuplement qui le contient. GTree dispose de deux méthodes pour l'enregistrer ou le retirer d'un terrain (GPlot).
GMaddTree est un arbre générique spatialisé. Il reprend les propriétés de GTree dont il hérite. En plus, il implante l'interface capsis.util.Spatialized qui définit des coordonnées 3D : x, y et z.
GMaidTree est un arbre générique à effectif. Il hérite également de GTree, mais représente une classe d'arbres dont il porte l'effectif. Il implante l'interface capsis.util.Numberable qui spécifie l'emploi d'un effectif. GMaidTree possède également une propriété numberOfDead qu'on peut employer pour mémoriser le nombre de morts (ou d'éclaircis) dans la classe représentée par l'arbre depuis la dernière étape.
Dans les modules utilisant un arbre individualisé, il est d'usage d'hériter de GMaddTree pour les modèles spatialisés et de GMaidTree pour les modèles indépendants des distances. Ceci est une possibilité mais pas une règle. De même, il est possible d'utiliser une sous classe de GMaddTree implémentant également l'interface Numberable pour construire un arbre particulier : spatialisé et représentant une classe d'arbres.
Des propositions sont faites pour l'utilisation d'un objet terrain GPlot divisable en cellules de terrain GCell.
Le GPlot a pour propriétés une origine, la liste des cellules qu'il contient, une forme pour le dessiner, des méthodes pour gérer ses cellules, récupérer la référence au peuplement qu'il accompagne et ajouter un arbre dans la cellule qui doit le contenir.
La GCell spécifie une origine, une liste d'arbres qu'elle contient, une forme permettant de la dessiner, des méthodes pour enregistrer des arbres et déterminer son terrain.
Des implémentations standard sont proposées :
RectangularPlot est un terrain rectangulaire composé de cellules carrées de même taille SquareCell. La subdivision en cellules permet d'associer des propriétés à la cellule de terrain (ex: régénération au niveau cellule).
La SquareCell supporte un mécanisme permettant d'appliquer un masque sur un terrain en visant une cellule de référence pour récupérer les cellules qui avoisinent la cellule visée et qui sont dans le masque. Ce mécanisme est assorti d'une option permettant de considérer le terrain comme étant torique pour éviter des effets de lisière indésirables en bordure du terrain.
PolygonalPlot et PolygonalCell sont des implémentations de GPlot et GCell qui décrivent des portions de terrain polygonales. Elles n'ont pas toutes les fonctionnalités de leurs homologues rectangulaires.
GModel est la superclasse de toutes les classes « modèle » des modules Capsis4. Cette classe définit des propriétés communes à toutes les classes modèles :
Possession d'une carte d'identité (GIdCard) redéfinie dans chaque module. Cette carte d'identité est utilisée dans le processus de chargement des modules. Elle contient notamment des renseignements sur le modèle et son auteur.
Association d'un jeu de paramètre (GSettings) redéfini dans chaque module. Ces paramètres sont sérialisables pour pouvoir être sauvegardés avec un projet et restitués lors d'un chargement ultérieur. Généralement, la plupart de ces paramètres sont fixés pendant la phase d'initialisation du modèle.
Référence du Projet associé. Un modèle avec son jeu de paramètres est associé à un projet. Il définit les modalités d'évolutions pour toute la durée du projet.
Capacité à être sérialisée avec ses paramètres lors de l'enregistrement du projet associé.
Appareillage pour implémenter les stratégies de gestion mémoire des projets par le moteur Capsis4.
GBeam et GBeamSet décrivent respectivement un rayon lumineux et un ciel utilisables pour l'ensoleillement d'une scène par lancer de rayons.
La classe Main est la classe de démarrage de Capsis4. Elle contient la méthode main qui permet de démarrer une application java.
Elle commence par créer une instance de CapsisSettings (cf. § 2.2.3) en lui passant les paramètres de la ligne de commande, puis elle crée l'instance d'Engine, moteur Capsis4 (cf. § 2.2.4) qui servira durant toute la session Capsis4.
La classe CapsisSettings établit les paramètres pour la session Capsis4 à partir des paramètres éventuels de la ligne de commande, de valeurs par défaut et de paramètres enregistrés sur disque lors de la dernière session Capsis4.
Elle détermine la langue courante, récupère les paramètres passés par la machine virtuelle Java (JVM), repère l'emplacement du répertoire « racine » de Capsis4, ainsi que des répertoires nécessaire à son fonctionnement : bin/, etc/, var/, tmp/, doc/.
Cette classe assure également le chargement de fichiers de paramètres : capsis.properties (fichier paramètres de Capsis4) et capsis.options, paramètres déterminés lors de la dernière session et venant modifier ceux de capsis.properties. Enfin, elle crée un fichier capsis.log qui recueillera toutes les informations écrites par Capsis4 ou ses modules pendant la session Capsis4.
La classe Engine est la classe principale du noyau. Elle contient les fonctions de base liées à la gestion de la structure de donnée (niveau organisationnel) : création, ouverture, sauvegarde et fermeture des sessions et projets, création d'une nouvelle étape à partir d'un peuplement initial ou calculé, suppression d'étapes existantes. Elle assure également la détection et le chargement des modules.
Elle porte le numéro de version de Capsis4, récupérable par une méthode d'accès.
La classe Engine a été conçue conformément au Design Pattern « Singleton » [Gamma95]. Cette disposition permet à toute classe de Capsis4, d'une extension ou d'un module de récupérer la référence à l'unique objet de type Engine instancié pendant une session Capsis4 par la méthode de classe Engine.getInstance ().
Cette méthode instancie Engine au premier appel (par la classe Main) par invocation d'un constructeur privé. Les appels suivants se contentent de renvoyer la référence au même objet. Ainsi, on est assuré qu'une seule instance d'Engine est créée. Une conséquence est l'inutilité de la transmission de la référence à l'objet Engine à bon nombre d'objets créés et donc une simplification du code.
Le pattern Singleton est utilisé par d'autres classes : ExtensionManager et GroupManager dans le package capsis.kernel, MainInterface et MainFrame dans le package capsis.gui.
La méthode processNewSession() permet de créer une nouvelle session. Une session doit être créée avant la création ou l'ouverture d'un projet. La création consiste en l'instanciation d'un objet de type Session et en l'attribution d'un nom.
processOpenSession() charge une session précédemment enregistrée sur disque. On lui passe un nom de fichier contenant une session. Le fichier session est un fichier descriptif contenant des informations permettant de recréer une session (avec processNewSession()), notamment une chaîne de caractère (java.lang.String) encodée contenant des informations enregistrées lors de la sauvegarde et les chemins d'accès aux projets enregistrés avec la session. Cette méthode appelle processOpenScenario() pour chacun des noms de fichier projet, recrée un pilote pour le modèle associé dans le mode courant (ex: interactif) puis ajoute ce projet à la session nouvellement créée.
processCloseSession() permet de supprimer la session en cours (il y a au plus une session en cours à un moment donné).
Enfin, processSaveAsSession() sauvegarde la session en cours dans un fichier portant le nom précisé. Ce fichier est composé d'informations sur la session, puis des noms des fichiers contenant les projets sauvegardés. Cette méthode considère que les projets viennent d'être sauvegardés sur disque (ce qui est de la responsabilité du pilote).
Rappel : Les projets sont des instances de la classe Scenario (cf. § 2.2.1.1).
Pour créer un nouveau projet, on utilise la méthode processNewScenario() en lui passant un modèle instancié et paramétré, ainsi qu'un nom pour le projet. La méthode invoque le constructeur de la classe Scenario, puis ajoute le projet ainsi créé à la session courante.
processOpenScenario() permet de charger un projet enregistré sur disque. Comme pour la session, une chaîne de caractères encodée précède les données du projet, qui sont sous forme sérialisée (cf. § 2.2.5). Le projet n'est pas associé à la session courante (responsabilité du pilote) mais juste retourné par la méthode.
La suppression d'un projet s'opère en invoquant la méthode processCloseScenario() qui supprime le projet donné de la session courante, puis invoque sa méthode dispose() pour libérer la mémoire explicitement.
La méthode processSaveAsScenario() permet de sauver un projet donné dans un fichier au nom précisé. Une chaîne de caractères encodée descriptive précède le projet sérialisé dans le fichier.
La classe Engine permet d'ajouter et de supprimer des étapes dans un projet. Pour l'ajout, la méthode processNewStep() nécessite la référence au projet concerné, l'étape parente, le peuplement à associer à la nouvelle étape, un booléen concernant l'aspect visible de l'étape et une chaîne de caractères donnant la raison de l'ajout.
processNewStep() procède à l'instanciation du Step, puis attache la nouvelle étape à son étape parente en respectant les options de mémorisations courantes du projet. Ainsi, l'étape pourra être mémorisée durablement ou bien seulement provisoirement en tant qu'étape intermédiaire.
La méthode processDeleteStep() supprime l'étape passée en paramètre ainsi que toutes ses étapes parentes jusqu'à l'étape visible précédente ou la racine du projet.
Le chargement d'un module s'opère en deux temps : détermination de son nom de classe principale, puis chargement proprement dit. Ces deux opérations sont effectuées grâce à des méthodes de la classe Engine.
Les modules sont des groupes de classes dans des packages. Ces derniers sont disposés dans le répertoire bin/ (cf § 2.5). La stratégie de gestion des modules sur disque prévoit par convention qu'un module terminé est compacté dans une archive java (.jar) qui porte le nom du module. Ce nom de module est également le nom de package de premier niveau du module.
Par exemple, le module arthur est constitué de deux package disposés dans bin/ : arthur.model et arthur.gui et il est destiné à être compacté dans une archive dans bin/ nommée arthur.jar.
Ces archives java servent de support au procédé de détection des modules. Ainsi, pour détecter les modules disponibles, Capsis4 recherche les fichier archives (par leur extension .jar) dans le répertoire bin/ : méthodes getJars() qui renvoie une collection des noms de modules.
Engine récupère ensuite les cartes d'identité de chaque modèle dont le nom est fixé par convention : <nommodule>.model.IdCard (ex: arthur.model.IdCard).
La méthode createHshIdCard() crée une Map ayant pour clé le nom de module spécifié dans la carte d'identité et pour valeur la carte d'identité elle-même. Cette Map permet par exemple au pilote graphique de créer et proposer à l'utilisateur une liste des noms de modèles disponibles (méthode getModelNames()).
Une fois le choix fait, la carte d'identité correspondant au nom dans la Map permet de charger le modèle dynamiquement à partir de la classe principale du modèle qu'elle contient.
Remarque : pendant le développement d'un module, les classes qui le composent ne sont pas encore compactées dans une archive java. Il est nécessaire dans ce cas de créer un fichier (vide) portant le nom permettant la détection du modèle par la classe Engine et de le disposer dans bin/ (ex: arthur.jar). Les classes seront lues dans les packages en cours de mise au point (disposés également dans bin/).
Les groupes sont utilisés dans le cadre d'une simulation pour travailler sur un sous-ensemble d'arbres - pour les modèles avec arbres individualisés - ou de cellules - pour les modèles utilisant le terrain générique Gplot - (visualisation, extraction de données, interventions).
AbstractGroup décrit un groupe Capsis4. Elle permet d'appliquer un groupe constitué d'une combinaison de « filtres » à un objet « Filtrable ». Classiquement, on travaille sur des groupes d'arbres ou de cellules de terrain et les « Filtrable » sont respectivement Gplot et GStand.
DynamicGroup enregistre les filtres paramétrés pour les rejouer sur le « Filtrable » considéré.
StaticGroup enregistre seulement les identifiants des éléments sélectionnés pour les retrouver sur un autre « filtrable » (ex: le même peuplement l'année d'après).
GroupManager (implémentant le design pattern « Singleton » cf. § 2.2.4.1) peut sauvegarder les groupes créés pendant une session Capsis4 et les recharger au début de la sessionCapsis4 suivante.
Une fois un groupe créé (cf. § 2.4.9 pour la construction), il est déclaré auprès du gestionnaire de groupes.
Tout composant Capsis4 peut demander au gestionnaire de groupes la liste des noms de groupes (liste complète ou limitée à un type d'élément ou de « Filtrable »). Une fois le groupe identifié, on en récupère une instance auprès du GroupManager.
GroupManager gm = GroupManager.getInstance ();
AbstractGroup group = gm.getGroup (name);
fi = group.apply (fi); // a group is also a Filter
La classe ExtensionManager (implémentant le design pattern « Singleton » cf. § 2.2.4.1) est chargée de la gestion des extensions Capsis4. C'est elle qui lit dans le fichier paramètre etc/capsis.extensions l'inventaire des extensions disponibles. Cet inventaire est interrogeable à tout moment par son intermédiaire.
Il contient un paragraphe par extension, composé des paramètres à mot-clé suivants :
extension : nom ce classe principale de l'extension (package compris). Certaines extensions peuvent comporter plusieurs classes et tenir dans un package individuel. Ce nom de classe permet de charger l'extension dynamiquement.
type : type de l'extension. Détermine son usage possible. Capsis4 peut proposer les extensions en fonction du contexte de travail. Les types connus sont : GenericTool, StandViewer, DataExtractor, DataRenderer, Filter, Intervener, IOFormat.
validModules : compatibilité de niveau modèle. Peut spécifier le modèle compatible, la liste des modèles compatibles, une famille de modèles compatibles ou bien le mot clé « All » : compatibilité tous modèles.
settings : paramètre optionnel, dépendant du type d'extension. Si le paramètre apparaît, il est transmis à l'extension lors de son chargement. L'extension a la responsabilité du décodage de ce paramètre.
extension = capsis.extension.dataextractor.DETimeG
type = DataExtractor
validModules = All
settings = "defaultDataRenderer = capsis.extension.datarenderer.drcurves.DRCurves"
Pour chaque extension connue, ExtensionManager charge également sa dernière configuration connue depuis le fichier etc/extensions.settings.
Plusieurs méthodes permettent de chercher des extensions dans la liste des extensions disponibles :
getExtensionClassNames(String type) renvoie la liste des noms de classes des extensions du type considéré.
getExtensionClassNames(String type, GModel xModel) renvoie la liste des noms de classes des extensions du type considéré et compatibles avec le modèle spécifié. La compatibilité prise en compte est de niveau modèle, elle s'appuie sur le paramètre validModules du fichier capsis.extensions.
getExtensionClassNames(String type, Object target) renvoie la liste des noms de classes des extensions du type considéré et compatibles avec l'objet donné. La compatibilité prise en compte est de niveau objet. Elle s'appuie sur l'invocation d'une méthode de classe matchWith(Object) décrite par la classe de l'extension. La méthode sélectionne les classes qui renvoient true sur invocation de la méthode matchWith() avec comme paramètre l'objet target. Les extensions concernées par matchWith () sont DataRenderer et Filter.
L'ExtensionManager permet ensuite de charger une extension dont on connaît le nom de classe principale par la méthode loadExtension(). Celle méthode prend le nom de classe de l'extension et un paramètre commun à toutes les extensions pour leur construction : une instance d'ExtensionStarter. Cet objet est préalablement préparé pour contenir les informations nécessaires à la construction de l'extension.
D'autres classes outils d'ExtensionManager permettent d'obtenir le nom d'une extension dans la langue courante à partir de son nom de classe, les informations lues dans capsis.extensions pour une extension, ou encore de tester la compatibilité d'une extension dont on a le nom de classe avec un modèle instancié.
Les pilotes de Capsis permettent d'utiliser les fonctionnalités du noyau complétées par les méthodes fonctionnelles d'un module pour créer des simulation. Les pilotes sont définis pour un contexte d'utilisation.
Ainsi la première version de Capsis4 est-elle accompagnée d'un pilote interactif permettant d'utiliser Capsis4 dans un environnement à base de fenêtres, de menus et de dialogues constitués de composants graphiques.
De même, il est prévu un pilote en mode console, c'est à dire non interactif, prenant ses instructions dans des fichiers de paramètres préparés à l'avance pour jouer des simulations longues ou répétitives.
Ces pilotes génériques sont complétés par du code accompagnant chaque module, permettant d'utiliser le module dans tel ou tel contexte et dénommés pilotes de module. Ainsi, pour utiliser un module en mode console, il faut fournir un pilote de module en mode console.
Tous les pilotes génériques ont en commun la contractualisation de certaines action avec les pilotes de modules. Il partagent également une stratégie de construction et de reconstruction du pilote de module lors de la réouverture d'un projet sauvegardé par sérialisation.
Le pilote générique impose des contrats au pilote de module, c'est à dire l'implémentation de certaines méthodes au prototype imposé. C'est par ce moyen que le « noyau capsis » ou plus précisément un pilote générique, peut déclencher des actions dans le module.
Les pilotes génériques décrivent une superclasse abstraite GInterface qui décrit elle même des méthodes particulières : abstraites ou bien proposant des implémentations par défaut, redéfinissables dans la sous classe.
Cette superclasse doit être impérativement sous classée dans le pilote de module pour fournir des implémentations à ces méthodes.
Plusieurs type d'actions sont consernés : des requêtes et des commandes. Les requêtes sont du type demande de paramètres dans la perspective d'effectuer une action. Les commandes sont le déclenchement d'actions dévolues au module, concenant principalement l'initialisation et l'évolution.
Généralement, le pilote du module répond lui même aux requêtes et transmet les commandes à des méthodes des classes modèles du module. Une règle primordiale est que le pilote du module n'implémente jamais de méthodes fonctionnelles, c'est à dire faisant partie du modèle (algorithmes, méthodes de calcul...). Toutes ces méthodes fonctionnelles sont implémentées dans les classes fonctionnelles du module pour pouvoir être utilisées dans plusieurs contextes d'utilisation, c'est à dire par plusieurs pilotes différents.
Par convention, les méthodes de calcul des classes fonctionnelles correspondant aux méthodes relais du pilote de module portent le même nom (ex: module.gui.processEvolution (protype imposé) appelle module.model.processEvotution (prototype libre)). Pour désigner les classes de meme nom du pilote du module et de sa classe fonctionnelles, on parle de méthodes homologues.
Les méthodes du pilote de module ont un prototype imposé par la superclasse GInterface, mais leurs méthodes homologues de la classe fonctionnelle du module ont un prototype libre, connu du pilote de module, mais inconnu de Capsis4 (noyau et pilote générique).
Le pilote du module a toute latitude pour effectuer des actions de son ressort avant et après la redirection des commandes vers les classes fonctionnelles du module.
Les principaux contrats sont les suivants :
getInitialParameters () - obtention des paramètres initiaux du modèle, renvoie un StandInitializer, c'est à dire un objet sur lequel on peut invoquer getInitStand () pour obtenir un peuplement initial pour l'associer à l'étape racine de projet en cours de construction,
initializeModel () - Initialisation du modèle, permet au modèle d'effectuer des prétraitements qui ne doivent être effectués qu'une fois,
getEvolutionParameters () - récupération des paramètres conditionnant l'évolution, qui sont spécifiques au modèle, ils seront repassés en paramètre à la méthode d'évolution,
processEvolution () - processus d'évolution, reçoit les paramètres récupérés par getEvolutionParameters (), retourne la dernière étape (capsis.kernel.Step) créée par le processus d'évolution,
processPreIntervention () - appelée par Capsis4 avant une intervention pour permettre une éventuelle configuration par le module du mécanisme d'intervention choisi par l'utilisateur,
processPostIntervention () - appelée après une intervention. Le module peut choisir d'effectuer un post traitement après l'intervention, par exemple un ensoleillement de la scène après une éclaircie.
Les implémentations concrètes des pilotes génériques existants sont traitées au chapitre 3.
L'implémentation actuelle est provisoire. Elle sera réécrite pour être plus générale.
Lors de la sauvegarde d'un projet par sérialisation, le pilote de module n'est pas sauvegardé. En effet, le projet peut être réouvert dans un autre contexte d'utilisation, nécessitant un pilote de module différent. Après l'ouverture d'un projet sérialisé, il faut donc reconstruire le pilote de module correspndant au contexte d'utilisation courant (ex: mode console).
Capsis4 héberge des modèles de croissance, de production ou de dynamique forestière. Ils peuvent s'appliquer à des plantations ou à des forêts naturelles. Dans la suite, ces modèles sont dénommés « modèles de croissance ».
On considère des modèles de plusieurs types, notamment modèles de type « Peuplement » -- travaillant sur les propriétés globales d'un peuplement (densité, facteurs d'espacement...), modèles « Arbre, Indépendant des Distances » (MAID) -- prenant en compte des arbres « à effectif » représentant plusieurs individus ayant les mêmes propriétés, ou encore modèles « Abre, Dépendant des Distances » (MADD) -- où l'on individualise chaque arbre dont on connaît les coordonnées sur le terrain. Si Capsis4 est concu pour héberger tout type de modèles (a priori dendrométrique, mais ce n'est pas une limitation), ceux-ci sont jugés représentatifs et ont donné lieu à une attention particulière.
Chaque modèle est implémenté dans un module Capsis4.
Le module contient des classes « fonctionnelles » ou « classes modèle » contenant la connaissance du modélisateur et des « classes pilote » proposant les outils nécessaires à l'exploitation du module dans un contexte d'utilisation donné (contexte de pilotage, ex: interactif).
Par exemple, en mode de pilotage interactif, des boîtes de dialogue spécifiques sont nécessaires à l'initialisation et au fonctionnement du modèle (évolution du peuplement...). Elles sont décrites parmis les classes pilote.
Les classes des modules sont regroupées dans des « packages java ». Par convention, le premier membre du nom de package est le nom du module (ex: eucalypt) ci dessous dénommé « module ».
Les classes fonctionneles sont dans un package module.model (ex: eucalypt.model) et les classes du pilote graphique sont dans module.gui (ex: eucalypt.gui). Dans ces packages, toutes les classes à l'exception de module.model.IdCard voient leur nom débuter par un préfixe propre au modèle (ci après désigné par "mod"). Par exemple: eucalypt.model.EptusStand -- nom du module : eucalypt, préfixe : Eptus. Cette convention permet de reconnaître facilement les classes de chaque modèle.
La classe IdCard est la "carte d'identité" du modèle. Elle contient des informations relatives au modèle et à son auteur, ainsi que des informations nécessaires au chargement du module par le moteur de Capsis4 (nom de classe principale...). Le nom de cette classe est le seul qui n'est pas préfixé, pour répondre aux conventions du mécanisme de détection et de chargement de modules (cf § 2.2.4.5).
Ces classes regroupent les descriptions des structures de données utilisées, les algorithmes et les méthodes du modèle, ainsi que des données de paramétrage.
Le modélisateur doit utiliser une implémentation de l'interface capsis.kernel.GStand (Generic Stand) pour représenter son peuplement. C'est le contrat minimal qu'un module doit honorer pour ce qui concerne sa structure de données. Il est possible d'utiliser directement une implémentation proposée par le noyau. Par exemple, les modèles gérant une liste d'arbres peuvent s'appuyer sur capsis.kernel.GTCStand (Generic Tree Collection Stand).
Généralement, le modélisateur décide de sous classer une classe de base (par exemple GTCStand) pour ajouter des propriétés particulières à son objet peuplement, ou bien redéfinir certaines méthodes pour lesquelles il souhaite un comportement particulier. Cette dernière possibilité permet par exemple de créer une liste d'arbres ou un terrain différent des implémentations par défaut en redéfinissant createTreeCollection () ou createPlot ().
Le modélisateur peut choisir de sous classer les classes génériques décrites dans le noyau Capsis4 (GTCStand, GPlot, GTree, GCell...) pour les enrichir, ce qui lui permet par la suite de bénéficier d'outils travaillant sur ces structures de données (visualisateurs, filtres, extracteurs de données...). D'un autre côté, il a la liberté de créer toutes les structures de données dont il a besoin. Dans ce cas, il ne dispose que des outils spécifiquement développés pour son modèle.
Le modélisateur doit implémenter une classe "modèle" nommée par convention module.model.ModModel (avec module = nom du module et Mod = préfixe du modèle, ex: eucalypt.model.EptusModel) et héritant de la classe capsis.kernel.GModel (Generic Model). Cette superclasse définit certaines fonctions disponibles sur les classes modèles des modules. Capsis4 peut ainsi notamment obtenir :
le nom du modèle -- getModelName (),
un fournisseur de méthodes compatible -- getMethodProvider (),
la carte d'identité du modèle -- getIdCard (),
le projet (notion interne : scénario) auquel est associé le modèle -- getScenario (),
les paramètres actuels du modèle -- getSettings (),
diverses informations sur le mode de gestion mémoire du projet associé.
Il n'est pas fixé de contrat à ce niveau sur les propotypes des méthodes pour le chargement d'un peuplement initial, l'initialisation du modèle ou encore l'évolution. Cela permet de laisser libre la signature des méthodes qui implémentent ces processus dans la classe modèle. De tels contrats sont toutefois fixés dans les classes pilotes (cf. § 2.4.3) pour permettre à Capsis4 d'invoquer des méthodes du module.
Il est à noter que certaines conventions existent sur les noms de méthodes principales de la classe modèle. Le principe est que les méthodes doivent porter le même nom que leurs homologues de la classe pilote correspondante :
getInitialParameters (...) : en général résolu par le pilote,
initializeModel (...),
getEvolutionParameters (...) : en général résolu par le pilote,
processEvolution (...),
processPreIntervention (...),
processPostIntervention (...).
Seuls les noms sont concernés par la convention, les paramètres de ces méthodes peuvent différer d'un module à l'autre dans les classes modèle (cf § 2.3.2).
Ainsi, quand Capsis4 demande l'évolution au pilote du modèle depuis une étape de référence d'un projet donné, ce pilote peut décider de récupérer ou de calculer des paramètres pour l'évolution et il les transmet à sa classe modèle en utilisant une méthode de prototype connu et spécifique au module (ex: processEvolution (int nbYears) ou processEvolution (int nbYears, double gMax)).
Classiquement, la classe modèle propose une méthode de chargement depuis un inventaire sur disque ou de génération d'un peuplement initial - loadInitStand (), une méthode d'initialisation du modèle - initializeModel () - invoquée après la récupération des paramètres initiaux par le pilote et d'une méthode d'évolution - processEvolution () - procédant au calcul des états successifs des peuplements et à leur ajout au projet courant les uns à la suite des autres grâce à la méthode Engine.processNewStep ().
Capsis4 est utilisé au travers d'un pilote (cf § 2.3). Le pilote est un groupe de classes permettant de construire des simulations dans un contexte donné. Dans cette section, on évoque un pilote interactif en mode graphique.
Le noyau Capsis4 est accompagné d'un pilote graphique permettant l'utilisation de l'application interactivement. Les fonctionnalités de base sont proposées dans les menus d'une fenêtre principale.
Chaque module est accompagné de compléments de pilote pour un ou plusieurs contextes d'utilisation. Ainsi, tel module dispose d'un pilote graphique, tel autre possède un pilote en mode console (non interactif, utilisant des fichiers paramètres pré-établis). Certains module auront plusieurs pilotes permettant de les utiliser dans plusieurs contextes.
Dans le contexte interactif, chaque module doit sous classer capsis.gui.GInterface pour constituer une "classe relai". Un contrat est défini par GInterface avec cette classe relai (prototypes de méthodes imposés) qui permettra à Capsis4 d'invoquer des méthodes du module par l'intermédiaire de son pilote.
Les méthodes de GInterface dont l'implémentation est attendue dans la classe relai sont présentées dans la section traitant des pilotes génériques de Capsis4 (cf § 2.3.2).
Ces méthodes sont discutées dans les sections qui suivent.
Note: certaines des méthodes ci-dessus peuvent être appelées dans des threads (gestion multi-tâche) par certains pilotes. C'est le cas du pilote graphique pour initializeModel (), processEvolution () et processPostIntervention (). Ces trois méthodes peuvent opérer des traitements longs et le pilote interactif peut ainsi libérer le thread de rafraichissement de l'interface graphique pour éviter à l'utilisateur un blocage apparent de cette dernière.
Les paramètres du modèle sont par convention regroupés dans une classe héritant de capsis.kernel.GSettings. La classe GModel, superclasse de la classe modèle de chaque module, propose une méthode getSettings () qui renvoie ces paramètres.
Note : La méthode GModel.getSettings () renvoie un objet de type GSettings. L'utilisation dans un module nécessite le transtypage (cast) du résultat dans le type de la sous classe de settings du module à chaque utilisation ((ModSettings) getSettings ()). Il est possible de définir dans ModModel une méthode renvoyant directement les settings dans le type attendu :
protected ModSettings getModSettings () {
return (ModSettings) getSettings ();
La classe settings de chaque modèle comporte une série de variables d'instances publique, accessible directement (sans accesseurs). Cet objet est en effet considéré comme une simple structure de données et on évite ainsi une somme d'accesseurs inutiles.
Il est possible de prévoir une série de valeurs par défaut pour les variables d'instances, sous la forme d'autant de constantes portant le même nom mais avec la convention de nommage des constantes en java.
public static final String PLOT_NAME = "Plot 1";
public String plotName = PLOT_NAME;
Généralement, les paramètres du modèle sont déterminés en début de simulation, au moment de la construction du projet. On crée alor un "GSettings" (une sous classe) que l'on attribue au module (GModel.setSettings (laClasse)).
Ce mécanisme de centralisation des paramètres est important. En effet, lors des sauvegardes de projets, le modèle associé est sauvegardé par sérialisation et ces paramètres sont sauvegardés également. Ainsi, lors de la réouverture ultérieure du projet, les paramètres sont restitués dans le même état.
Pendant la création d'un projet, immédiatement après le chargement du modèle à lui associer, le pilote générique invoque la méthode getInitialParameters () du pilote du module. Cette méthode a pour obligation de renvoyer un objet qui implemente l'interface capsis.kernel.StandInitializer qui impose la méthode Gstand getInitStand ().
De cette manière, le pilote générique s'assure que le processus d'initialisation du modèle, qui comporte par ailleurs une acquisition des paramètres du modèles (boites de dialogue en mode interactif), renverra un peuplement initial qu'il pourra accrocher sous la première étape - ou étape racine - du projet.
Le module peut choisir de charger un fichier inventaire au format libre (cf. § 4.7) ou d'en générer un par une méthode qui lui est particulière (peuplement virtuel).
Après l'acquisition des paramètres du modèle, le pilote générique invoque la méthode initializeModel () du pilote du module.
Cette méthode peut soit ne rien faire si aucun pré-traitement n'est à faire pour ce module, soit déléguer l'initialisation à une homologue au prototype libre de la classe module.model.ModModel.
La méthode du pilote peut executer des actions qui lui sont attribuables avant et après l'appel de la méthode de la classe modèle. Il s'agit par exemple de toute action graphique dans le contexte graphique.
La classe modèle fournit l'implémentation concrète des pré-traitements envisagés. Par exemple, le module Mountain procède à la construction d'un ciel (ensemble de rayons) pour ensoleiller les scènes successivement calculées au cours du temps. Ce ciel est construit une seule fois au cours d'un pré-traitement.
Dans le contexte graphique, l'évolution est demandée par l'utilisateur sur une étape de référence à l'aide de la souris ou du clavier. Cette requête donne lieu à l'invocation de la méthode getEvolutionParameters () du pilote du module.
Ce pilote peut alors ouvrir un dialogue générique ou spécifique pour acquérir les paramètres déterminant l'évolution, typiquement une date cible (le pas de temps est bien entendu déterminé par le modèle).
Une fois ces paramètres retournés, le pilote générique invoque la méthode processEvolution () du pilote du module. Cette méthode délègue également le travail à une homologue de la classe modèle du module au prototype non imposé. C'est dans cette méthode module.model.ModModel.processEvolution () que la croissance et les processus éventuellement affiliés (mortalité, régénération...) sont décrits.
La méthode d'évolution du modèle peut classiquement opérer une itération sur le nombre de pas de temps demandés et produire des peuplements successifs résultant à chaque fois de la croissance (au sens large) de celui de la précédente étape. Chaque peuplement calculé est raccroché au projet courant après l 'étape de référence par l'utilisation d'une méthode de la classe capsis.kernel.Engine : processNewStep (). Cette dernière connaît et gère les options mémoires choisies pour le scénario.
La dernière étape calculée est renvoyée jusqu'au pilote générique qui a initié l'action.
Les interventions sont déléguées à des extensions de type « Intervener » (cf. § 4.2). Les Interveners sont des mécanismes simulant l'éclaircie, la fertilisation, l'élagage... Les modélisateurs profitent des Interveners compatibles avec leur module et développent certains autres spécifiques le cas échéant.
La méthode processPreIntervention () du pilote de module est appelée juste avant l'invocation de l'Intervener. On lui passe le peuplement qui va supporter l'intervention, résultat d'un getInterventionBase () sur le peuplement de l'étape de référence, et l'objet destiné à paramétrer l'extension (ExtensionStarter). Le module a donc la possibilité d'agir avant l'intervention, par exemple pour configurer un « éclaircisseur » en mode « marquer les arbres » (au lieu de les supprimer de la liste).
De même, après l'intervention, une autre méthode du pilote module - processPostIntervention () - est appelée pour donner la possibilité au module d'opérer un post-traitement. Il est important de noter que le traitement doit être implémenté dans une méthode homologue le la classe modèle du module. Il s'agit par exemple pour le module Mountain d'un ensoleillement du peuplement une fois éclairci.
Un mécanisme a été mis en place pour gérer les méthodes de calcul de grandeurs dendrométriques (ou autres) par les différents modules. Ces modules ayant des structures de données potentiellement très différentes, des méthodes calculant une même grandeur peuvent nécessiter des implémentation très différentes également.
Pour des raisons de stabilité par rapport à la sérialisation, ces méthodes ne doivent pas être implantées dans la classe peuplement du module comme cela pourrait sembler logique. On préfère regrouper ces méthodes dans des classes outils appelées par la suite MethodProvider.
La classe capsis.kernel.GModel possède une déclaration de méthode abstraite getMethodProvider (). L'objet renvoyé est une sous classe de MethodProvider, un fournisseur de méthodes.
Chaque module renvoie une MethodProvider qui contient des méthodes de calcul. Il peut sous classer un MethodProvider contenant des implémentations par défaut pour une famille de modèles (ex: les modèles MADD).
Certaines implémentations par défaut peuvent être redéfinies si elles sont fausses pour le modèle (à cause d'une variante dans la structure de données par exemple).
Une série d'interfaces est introduite indiquant que la classe qui l'inplémente possède un accesseur sur une grandeur calculée. Ainsi, par exemple, l'interface GProvider définit l'accesseur getG (GStand s).
public interface GProvider {
// G : Basal area
public double getG (GStand s);
Ces interfaces sont regroupées dans un package capsis.util.methodprovider.
Les MethodProvider des modules implémentent les interfaces pour les méthodes qu'elles définissent. Ce système permet aux outils de Capsis4 (par exemple les extracteurs de données) de juger de leur compatibilité avec tel ou tel module : « son MethodProvider implémente-t-il l'interface StuffProvider me garantissant une méthode getStuff () ? »
if (model.getMethodProvider () instanceof Gprovider) {
// I can invoke mp.getG () !
Les implications de cette conception sont les suivantes :
Compatibilité au niveau objet et non pas au niveau modèle (dans etc/capsis.extensions) -> plus robuste (dynamique) ;
Pas de liste de méthodes obligatoires à implenter par les modèles -> souplesse ;
Gstand est stable (peu de maintenance) -> relecture des projets par sérialisation facilitée ;
Le MethodProvider de Gmodel n'est pas sérialisé (inutile) ;
Capsis4 est installé dans un répertoire sur disque, ci-après nommé install/. Après installation, ce répertoire contient lui même une série de répertoires :
bin/ : c'est le répertoire qui contient les sources et les classes de Capsis4 et des modules installés. Ce répertoire est la base des packages de Capsis4. Il contient les scripts permettant de lancer Capsis4 à partir d'un terminal système (ou shell pour les systèmes Unix). Ces scripts lancent Capsis4 en spécifiant que la variable CLASSPATH contient bin/, ce qui est indispensable au démarrage de l'application. Les développeurs et modélisateurs qui veulent compiler des classes de Capsis4 ou de modules doivent positionner la variable CLASSPATH de leur système d'exploitation sur install/bin/ pour permettre au compilateur javac de localiser les packages qu'il recherche. bin/ contient également les fichiers archive .jar destinés à contenir les modules une fois stabilisés. Ces archives servent à la détection des modules (cf. § 2.2.4.5) et doivent exister dans bin/ (provisoirement vide) pour permettre leur utilisation dans Capsis4.
data/ : il est destiné à contenir des données pour l'utilisation des modules intégrés. Il n'est évidement pas obligatoire de disposer les données des modélisateurs dans ce répertoire. Cependant, le modélisateur peut créer un répertoire dans data/ pour y disposer un jeu de données de test (pas trop volumineux) qui sera utilisable par un utilisateur installant la plate-forme Capsis4. Cette démarche est encouragée.
doc/ : ce répertoire accueille la documentation javadoc générable automatiquement par la lecture des sources java. Pour générer la documentation correspondant à la version installée de Capsis4, utiliser le script jmk (« Java MakeFile ») dans bin/. Le fichier bin/Makefile.jmk joint comporte une commande doc qui lance javadoc avec pour cible le répertoire doc. Il est possible de compléter le fichier Makefile.jmk pour générer la documentation de modules non prévus.
etc/ : le répertoire de paramétrage contient plusieurs fichiers de paramètres nécessaires au bon fonctionnement de Capsis4.
capsis.properties contient les paramètres de l'application.
capsis.options modifie capsis.properties avec les paramètres choisis par l'utilisateur lors de la dernière session Capsis4.
capsis.extensions est le fichier de description externe des extensions. Il est lu par le gestionnaire d'extensions Capsis4.
extensions.settings est le fichier ou l'ExtensionManager enregistre la dernière configuration connue de chaque extension.
capsis.groups est une sauvegarde des groupes (paramétrés) connus lors de la dernière session Capsis4. Il est rechargé au démarrage par le gestionnaire de groupes.
ext/ : il contient les extensions utilisées par Capsis4, éventuellement sous forme de fichier archives .jar. Les scripts de lancement de Capsis4 précisent la liste des extensions employées et les recherchent dans ce répertoire. Ce mécanisme se substitue au mécanisme d'extension de la plate-forme Java qui prévoie que les classes d'extensions compactées en « jarFile » sont placées dans installjdk/jre/lib/ext où installjdk est le répertoire d'installation du java development kit (ex: /usr/java/jdk1.3_01). Cette mesure facilite l'installation de la plate-forme Capsis4 qui contient tout ce dont elle a besoin pour fonctionner dans l'arborescence définie à partir de son répertoire d'installation.
project/ : proposé pour sauvegarder les projets individuellement.
session/ : proposé pour sauvegarder les sessions.
tmp/ : utilisé par Capsis4 pour héberger des fichiers temporaires.
var/ : contient des fichiers de longueur variable (dont la taille augmente). capsis.log, le fichier dans lequel Capsis4 écrit des traces des événements qu'il rencontre, est dans ce répertoire.
Capsis4 est une plate-forme évolutive. Elle est destinée à évoluer au fur et à mesure de l'intégration de modèles nouveaux par des modalisateurs ayant des problématiques sensiblement différentes.
Par ailleurs, il faut que le logiciel soit suffisament stable, pour que l'intégration d'un nouveau modèle ne nécessite pas des modifications telles dans le noyau, qu'une mise à niveau de tous les modules existants soit rendue nécessaire à chaque fois.
Dans ce contexte, il a été développé une architecture d'extensions (comparables aux plugins de certaines autres applications). Les extensions Capsis4 sont des outils qui peuvent être écrits ou modifiés parallèlement au développement des modules sans déstabiliser l'architecture du noyau, en se conformant à des spécifications de développement.
Ces outils prennent en charge plusieurs fonctionnalités de Capsis4, dont la principale est l'Intervention. En effet, si l'Evolution est à la charge de chaque module, l'Intervention est déportée dans des extensions dont certaines implémentations sont utilisables par plusieurs modules.
C'est le cas des mécanismes d'éclaircie qui opèrent à un niveau suffisament abstrait, par exemple sur un peuplement (GStand) comportant une liste d'arbres (TreeCollection) contenant une sous classe d'arbre générique (GTree) éventuellement spatialisée (Spatialized). Autant de propriétés détectables dynamiquement par l'extension quand on lui demande si elle peut être appliquée sur un objet donné.
Les extensions sont classées par type, suivant l'utilisation qui en est faite. Le gestionnaire d'extensions ExtensionManager permet de chercher une extension correspondant à des critères (type, compatibilité avec un modèle, avec un objet ou dont on connaît le nom) et de la charger.
Les extensions sont construites avec un constructeur prenant un paramètre normalisé : une instance d'ExtensionStarter. Cet objet est préalablement renseigné avec les informations nécessaires au fonctionnement de l'extension.
Chaque extension doit être définie dans le fichier etc/capsis.extensions pour être connus du gestionnaire d'extension. Parmis les entrées, on spécifie le nom complet (package compris) de la classe principale de l'extension. Certaines extensions volumineuses (plusieurs classe) peuvent tenir dans des packages particuliers (ex: capsis.extension.datarenderer.drcurves contient quatre data renderers : DRCurves, DRHistogram, DRScatterPlot et DRTable).
De manière générale, toutes les extensions Capsis4 implémentent l'interface capsis.extension.Extension qui exige les méthodes suivantes :
// Cette méthode est héritée de l'interface Namable
// Return extension type : STAND_VIEWER, DATA_EXTRACTOR...
// Return getClass ().getName () : complete class name
// Optional initialization processing. Called after constructor.
// Return version.
public String getVersion ();
// Return author name.
public String getAuthor ();
// Return short description.
L'interface Extension définit également les types d'extension connus :
public static final String STAND_VIEWER = "StandViewer";
public static final String DATA_EXTRACTOR = "DataExtractor";
public static final String DATA_RENDERER = "DataRenderer";
public static final String GENERIC_TOOL = "GenericTool";
public static final String INTERVENER = "Intervener";
public static final String IO_FORMAT = "IOFormat";
Généralement, les différentes extensions héritent d'une superclasse implémentant l'interface Extension ou bien implémentent une interface qui en dérive.
Les interventions sont des actions qui sont appliquées sur un peuplement à un moment donné et qui modifient ce peuplement. C'est le complément naturel de l'évolution, qui est la charge du module, pour la construction de scénarios sylvicoles dans Capsis4.
L'intervention type est l 'éclaircie. Elle consiste en la simulation de la coupe d'arbres suivant une stratégie d'éclaircie donnée. Différents mécanismes d'éclaircie existent dans Capsis4 (ex: un éclaircisseur par filtrage d'arbres en utilisant des extensions de type Filtre et un éclaircisseur de type Capsis2 développé pour le module PNN).
La technologie des extensions permet au modélisateur de choisir parmi les éclaircisseurs existants ou bien d'en développer un nouveau pour son module (ou pour une famille de modules compatibles).
Des modèles de fertilisation, d'élagage, d'attaque par des insectes, de simulation de feux de forêts... sont autant de mécanismes d'intervention potentiels dans Capsis4.
En mode interactif (pilote capsis.gui), les interventions sont choisies par la commande capsis.gui.command.Intervention et la boîte de dialogue DIntervention.
Le peuplement qui supporte l'intervention n'est pas directment le peuplement sous l'étape de référence : on demande à ce peuplement de fournir une base pour l'intervention en utilisant GStand.getInterventionBase (). Il s'agit d'une forme de clone du peuplement origine. Dans le cas du GTCStand, c'est un stand de même type, comportant des clones des arbres de l'original, mais pointant sur l'objet terrain (s'il y a lieu, en fonction du module) de l'original. Cette concession permet d'accélérer la copie du peuplement à éclaircir.
Le paramètre ExtensionStarter pour les interveners est constitué comme suit (wStep est l'étape de référence à partir de laquelle on souhaite éclaircir) :
GStand fromStand = wStep.getStand ();
// This object is a partial copy of fromStand.
// Its step instance variable is null !
GStand newStand = (GStand) fromStand.getInterventionBase ();
// Load an extension of type : the one chosen by user
// we're gonna cut trees in newStand
final ExtensionStarter starter = new ExtensionStarter ();
starter.setModel (wStep.getScenario ().getModel ());
starter.setStand (newStand);
starter.setStep (wStep); // passed for convenience
La spécification de l'interface des interveners est donnée par la classe abstraite capsis.extension.Intervener qui implémente Extension.
Cette classe rajoute les contrats suivants à Extension :
* Tells if construction was ok.
* It could be wrong because of wrong parameters in console
* mode or cancel in gui mode.
abstract public boolean isReadyToApply ();
* Makes the actual intervention.
abstract public Object apply () throws Exception;
Elle fournit également les implémentations par défaut de certaines méthodes d'Extension :
* From Extension interface.
return Extension.INTERVENER;
public String getClassName () {
return this.getClass ().getName ();
* May be redefined by subclasses. Called after constructor
* at extension creation (ex : for view2D zoomAll ()).
public void activate () {}
Dans les packages capsis.extension.intervener et inférieurs, voir FilterThinner, IndividualThinner et C2Thinner.
Les visualisateurs de peuplements sont des outils utilisables seulement dans un contexte interactif en mode graphique. Il s'agit de représentation graphiques (cartes2D...) d'un peuplement dans un état donné. Ces outils sont disponibles en utilisant le pilote graphique de capsis (capsis.gui) qui permet de synchroniser (ViewerMediator) des « outils d'étape » avec les boutons représentant les étapes dans le gestionnaire de scénarios (ScenarioManager).
Les spécifications d'interface des visualisateurs de peuplement sont données par la classe abstraite capsis.extension.StandViewer. Elle définit en plus d'Extension les méthodes suivantes :
* A stand viewer may be updated to synchronize itself with a
* given step button.
public void update (StepButton sb) {
super.update (sb);
* Dispose the extension.
* Print method. Called by a printJob. See
* capsis.gui.command.PrintPreview
* and capsis.gui.command.Print.
public int print (Graphics g, PageFormat pf, int pi)
throws PrinterException {...}
Les stand viewers sont placés dans le package capsis.extension.StandViewer et d'autres packages en aval.
Parmis les stand viewers, certains sont destinés à être sous-classés pour servir de base à l'élaboration de visualisateurs spécifiques-modules. C'est le cas de SVSimple.
Ce visualisateur propose une représentation sous forme de carte vue de dessus des peuplements spatialisés. Il dessine les arbres à leur place par un cercle proportionnel au diamètre trouvé dans la définition de GTree. Si le peuplement est relié à un terrain (GPlot), SVSimple tente de dessiner les cellules de terrain. Des options de représentation sont proposées dans une boîte de dialogue de paramétrage et on peut appliquer des seuils sur le diamètre des arbres à représenter. La zone utile du visualisateur supporte des fonctionnalités de zoom et de déplacement commandés par la souris, ainsi qu'une fonctionnalité de sélection dont le résultat est un panel d'introspection par arbre contenu dans le rectangle de sélection. Ces panels sont disposés par SVSimple dans une boîte de dialogue.
Le modélisateur qui souhaite spécialiser SVSimple procède par dérivation. Les méthodes de dessin de l'arbre et de la cellule de terrain (le cas échéant) sont réécrites pour rendre plus précisément les propriétés de l'arbre du modèle. Par exemple, si l'arbre possède un rayon de base du houppier, on peut dessiner des disques de rayon proportionnels et de coulleur fonction de la hauteur de l'arbre (cf. capsis.extension.standviewer.SVMountain). Il est possible de spécifier des options particulières à la nouvelle version de visualisateur, elles apparaissent dans un deuxième onglet de la boîte de paramétrage.
Dans les packages capsis.extension.standviewer et inférieurs, voir View2D, SVText, SVSimple, SVMountain, SVVentoux.
Cette section traite de deux type d'extensions qui fonctionnent généralement ensemble. Les extracteurs de données constituent des séries de données par lecture d'un étape ou d'une suite d'étapes en mémoire. Les metteurs en forme présentent ces données sous forme de courbes, de tables etc...
Capsis4 propose une série d'extracteurs de données génériques pour extraire des grandeurs forestières classiquement utilisées dans la profession (surface terrière, diamètre ou hauteur dominante ou de l'arbre moyen...). Ces extracteurs s'appuient parfois sur les fournisseurs de méthodes des modèles (cf. § 2.4.9).
Les extracteurs de données construisent des structures de données d'un format décrit parmis les formats regroupés dans le package capsis.extension.dataextractor.format. Ces structures de données sont visualisables par les rendeurs de données compatibles avec ces formats.
Les extracteurs et rendeurs de données sont gérés dans le contexte de pilotage interactif par un OutputMediator qui « écoute » les actions dans le gestionnaire de scénario. En fonction de ses actions, il crée, modifie ou supprime les extracteurs de données sélectionnés à un moment donné dans la fenêtre des sorties graphiques (OutputBox) et rafraichit les rendeurs de données connectés.
OutputMediator peut également proposer les rendeurs alternatif compatibles et gérer les modifications de rendeur (ex: courbe -> table).
On peut immaginer que les extracteurs et rendeurs de données soient utilisés dans d'autres domaines, par exemple dans un visualisateur de peuplement générique.
Les extracteurs de données ont été conçus pour pouvoir caluler des grandeurs dendrométriques données à partir d'étapes de références de scénarios sylvicoles associés à des modèles différents.
Le but est de comparer sur le même graphe des données de différents scénarios à des fins de comparaisons (modèles différents, paramétrages différents, sylvicultures différentes...).
Dans cette optique, plusieurs extracteurs de données chacun synchronisé sur une étape de référence sont regroupés autour d'un DataBlock qui est relié à un rendeur de données courant. Le rendeur dessine les données de chaque extracteur du bloc.
Les extracteurs de données implémentent une des interfaces de capsis.extension.dataextractor.format qui définit leur type.
Les extracteurs reliés à un DataBlock sont tous du même type (et même de la même classe) et sont paramétrés de manière cohérente. Ainsi, si l'on raisonne en hectare, tous les extracteurs du bloc sont configurés pour fonctionner par hectare. Certains extracteurs utilisent par ailleurs des éléments de configuration individuels. Ainsi, deux extracteurs pourront suivre l'évolution de la hauteur pour deux groupes d'arbres donnés.
Il y a par conséquent deux niveaux de configuration pour les extracteurs de données : configuration commune à tous les extracteurs reliés au même bloc (multi-configuration) et configuration individuelle.
Les extracteurs de données implémentent deux interface pour gérer ces aspects de configuration.
La multi-configuration est gérée par l'interface capsis.util.MultiConfigurable :
public interface MultiConfigurable {
public String getMultiConfLabel ();
public ConfigurationPanel getMultiConfPanel (Object param);
public void multiConfigure (ConfigurationPanel p);
public void postConfiguration ();
La configuration indivudiuelle est gérée par l'interface capsis.util.Configurable :
public String getConfigurationLabel ();
public ConfigurationPanel getConfigurationPanel (Object param);
public void configure (ConfigurationPanel panel);
Les spécifications des extracteurs de données sont décrites dans la classe abstraite capsis.extension.DataExtractor. En plus d'Extension qu'elle implémente et des deux interfaces de configuration, elle définit :
Des méthodes liées à l'héritage de propriétés de configuration :
// Used by subclasses to choose config properties
abstract public void setConfigProperties ();
// Used by subclasses to add config properties
public void addConfigProperty (String property) {
// Used in configuration panels to add needed components.
public boolean hasConfigProperty (String property) {
Ces méthodes sont liées à la configuration des extracteurs et permettent d'hériter de champs de configuration automatiquement dans les panneaux de configurations.
Des méthodes liées au paramétrage courant de l'extracteur :
// Asks the extension manager for last version of
// settings for this extension type.
protected void retrieveSettings () {
public DESettings getSettings () {
Les settings sont une sous classes de GSettings, ils sont sérialisés par le gestionnaire d'extension à chaque modification et récupérés depuis le disque à chaque nouvelle session Capsis4.
Des méthodes liées à l 'étape de référence :
// Changes current step.
public void setStep (Step stp) {
public Step getStep () {return step;}
Des méthodes liées à la restriction à un groupe d'éléments et à l 'extraction proprement dite :
* If a group was selected in settings, apply it to GStand or GPlot.
* This method should be called from doExtraction if needed.
public Filtrable doFilter (Filtrable s) {
* Effectively process the extraction.
* Return false if trouble.
abstract public boolean doExtraction ();
Les sous classes implémentant concrètement les extracteurs redéfinissent doExtraction () pour procéder à la lecture des données et construire le résultat en fonction des options courantes.
Une méthode pour récupérer le metteur en forme par défaut :
* From DataFormat interface.
* NOTE: This is an abstract class : DataFormat.getName () and
* DataFormat.getCaption () are not implemented here.
public String getDefaultDataRendererClassName () {
Des méthodes relative à l'aspect :
* Returns the color of the step button of the step of the output.
* If step button has no color, returns another color.
public void setHidden (boolean val) {
public boolean isHidden () {
Packages capsis.extension.dataextractor et inférieurs, voir un exemple d'extracteur de données Configurable : DETimeH. Un extracteur MultiConfigurable : DETimeG.
Les rendeurs de données savent représenter d'une manière donnée un format de donnée connu. Les formats sont décrits dans le package capsis.extension.dataextractor.format. Les extracteurs de données implémentent l'interface du format qu'ils produisent (cf. § 4.4.1). Ils sont donc directement représentables par les rendeurs de données.
Pour vérifier la compatibilité d'un renderer avec un extracteur, le gestionnaire d'extension invoque sa méthode matchWith () en lui passant l'extracteur. Voilà la définition de matchWith () dans DataRenderer (la superclasse des data renderers).
// "matchWith" mecanism for DataRenderers.
// If method not implemented by subclass, this will write
// a note in log
// and forbid the subclass use (return false).
static public boolean matchWith (Object target) {
Remarques : matchWith () est une méthode de classe (static). Le gestionnaire de scénarios peut l'invoquer dynamiquement sans référence vers une instance de la classes, mais en se contentant de charger la classe. Si un renderer ne redéfinit pas matchWith (), l'implémentation de DataRenderer envoie un message d'erreur vers la Log.
C'est par ce dispositif qu'un data renderer peut vérifier sa compatibilité avec un extracteur. Par exemple, le data renderer DRCurves représente des données de type DFCurves (DataFormat). Sa méthode matchWith () est la suivante :
if (target instanceof DataExtractor
&& target instanceof DFCurves) {b = true;}
Ce procédé de vérification de compatibilité est très robuste et il devrait être généralisé pour d'autres types d'extensions.
Les rendeurs de données sont configurables. DataRenderer implémente l'interface Configurable et peut donc renvoyer un panneau de configuration à partir duquel il peut ensuite se configurer.
Les rendeurs de données possèdent d'autre méthodes, dont des méthodes de mise à jour :
public void update (int w, int h) {
Des méthodes d'ordre général :
public boolean isFrozen () {
public DataBlock getDataBlock () {
public int getUserWidth () {
public int getUserHeight () {
Et une classe interne définissant un menu contextuel qui apparaît à la demande de l'utilisateur. Des méthode de détection des clics souris décrivent la gestion de ce menu :
* DataRenderer's Popup menu.
class DataRendererPopup extends JPopupMenu implements ActionListener public void mousePressed (MouseEvent evt) {
public void mouseReleased (MouseEvent evt) {
Ce menu a une partie fixe (configuration...) et une partie créée dynamiquement et proposant une option par rendeur de données compatible. Quand l'utilisateur choisit l'un de ces rendeurs, il remplace le rendeur courant. Ces comportements sont hérités par tous les rendeurs de données de leur superclasse commune DataRenderer.
Il est bien sûr possible pour le modélisateur de créer d'autres types de formats de données, avec les extracteurs et rendeurs de données correspondant. C'est par ce système que l'on prévoit par exemple de reproduire les dessins d'arbres et les tableaux de productions de Capsis2.
Dans les packages capsis.extension.datarenderer et inférieurs, voir DRCurves, DRHistogram, DRScatterPlot et DRTable.
Ce sont des extensions destinées à remplir des fonctions d'ordre général, qui ne dépendent d'aucun modèle particulier. Elles sont détectées au démarrage par le gestionnaire d'extensions comme les autres extensions, mais la fenêtre principale (MainFrame) crée autant d'entrées dans un menu « Outils ».
On peut écrire plusieurs types d'outils, comme des éditeurs de texte, des moniteurs de surveillance des ressources urilisées par Capsis4 ou la JVM, ou des mécanismes facilitant le déverminage du code en montrant la structure de données par introspection par exemple.
Ces outils sont généralement développés pour fonctionner en contexte interactif et ont accès à la totalité de la structure de données de Capsis4.
Il est envisageable de créer ici des mécanismes de pilotage régulant les interactions de Capsis4 avec d'autres logiciels du même domaine à travers le réseau pour travailler à une tâche commune
Les generic tools sont des GenericTool (JInternalFrame) ou des GenericDialogTool (GDialog) qui implémentent Extension et Repositionable.
Cette dernière extension permet à un Positionner courant de placer la fenêtre contenant l'outil en respectant une stratégie de placement courante.
* From Repositionable interface.
public void reposition () {
Dans les packages capsis.extension.generictool.*, voir MemoryView et TextBrowser.
Les filtres sont des extensions s'appliquant sur des objets complexes que l'on peut « réduire » par filtrage. C'est par exemple le cas d'objets composés d'éléments sur lesquels ont peut donc opérer une sélection. Les objets sur lesquels on peut opérer des filtrages doivent implémenter l'interface Filtrable.
Les filtres sont destinés à être utilisés dans un contexte interactif ou non.
GStand et GPlot héritent de l'interface Filtrable. C'est classiquement sur des peuplements et sur des terrains que l'on opère des filtrages dans Capsis4.
Le résultat d'un filtrage sur un Filtrable est un autre Filtrable, ce qui permet de combiner des filtres, par exemple pour réduire une sélection petit à petit.
Les filtres servent de support à la création de groupes (cf § 2.2.6), mais ils peuvent avoir d'autres utilisations. Par exemple, l'intervener FilterThinner permet d'utiliser des filtres pour opérer des éclaircies dans un peuplement.
L'interface Filtrable spécifie notamment une méthode getFiltrationBase () dont l'implémentation doit renvoyer une base de filtration, image de l'objet auquel on la demande et prête à subir l'opération de filtrage. Si l'original contient des éléments, la base de filtration doit contenir des clones de ces éléments.
Généralement, le Filtrable renvoie un clone plus ou moins complet de lui même (en tout cas de même type). Ainsi, par exemple, GTCStand renvoie une copie de lui même contenant des copies de ses arbres, mais avec une référence vers son propre terrain (si la référence de terrain, qui est optionnelle, est renseignée). Cette disposition permet d'économiser le clonage de l'objet terrain (qui peut contenir beaucoup de cellules) qui n'est pas déterminant pour l'opération de filtrage.
Les filtres utilisent le dispositif de compatibilité matchWith () employé par le gestionnaire d'extension (cf. § 4.4.2)pour déterminer si une extension est compatible avec un objet donné. Le filtre vérifie qu'il peut filtrer l'objet qu'on lui passe (un Filtrable).
Ainsi par exemple, FThreshold vérifie les qualités suivantes pour la cible qu'on lui propose : Filtrable, GStand, TreeCollection, non vide, contenant des GTree.
Il est à noter que rien n'empêche d'écrire des filtres pour des GStand qui ne sont pas des TreeCollection (modèles peuplement).
Les filtres peuvent servir à montrer une partie seulement d'un Filtrable, à construire un groupe à partir d'une sélection d'éléments d'un Filtrable, ou encore dans un contexte d'éclaircie, à supprimer une sélection d'éléménts d'un Filtrable.
Les Filtres sont des sous classes de capsis.extension.Filter qui implémente les interfaces Extension et GenericFilter.
public interface GenericFilter {
public Filtrable apply (Filtrable f) throws Exception;
public boolean matchWith (Filtrable filtrable);
Il est à noter que la méthode matchWith () décrite par GenericFilter n'est pas statique et qu'elle prend un Filtrable. Elle permet de vérifier auprès d'un filtre générique (Filter ou AbstractGroup) qu'il peut être appliqué sur un Filtrable.
Filter décrit également la méthode statique matchWith (Object) utilisée par le gestionnaire d'extension.
La méthode d'instance s'appuie sur la méthode de classe (appel dynamique de l'implémentation de la méthode statique d'une sous classe) pour répondre.
La méthode apply () de GenericFilter recoit dans les sous classes le traitement de filtrage prorement dit, différent pour chaque filtre.
Cerains filtres pauvent être configurable. Il implémentent la méthode Configurable vue plus haut.
Les filtres sont au final des objets délicats à mettre en oeuvre et il convient d'être très attentif à leur performance (méthode apply ()) car ils peuvent être appelés souvent (par exemple, un extracteur en évolution sur n étapes travaillant sur un groupe constitué de trois filtres appliquera 3n fltres à chaque raffraichissement). La rapidité de réponse de getFiltrationBase () sur les filtrables est également déterminante.
Dans les packages capsis.extensions.filter.*, voir FThreshold, FTreeGridSelector, FTreeMouseSelector, FCellGridSelector, FIndividualSelector et FQualitativeProperty.
Les formats d'import/export sont un moyen de créer un peuplement (une classe implémentant GStand) à partir d'un fichier inventaire et/ou de créer un fichier inventaire à partir du peuplement.
Lors de la phase de récupération des paramètres initiaux déléguée au pilote du module, qui doit renvoyer un StandInitializer (cf. § 2.3.2), il est possible dans une méthode fonctionnelle du module de faire appel à un format d'import pour charger un fichier au format connu.
De même, pour une étape de référence, il est possible d'exporter des données vers un fichier en utilisant un format d'exportation (ex: par un menu contextuel en mode interactif).
Ces formats sont des extensions héritant de capsis.util.RecordSet et implémentant l'interface capsis.extension.IOFormat.
public interface IOFormat extends Extension {
* Load an import format into an imported GStand.
public GStand load (GModel model) throws Exception;
* Save a export format into an export file.
public void save (String fileName) throws Exception;
* Tell if format allows import.
public boolean isImport ();
* Tell if format allows export.
public boolean isExport ();
RecordSet est une sous classe de Vector qui propose un appareillage pour automatiser les opération RecordSet -> fichier et fichier -> RecordSet. Il reste au développeur à écrire les méthodes load () (RecordSet -> GStand) et createRecordSet (MountStand stand) (GStand -> RecordSet).
RecordSet est un ensemble d'enregistrements qui héritent tous de capsis.util.Record. Cette classe fournit un constructeur qui prend une ligne (chaine de caractères) et tente de construire avec une instance d'elle même par introspection en appliquant un StringTokenizer sur la ligne pour en extraire les éléments.
RecordSet décrit certains formats d'enregistrements qui peuvent donc être utilisés dans tous les fichier import/export (hérités) :
KeyRecord : de type clé = valeur. Evaluation dans la méthode load () par le modélisateur et chargement des valeurs dans les variables d'instances souhaitées. Des accesseurs permettent de récupérer la valeur dans le type souhaité (ex: double getDoubleValue ()) ;
EmptyRecord : une ligne blanche ;
CommentRecord : une ligne de commentaire commençant par le caractère '#' ;
FreeRecord : une ligne au format libre. Cette ligne n'ayant pas de schéma, elle ne peut pas être reconnue lors d'une importation. FreeRecord sert donc seulement à l'exportation.
Dans son format (classe dérivant de RecordSet par le biais de StandRecordSet ou de ParameterRecordSet), le modélisateur décrit ses formats d'enregistrements de la même manière : classes internes public static étendant Record, avec un constructeur par défaut faisant appel à celui de la superclasse et un constructeur prenant une chaîne de caractères (une ligne de fichier) et invoquant le constructeur de la superclasse de meme signature. Les variables d'instance de la classe interne sont publiques et dans l'ordre attendu dans la ligne du fichier.
Chargement en mémoire:
C'est la méthode (implémentation par introspection) createRecordSet (String fileName) qui lit le fichier ligne à ligne et tente pour chacune d'entre elle de créer un Record dont il connaît la description. Les descriptions d'enregistrement sont des classes internes de RecordSet et de la sous classe considérée qui implémente le format. Le résultat du chargement de RecordSet est que le Vector contient un Record par ligne « utile » du fichier d'entrée. Au cas où une ligne du fichier d'entrée ne permet de construire aucun Record connu, une exception est lancée pour signifier une erreur de format de fichier.
Une fois le RecordSet créé, la méthode load () (implémentée par le développeur) est utilisée pour construire un GStand. Pour cela, il convient d'itérer sur les enregistrements du RecordSet et d'en reconnaître le type avec l'opérateur instanceof. Pour chaque ligne, créer un arbre, une cellule de terrain ou toute autre structure de données prévue par le modélisateur.
Exemple : la méthode fonctionnelle de chargement de fichier d'inventaire de mountain.model.MountModel (utilisation directe, sans passer par le gestionnaire d'extensions) :
* Loads the inventory file given in parameter.
* File format is described in MountInventory.
public GStand loadInitStand (String fileName) throws Exception {
// this == model
GStand initStand = new MountInventory (fileName).load (this);
return initStand;
Ecriture sur disque :
L'écriture sur disque consiste en la création du RecordSet à partir du peuplement (par la méthode createRecordSet (GStand) à implémenter par le modélisateur), puis à l'écriture proprement dite par la méthode save (String fileName) fournie par RecordSet et utilisant la méthode toString () de chaque Record.
(1) Dans DExport : GStand -> RecordSet
ExtensionManager em = ExtensionManager.getInstance ();
ExtensionStarter starter = new ExtensionStarter ();
starter.setStand (Current.getStepButton ().getStep ().getStand ()); // export mode
String cn = (String) extensionKey_classname.get (formatClassName);
ioFormat = (IOFormat) em.loadExtension (cn, starter);
(2) Dans ExportStep : RecordSet -> File
// Export format class name is retrieved from DExport dialog
IOFormat ioFormat = dlg.getIOFormat ();
String fileName = dlg.getFileName ();
// 4. Export now
ioFormat.save (fileName);
Dans les packages capsis.extension.ioformat.*, voir MountInventory et EptusInventory.
5.1 Utilisation de Capsis4
Se positionner dans le répertoire bin/.
Pour Win32: capsis [options]
Pour Unix: ./capsis.sh [options]
liste des options : faire capsis -h
5.1.2 Modèles disponibles
Aide > A propos
5.1.3 Création d'un projet
Projet > Nouveau - nom: a - modèle: Mountain - [Initialiser]
Fichier inventaire: data/benoit/bc2001/Ort3AvantEclNF.inv
Terrain: [Réglage] - Cellules: [Définir] - Côté: 10 (m.)
[Ok]... [Ok]
5.1.4 Gestionnaire de scénario
S'ouvre après la création du nouveau projet.
Clic et ctrl-clic sur étapes: sélections avec couleurs pour synchronisation avec les outils d'étape (cf. plus bas).
Vérifier que l'option Afficher > Visualisateurs est cochée (et Afficher > Sorties décochée).
5.1.5 Configuration projet
Configuration: ctrl-clic sur titre projet ou sélection projet et Projet > Configurer ou Menu contextuel > Configurer Projet.
Sélection Projet: clic sur titre projet ou Menu contextuel > Sélectionner Projet ou clic sur une étape du projet (étape courante) puis Projet > Sélectionner.
Visibilité: [Changer] puis sélectionner les étapes intermédiaires qui deviendront visibles dans le gestionnaire de scénarios.
Fréquence: laisser inchangé (en développement).
Onglet Paramètres:
Paramétrage du projet : c'est un introspecteur en lecture seule sur l'objet Settings du module : module.model.ModSettings.
Valeurs par défaut dans les constantes (en majuscules).
Valeurs courantes dans les variables (en minuscules).
Onglet Visualisateurs:
En cocher un à la fois pour des raisons d'encombrement.
Sélectionner le Visualisateur Mountain.
5.1.6 Visualisateurs
Les visualisateurs graphiques présentent des fonctionnalités communes :
Sélection rectangulaire bouton gauche: zoom.
Bouton droit: zoom arrière.
Ctrl-bouton gauche et déplacement: translation.
(Ctrl) double-clic gauche: (dé) sélection.
(Ctrl) sélection rectangulaire bouton droit: (dé) sélection multiple.
Bouton seuil:
Actions sur des seuils de diamètres pour:
Vue détaillée / grossière en fonction de la proximité de l'observateur à l'arbre.
Non représentation des petits arbres.
Non représentation des gros arbres.
Les boutons rouges annulent l'effet du seuil considéré.
La sélection d'arbres ouvre des boîtes de dialogues contenant des introspecteurs sur les arbres dans la sélection.
Préférences: explorer, peut contenir plusieurs onglets.
5.1.7 Evolution
Menu contextuel étape > Evolution - Année: 15 ans.
Remarque pour Mountain: ensoleillement tous les 5 ans.
5.1.8 Intervention
Menu contextuel étape > Intervention - Type: Eclaircie Sélective - Méthode: Eclaircie par filtrage - Sélecteur graphique - Bouton [>] pour sélectionner le filtre (la boîte de dialogue de configuration apparaît - Bouton [V] pour faire apparaître le témoin.
Paramétrer le filtre choisi: un martelodrome à la souris offrant les mêmes possibilités de manoeuvre à la souris que le Visualisateur Mountain.
La sélection rougit les arbres qui seront coupés.
Raffraîchir le témoin par action sur le bouton [Raffraîchissement].
Faire une sélection au milieu de la placette.
Remarque : Réensoleillement de la placette après éclaircie pour Mountain.
Puis: Evolution 20 ans.
5.1.9 Sorties graphiques
Afficher > Sorties graphiques.
Remarque: Enlever les visualisateurs (encombrement, synchronisation différente).
La boîte de sorties apparaît. Cocher Surface terrière.
(Ctrl) cliquer dans le gestionnaire de scénarios. Des synchronisation de la sortie graphique ont lieu.
Plusieurs boutons sélectionnés: plusieurs courbes de couleurs correspondantes.
Exemple: Observer les étapes de référence 15 et 20. Effet de l'éclaircie du deuxième scénario.
Menu contextuel: changer de rendeur.
Menu contextuel > Configurer.
Onglet Rendeur: diverses options.
Onglets extracteurs:
Options liées aux extracteurs (un par série de données, ex: un par courbe dans notre exemple).
Cocher "par hectare" - [Ok].
Le titre change, ainsi que le label de l'axe des Y.
5.1.10 Groupes
Etape racine - Menu contextuel > Grouper.
Onglet Groupe:
Nom: "small".
Laisser les autres options (arbre / dynamique).
Onglet Définition:
Choisir un filtre, le passer dans la liste des sélectionnés et le configurer.
Choisir "Seuils Age, Diamètre, hauteur" - Diamètre (cm.) - Seuil bas: rien - Seuil haut: 15 cm.
Contrôler l'action dans le témoin - [Ok].
Le groupe existe, il est géré par un gestionnaire de groupe qui le tien à disposition des demandeurs et il sera sauvé à la fin de la session Capsis4 pour être réouvert automatiquement à la prochaine utilisation.
Utilisation du groupe:
Visualisateurs: dans le Visualisateur Mountain: bouton [Préférences], cocher "Montrer le groupe" et choisir "small" - [Ok].
Sorties graphiques: dans "Surface terrière" - Menu contextuel > Configurer > Commun - cocher "Montrer le groupe" et choisir "small" - [Ok].
5.1.11 Sauvegardes
Les répertoires de sauvegarde proposés sont les derniers qui ont été utilisés dans les boîtes de dialogue Enregistrer sous. On peut modifier ces répertoires à tout moment par Editer > Options - Onglet Répertoires.
Par projet:
Projet (le sélectionner d'abord) > Enregistrer sous - dans projet/a - [Ok].
Session (facultatif, si plusieurs projets par exemple) > Enregistrer sous - dans session/a - [Ok].
La session n'est constituée que des chemins sur disque des projets qui la composent. Les projets sont sauvés indivuduellement pendant l'opération de sauvegarde de la session pour être réouverts seuls le cas échéant.
Réouverture par:
Projet > Ouvrir.
Session > Ouvrir.
5.1.12 Impression
Fichier > Configurer Impression: choix de la source - mise en page - aperçu.
Fichier > Imprimer: imprime ce qui a été configuré dans Configurer Impression.
5.2 TD Construction d'un Modèle
Construction du module Sapin :
package : sapin
préfixe : Sap
Un Modèle Arbre Dépendant des Distances (MADD) avec croissance en diamètre et en hauteur et une méthode sommaire de régénération.
A partir du squelette de module sapin existant, mettre en place les fonctionnalités suivantes :
(1) Identité.
Modifier les propriétés relatives à l'identité de l'auteur et son organisme : vous.
(2) Age des arbres.
Mettre en place une propriété age dans les arbres.
Initialiser l'âge de l'arbre récupéré dans le fichier d'inventaire.
Format de fichier : capsis.extension.ioformat.SapInventory
Incrémenter l'âge chaque année.
Voir : capsis.kernel.GTree
(3) Terrain
Associer au peuplement un terrain rectangulaire de cellules carrées de 10m. de côté.
Voir : capsis.extension.ioformat.MountInventory.load ()
mountain.model.MountStand
capsis.kernel.RectangularPlot
(4) Taille de la cellule.
Ajouter au modèle un paramètre taille de cellule (décimal) cellWidth.
La taille par défaut est de 10m. (c'est un carré).
Ajouter au dialogue initial une zone de saisie pour choisir la taille.
(5) Régénération.
Ecrire une méthode sommaire de régénération.
Exemple : Chaque année, on ajoute entre 0 et 4 arbres dont les coordonnées sont calculées automatiquement pour tenir dans les limites du peuplement. La hauteur initiale est comprise entre 0 et 1m. Le diamètre initial est de 1cm.
Le squelette de module Sapin a été pré-construit pour démarrer le TD. Il convient de déclarer l'auteur du nouveau module Sapin, ainsi que son organisme.
Modifier dans sapin.model.IdCard : modelAuthor et modelIntitute.
L'âge est définit dans GTree. L'implémentation de départ de SapTree ne l'utilise pas. L'âge n'est donc pas requis dans les constructeurs de SapTree et la valeur 0 est passée au constructeur des superclasses (GMaddTree et GTree en l'occurence).
Rétablir l'âge dans les constructeurs de SapTree, les passer au constructeur de la superclasse. Répercuter dans les classes qui utilisent ces constructeurs.
SapInventory : modifier TreeRecord : ajouter public int age après id
Modifier le fichier d'inventaire data/form/sapsin1.inv en conséquence : ajouter une colonne âge.
SapInventory.load () : affecter l'âge lu dans l'inventaire à l'arbre.
SapInventory.createRecordSet (SapStandstand) : renseigner l'âge du TreeRecord.
(3) Terrain.
La création d'un terrain se fait en deux étapes.
La décision consiste en l'invocation de la méthode createPlot () de la classe peuplement du modèle.
Dans SapModel.loadinitStand (), avant return iniStand ou dans capsis.extension.ioformat.SapInventory.load () :
iniStand.createPlot (this, 10); // 1. décision (this = sapModel)
Remarque : tous les arbres sont chargés avanrt la création du terrain.
La mise en oeuvre consiste en la redéfinition de la méthode createPlot () pour choisir le type de terrain souhaité. C'est ici qu'il est possible d'instancier un PolygonalPlot ou une sous classe de RectangularPlot (SapPlot ?) qui dans son constructeur décide le la classe cellule à utiliser (si on en utilise une : SapCell ?).
Dans SapStand.createPlot () :
plot = new RectangularPlot (this, cellWith); // 2. mise en oeuvre
((RectangularPlot) plot).createCells ();
makeTreesPlotRegister ();
(4) Taille de cellule.
Dans la classe SapSettings :
public static final double CELL_WIDTH = 10d; // m.
public double cellWidth = CELL_WIDTH;
Dans la classe SapDInitStand :
Déclarer une VI private JTextField cellWidth;
Ajouter une ligne dans la boite de dialogue : dans createUI (), à la suite de l5,
JPanel l6 = new JPanel (new FlowLayout (FlowLayout.LEFT));
cellWidth = new JTextField (5);
cellWidth.setText (""+sapSettings.cellWidth);
l6.add (new JWidthLabel (
Translator.swap (SapDInitStand.cellWidth)+" :", 160));
l6.add (cellWidth);
modelParameters.add (l6);
Controler la saisie dans okAction () : en utilisant Check.isDouble ()
Puis : sapSettings.cellWidth =
new Double (cellWidth.getText ()).doubleValue ();
Enfin, utiliser cette valeur dans l'invocation de createPlot () au lieu de 10 : sapSettings.cellWidth -> cf (3)
Dans SapModel, écrire une méthode processRegeneration () appelée dans processEvolution ().
Voir exemple de correctif dans form/.
5.3 TD Construction d'un Intervener
Sur le modèle de capsis.extension.intervener.SapThinner.
SapThinner est un éclaircisseur simple qui propose de couper les arbres suivant une fréquence donnée (un arbre sur n). Il est utilisable en mode console ou interactif. Il dispose d'une boîte de dialogue asservie pour saisir le paramètre fréquence.
L'éclaircisseur a deux modes de fonctionnement : "coupe" ou "marque". Pour déterminer son mode de fonctionnement, il interroge le modèle du projet de l'étape sur laquelle il opère.
Pour agir, il passe en revue les arbres du peuplement de l'étape de référence et coupe un arbre sur n.
A partir du squelette de mécanisme d'intervention existant, mettre en place la fonctionnalité suivante : Ajouter la coupe de tous les arbres en dessous d'un diamètre limite.
(1) Ajout et renseignement de la nouvelle VI.
Dans SapThinner, sous la VI frequency, ajouter la VI dbhMin.
Dans SapThinnerStarter, ajouter la VI pour utilisation en mode console.
Dans le constructeur de l'intervener, au retour du dialogue d'initialisation, mémoriser la valeur saisie dans la VI.
Dans le constructeur du mode console, mémoriser la valeur trouvée dans le starter dans la VI.
(2) Dialogue.
Rajouter une VI de type JTextField avec un accesseur.
Rajouter un label et un champ à la boîte de dialogue pour la saisie par l'utilisateur.
Compléter les contrôles de saisie par des contrôles sur la valeur de dbhMin : non vide, un décimal, supérieur à zéro. La boîte de dialogue doit tester toutes les erreurs possibles et envoyer des messages à l'utilisateur pour l'aider à la correction jusqu'à une saisie correcte. Alors seulement, elle peut se fermer sur "Ok".
(3) Assertions.
L'intervener vérifie des assertions quel que soit son mode. Rajouter les assertions concernant dbhMin : il doit être supérieur à zéro (à ce stade, on travaille sur un double et les question de type ne se posent plus).
Prendre en compte le seuil minimal dans l'action de l'intervener.
Les arbres ayant un diamètre inférieur au seuil sont coupés (ou marqués), pour les autres, on coupe 1 / n en fonction de la fréquence choisie.
(5) Trace.
Compléter la trace que l'objet peut renvoyer de lui même sous forme d'une chaîne de caractères.
(6) Internationalisation.
Ajouter les labels de traduction introduits au cours du TD dans les fichiers langages français et anglais.
capsis.extension.intervener.SapThinner
capsis.extension.intervener.SapThinner_fr.properties et SapThinner_en.properties.
Ajouter une entrée pour l'éclaircisseur dans capsis.extensions.
5.4 TD Construction d'un StandViewer
Sur le modèle de capsis.extension.standviewer.SVSapin.
SVSapin est un visualisateur de peuplements graphique héritant de capsis.extension.standviewer.SVSimple, ce qui lui confère directement les fonctionnalités suivantes :
Représentation des cellules de terrain (si le modèle en gère) ;
Représentation des arbres à leur emplacement (vue cartographique) ;
Zoom et déplacement à l'aide de la souris sur le terrain ;
Interrogation des propriétés des arbres sélectionnés à la souris par introspection ;
Options permettant de changer des couleurs, voir ou enlever les labels ou les arbres, se restreindre à un groupe préparé à l'avance ;
Limitation de la vue aux arbres dont le diamètre est compris dans les limites de seuils bas et haut choisis, possibilité de changer de niveau de détail quand on se rapproche de l'arbre (proche, loin).
A partir du squelette de ce visualisateur, ajouter les fonctionnalités suivantes : Colorer les cellules en fonction de l'effectif quelles portent et représenter les houppiers.
(1) Coloration des cellules.
Redéfinir la méthode drawCell () de SVSimple, évaluer l'effectif en arbres porté par chaque cellule et changer de couleur en fonction de 5 classes (-5, 10, 15, 20, +20).
Ne remplir la cellule que si son dessin intersecte le rectangle représenté à l'écran (zooms).
Ne pas oublier de redessiner le bord de la cellule s'il y a lieu avec la couleur de cellule choisie dans les options de SVSimple.
(2) Représentation des houppiers.
Le modèle Sapin calcule le rayon de la base du houppier, que SVSimple ne connaît pas et ne peut donc pas représenter.
Dans la méthode drawTree (), dessiner un cercle pour représenter la courone en plan.
Utiliser une Shape : Ellipse2D.Double (x, y, w, h). On travaille en coordonnées utilisateur.
Ne dessiner la courone que si elle intersecte le rectangle représenté à l'écran (zooms).
Voir l'exemple de correctif dans form/.
capsis.extension.standviewer.SVSapin
SVSapin-fr.properties et SVSapin_en.properties
Ajouter une entrée pour SVSapin dans capsis.extensions.
5.5 TD Construction d'un MethodProvider et d'un DataExtractor
Sur le modèle de capsis.util.methodprovider.MaddMethodProvider, GProvider, capsis.extension.dataextractor.DETimeN.
Pour ce TD, reproduire les conventions de nommage rencontrées pour les noms de fichiers, de classes et de méthodes. Mettre à jour les champs auteur et les commentaires. Reproduire le cas échéant les fichiers langages français et anglais obligatoires et les mettre à niveau (clés + traductions).
(1) MethodProvider.
Construire un MethodProvider pour Sapin, reprenant les fonctionnalités de MaddMethodProvider et ajoutant une méthode de calcul sommaire du couvert forestier.
La méthode de calcul du couvert du nouveau method provider sera créée de manière à pouvoir être par la suite être remonté dans MaddMethodProvider, constituant une méthode générique (pas de référence à Sapin). Prendre des précautions pour assurer par la méthode la vérification de sa compatibilité avec le peuplement cible (sur le modèle de GProvider).
Pour le couvert, calculer la somme des aires des houppiers à leur base, sans gérer les recouvrements.
(2) DataExtractor.
Construire un nouveau DataExtractor pour exploiter la nouvelle méthode de calcul de couvert en s'appuyant sur un extracteur en évolution par rapport au temps, par exemple DETimeN.
Le nouvel extracteur devra fournir les capacités de paramétrage "par hectare" et "montrer un groupe" des autres extracteurs en évolution.
Rappel : les extensions sont déclarées dans le fichier etc/capsis.extensions.
capsis.util.methodproviderCoverProvider et CrownRadiusProvider
capsis.extension.dataextractor.DETimeCover
DETimeCover_fr.properties et DETimeCover_en.properties
sapin.model.SapMethodProvider
SapModel.createMethodProvider ()
SapTree implements CrownRadiusProvider
capsis.extensions : ajouter DETimeCover
Dreyfus96: Ph Dreyfus, F.-R. Bonnet - INRA Unité de Recherches Forestières Méditerranéennes, av. Vivaldi, 83000 Avignon, France, CAPSIS - An interactive simulation and comparison tool for tree and stand growth, silvicultural treatments and timber assortment, 1996, IUFRO WP S5.01-04 Biological Improvement of Wood Properties
Gosling96: J. Gosling, B. Joy, G. Steele, The Java Language Specification (Java Series), 1996
Cormen90: Th. Cormen, Ch Leiserson, R. Rivest , Introduction to algorithms, 1990
Gamma95: E. Gamma, R. Helm, R. Johnson, R. Vlissides, Design Patterns : Elements of rRusable Object-Oriented Software, 1995, Addison-Wesley Professional Computing
documentation/doc_reference_v1_0.txt · Last modified: 2013/05/23 08:25 (external edit)

References: § 2
 § 2
 § 2
 § 2
 § 2
 § 2
 § 2
 § 2
 § 2
 § 2
 § 2
 § 2
 § 2
 § 4
 § 4
 § 2
 § 2
 § 4
 § 2
 § 4
 § 2