![]() |
L'encapsulation La commande "lpgrp" |
--ooOoo--
Le professeur de mathématiques m'exposa ses difficultés pour démarrer. Il me confirma un peu plus en détail ce qu'il attendait de ce type de fonction. Il était plutôt intéressé par l'aspect graphique pour permettre à ses élèves d'afficher des courbes étudiées en classe. Il devait donc pratiquement faire un programme à chaque type d'étude. De plus, l'aspect "saisie" de l'interactivité devait être prise un minimum en compte. Je lui objectais qu'une méthode plus générale devrait être préférable et que, de toutes manières, il lui faudrait traiter des primitives normalisées dont les élèves devraient apprendre le codage.
J'étais en train de travailler sur mes curses personnelles "jprs" à ce moment-là pour écrire une petite commande "lpgdb" de debugging interactif qui encapsule la commande standard "gdb" de Linux, simplement pour évaluer la difficulté, pour voir, par curiosité. Je lui proposai de l'aider un peu plus en tâchant de réaliser un outil un peu plus général basé sur des primitives délibérément orientées graphiques. Je lui en expliquai les principes et la manière de l'aborder dans ses grandes lignes.
Personnellement, je regrette que, pour des raisons d'indisponibilité de part et d'autre, il n'ait pas pu suivre de plus près l'évolution de la programmation de cette commande "lpgrp", les corrections, les examens et les vacances d'été approchant à grands pas n'ayant rien arrangé aux choses.
Le développement étant en cours d'élaboration donc incomplet, j'en présente ici ses aspects théoriques et fonctionnels :
les primitives graphiques ainsi que les fonctions qui s'y rattachent :
les traitements du dialogue interactif en mode console.
I - Les structures graphiques :
Pour présenter des courbes et plus généralement des dessins, l'utilisateur doit suivre quelques principes de composition du document qu'il compte réaliser. La figure ci-dessous illustre la structure des images de la composition de l'exemple "lissajous" :
Pour élaborer sa composition, l'utilisateur doit effectuer les opérations suivantes :
choisir en tout premier lieu un support (le support P sur la figure ci-dessus) : une fenêtre d'écran, une imprimante sur laquelle il imprimera sa feuille de papier, etc..., ainsi que le format et le type (un papier peint grisé encadré de rouge par exemple),
dans un repère orthonormé,
confectionner les images A,
B,
C,
D
qu'il va appliquer sur le support à des endroits bien choisis A',
B',
C',
D'
du support P.
On imagine que ces images sont plaquées d'abord sur des peaux de
caoutchouc, élastiques qui seront étirées au moment
de l'application. C'est le cas des deux images B,
C
qui s'appliquent sur B',
C'. Pour
soutenir ce cas, les images sont définies par les quatre points
d'un quadrilatère de projection.
Pourquoi ce choix ? L'exemple des courbes
de Lissajous concernent des élèves des classes qui connaissent
et manipulent les fonctions trigonométriques
utilisées aussi dans les transformations d'images. L'intérêt
de la technique des quatre points permet justement de manipuler des images
sans l'usage de ces fonctions mathématiques beaucoup mieux à
la portée des plus petites classes où la notion
de coordonnées a été abordée.
Dans la commande "lpgrp", la notion d'image est repérée par un numéro, ce que nous verrons au § II :
le n°0 pour le support. Le support est tout naturellement considéré comme une image (*),
(*) Remarque :
Si l'on regarde les images de plus prêt, l'image A par exemple, la peau de caoutchouc rectangulaire blanche peut être considérée comme un support sur laquelle sont projetées les trois figurines, le titre "Programme Fortran", le sous-titre "une illustration des pseudo-terminaux" et le trait horizontal vert. On peut raisonner de même avec les autres images.
Si l'on descend encore une fois dans la décomposition, on pourrait imaginer que le titre "Programme Fortran" soit aussi une figurine qui est plaquée sur un support rectangulaire qui, lui-même, est projeté sur le support rectangulaire blanc de l'image A qui, à son tour, sera projetée sur le support P.
On en déduit donc que le concept d'image illustré ici est un concept récursif et qu'une image peut être décomposée en une suite d'images "fille-mère" en cascade.
On se trouve alors devant des entités graphiques :
à " 'n' dimensions + 2" pour une image dans le plan (2D),
à " 'n' dimensions + 3" pour une image dans l'espace (3D) comme des machines à commandes numériques (fraiseuses, pointeuses, tours,..),
à " 'n' dimensions + 5" pour certaines machines à commandes numériques dites "5 axes".
Cette théorie est appliquée dans le développement du "Noyau Graphique d'Images Structurées" (NGIS) limitée aux images dans le plan (2D).
II - Les attributs des primitives graphiques :
Les primitives graphiques s'appuient sur la bibliothèque 'SDL'. Leur approche tente de coller le plus possible au comportement naturel en la matière. Il faut rappeler que ces primitives sont des textes envoyés dans le "stdout" du programme encapsulé. Elles sont réunies sous la forme de fonctions dans le source "lpgrp_graph.c".
Remarquer au passage la faible
qualité des caractères représentant les codes des couleurs
et des grains. Cette qualité est très limite au niveau de la librairie
TTF de la SDL, cela n'arrange pas les choses quand on traite les textes pour
qu'ils se placent exactement dans des images appropriées définies
par l'utilisateur.
Presque toutes les directives admettent un attribut
comme paramètre en tant que chaîne de caractères où
chaque caractère positionnel définit.
Dans la palette par défaut, le codage des couleurs est défini par un caractère pouvant prendre 32 valeurs, du caractère "0" au caractère "9" puis du caractère "A" au caractère "V" (majuscule ou minuscule). Mais une directive "$palette{*}:" permet d'affecter à l'une de ces valeurs une composante des trois couleurs de base rouge, vert, bleu :
'_' : le pixel de l'attribut remplace le pixel existant de l'image,
'E' : l'opération logique 'ET' est appliquée entre le pixel de l'attribut et le pixel existant de l'image,
'O' : l'opération logique 'OU' est appliquée entre le pixel de l'attribut et le pixel existant de l'image,
la description de l'attribut des grains :
Toutes les primitives qui appliquent un grain sur une image voient leur paramètre 'attribut' codé sur 8 octets terminé par le caractère '\0' et qui conditionne la fonction de remplissage :
- octet '0' | : | code du grain à appliquer (transparent) | ||
= | ' ' ou '_' | : | pas de grain à appliquer (transparent) | |
= | '0'-'9','A'-'V' | : | code du grain | |
- octet '1' | : | code du contour | ||
= | ' ' ou '_' | : | pas de contour | |
= | '0'-'9','A'-'V' | : | épaisseur du contour ('0' : 1 trait, '1' : 2 traits, '2' : 3 traits, etc... | |
- octet '2' | : | code de la couleur à appliquer à l'encre du grain | ||
= | ' ' ou '_' | : | remplacé par '1' (noir) | |
= | '0'-'9','A'-'V' | : | code le la couleur de l'encre du grain | |
- octet '3' | : | code de la couleur à appliquer à fond du grain | ||
= | ' ' ou '_' | : | remplacé par '0' (blanc) | |
= | '0'-'9','A'-'V' | : | code le la couleur du fond du grain | |
- octet '4' | : | code de la couleur à appliquer au contour du grain | ||
= | ' ' ou '_' | : | remplacé par '1' (noir) | |
= | '0'-'9','A'-'V' | : | code le la couleur du contour du grain | |
- octet '5' | : | code du type de trait à appliquer au contour du grain | ||
= | ' ' ou '_' ou '0' | : | pas de contour | |
= | '1'-'9','A'-'V' | : | type de trait du contour | |
- octet '6' | : | mode d'application du grain | ||
= | ' ' ou '_' | : | remplacé par 'S' | |
= | 'S' | : | incrustation (le pixel de l'attribut remplace le pixel existant de l'image) | |
= | 'E' | : | opération logique 'ET' | |
= | 'O' | : | opération logique 'OU' | |
= | 'X' | : | opération logique 'OU EXCLUSIF' | |
- octet '7' | : | mode d'application du contour du grain | ||
= | ' ' ou '_' | : | remplacé par 'S' | |
= | 'S' | : | incrustation (le pixel de l'attribut remplace le pixel existant de l'image) | |
= | 'E' | : | opération logique 'ET' | |
= | 'O' | : | opération logique 'OU' | |
= | 'X' | : | opération logique 'OU EXCLUSIF' |
la description de l'attribut des tracés de traits (vecteurs) :
Toutes les primitives de tracés de vecteurs dans une image voient leur paramètre 'attribut' codé sur 6 octets terminé par le caractère '\0' et qui conditionne la fonction de tracé :
- octet '0' | : | code du type de trait à appliquer | ||
= | '0' | : | la primitive déplace le point courant vers le point <x,y> spécifié | |
= | '1'-'9','A'-'V' | : | type de trait à appliquer au vecteur | |
- octet '1' | : | type du paramètre spécifié en abscisse | ||
= | 'A' | : | le paramètre spécifié en abscisse est absolu | |
= | 'R' | : | le paramètre spécifié en abscisse est relatif au point courant dans l'image | |
- octet '2' | : | type du paramètre spécifié en ordonnée | ||
= | 'A' | : | le paramètre spécifié en ordonnée est absolu | |
= | 'R' | : | le paramètre spécifié en ordonnée est relatif au point courant dans l'image | |
- octet '3' | : | épaisseur du trait | ||
= | ' ' ou '_' | : | remplacé par '0' | |
= | '0'-'9','A'-'V' | : | épaisseur du contour ('0' : 1 trait, '1' : 2 traits, '2' : 3 traits, etc... | |
- octet '4' | : | code de la couleur à appliquer au trait | ||
= | ' ' ou '_' | : | remplacé par '1' (noir) | |
= | '0'-'9','A'-'V' | : | code le la couleur du trait | |
- octet '5' | : | mode d'application du trait | ||
= | ' ' ou '_' | : | remplacé par 'S' | |
= | 'S' | : | incrustation (le pixel de l'attribut remplace le pixel existant de l'image) | |
= | 'E' | : | opération logique 'ET' | |
= | 'O' | : | opération logique 'OU' | |
= | 'X' | : | opération logique 'OU EXCLUSIF' |
la description de l'attribut des tracés de chaînes de caractères :
Les deux primitives de tracés de textes dans une image, "$ttf:" et "$texte:" voient leur paramètre 'attribut' codé sur "n" octets terminé par le caractère '\0' et qui conditionne la fonction de tracé :
- octet '0' | : | cadrage du texte (pour le moment, le texte est justifié dans tous les cas) | ||
= | 'G' | : | Le texte est cadré à gauche | |
= | 'C' | : | le texte est centré | |
= | 'D' | : | le texte est cadré à droite | |
= | 'J' | : | le texte est justifié sauf s'il est terminé par un '.' (à la ligne) auquel cas il est cadré à gauche. | |
- octet '1' | : | code couleur du contour du texte | ||
= | ' ' ou '_' | : | couleur par défaut ('1' noir) | |
= | '0'-'9','A'-'V' | : | code da couleur | |
- octet '2' | : | épaisseur des contours | ||
= | ' ' ou '_' | : | pas de contour | |
= | '0'-'9','A'-'V' | : | code épaisseur du contour | |
- octet '3' | : | grain du plein des lettres | ||
= | ' ' ou '_' | : | pas de grain | |
= | '0'-'9','A'-'V' | : | code du grain | |
- octet '4' | : | mode d'application du texte | ||
= | ' ' ou '_' | : | remplacé par 'S' | |
= | 'S' | : | incrustation (chaque pixel du texte remplace le pixel existant de l'image) | |
= | 'E' | : | opération logique 'ET' | |
= | 'O' | : | opération logique 'OU' | |
= | 'X' | : | opération logique 'OU EXCLUSIF' | |
- octet '5'-'n' | : | nom de la police choisie |
III - Les primitives graphiques :
Dans le nom de la primitive, le caractère "*" marqué optionnel par les accolades "{" et "}" indique que l'utilisateur demande à la commande "lpgrp" d'afficher la primitive à traiter dans la zone-dialogue (couleur magenta).
|
"$support{*}: | ouverture du support de diffusion (l'image primaire ou physique) |
"$ferme{*}: | fermeture du support de diffusion |
"$image{*}: | ouverture d'une image en unités utilisateurs |
"$trace{*}: | tracé d'un vecteur |
"$rafraichir{*}: | mise à jour du support de diffusion |
"$palette{*}: | modification d'une couleur de la palette |
La primitive "$support:" est la première primitive à appeler. Elle ouvre l'image du support de diffusion appelée aussi "image primaire" ou "image physique". C'est celle qui est appliquée sur le périphérique physique (ici c'est une fenêtre-écran). La primitive doit être codée comme suit :
$support{*}: <attribut> <largeur> <hauteur> <titre>
attribut : attribut de l'image de fond (description ci-dessus). largeur : largeur du cadre exprimé en pixels hauteur : hauteur du cadre exprimé en pixels titre : texte à afficher sur le bandeau de la fenêtre. Tous les blancs doivent être marqués par '_' pour faire une chaîne continue..... en attendant mieux !...
Exemple :
"$support*: 351051 800 600 --_attributs_\'lpgrp\'_--"
La primitive "$ferme:" est la dernière primitive à appeler avant de sortir du programme. Elle ferme l'image du support de diffusion ouverte avec la primitive "$support". La primitive doit être codée comme suit :
$ferme{*}: Exemple :
"$ferme*:"
La primitive "$image:" permet d'ouvrir une image de la composition appelée aussi "image secondaire" ou "image sujet". C'est celle qui est appliquée sur le support de diffusion. L'utilisateur définit grâce à cette primitive un système d'unités qui lui est propre.
Remarquer que, dans pratiquement tous les logiciels de dessin, il est demandé dans quel système d'unités le programme doit travailler. Il me semble que cette notion est superflue car l'utilisateur doit être libre de définir son propre système d'unités. Il doit même avoir la possibilité de faire cohabiter simultanément des systèmes d'unités différents. Ici, les unités de mesure ne sont pas explicitées. Si l'utilisateur veut imprimer une composition sur une feuille de papier A4 à 300 points par inch avec 15 mm de marge tout autour, il devra alors ouvrir un support :
- largeur = (210-2*15)*300/25,4 pixels = 2244 pixels
- hauteur = (297-2*15)*300/25.4 pixels = 3154 pixels
Pour tracer des vecteurs et des textes dans son propre système d'unités, la primitive doit être codée comme suit :
a) - L'image est un rectangle :
$image{*}: <image> <attribut> <xmin> <xmax> <ymin> <ymmax> <x1> <y1> <x2> <y2>
b) - l'image est un parallélogramme :
$image{*}: <image> <attribut> <xmin> <xmax> <ymin> <ymax> <x1> <y1> <x2> <y2> <x0> <y0>
c) - l'image est un quadrilatère quelconque :
$image{*}: <image> <attribut> <xmin> <xmax> <ymin> <ymax> <x1> <y1> <x2> <y2> <x0> <y0> <x3> <y3>
image : n° de 1 à 20 de l'image à ouvrir,
attribut : attribut du fond de l'image (description ci-dessus),
xmin, xmax : domaine des abscisses,
ymin, ymax : domaine des ordonnées,
x1, y1 : coordonnées du coin supérieur gauche de l'image dans le support de diffusion.
x2, y2 : coordonnées du coin inférieur droit de l'image dans le support de diffusion.
x0, y0 : coordonnées du coin inférieur gauche de l'image dans le support de diffusion.
x3, y3 : coordonnées du coin supérieur droit de l'image dans le support de diffusion.
Exemples :
1°) - L'image A se projette sur un rectangle A' avec une primitive du type :
"$image*: 20 0000c1 0 100 0 60 25 675 425 525"
2°) - L'image B se projette sur un parallélogramme B' avec une primitive du type :
$image*: 1 10001 -20 +20 -50 +200 80 200 400 90 30 70"
3°) - L'image C se projette sur un quadrilatère quelconque C' avec une primitive du type :
"$image*: 2 020tc -1 +1 -1 +1 100 510 400 390 50 300 290 490"
La primitive "$trace:" permet de déplacer le point courant d'un image vers le point donné conformément à un attribut donné. La génération du vecteur par incréments de 1 pixel est basé sur l'algorithme de Bresenham.
La primitive doit être codée comme suit :
$trace{*}: <image> <attribut> <x> <y>
image : n° de 1 à 20 d'une image ouverte,
attribut : attribut du tracé de l'image (description ci-dessus),
x, y : coordonnées du point à atteindre dans le système d'unités de l'utilisateur.
Exemples :
"$trace*: 2 0aa -0.5 0.8"
"$trace*: 2 2ar +0.85 -0.2"
Ici "-0.5" et "+0.85" sont des abscisses absolues, "0.8" est une ordonnées absolue et "-0.2" est un déplacement par rapport au point courant <-0.5 , 0.8>.
La primitive "$ttf:" permet à l'utilisateur de tracer une chaîne de caractère avec une police TTF.
Pour tracer un texte dans son propre système d'unités, la primitive doit être codée comme suit :
a) - Le texte s'étale sur un rectangle :
$ttf{*}: <image> <attribut> <texte> <x1> <y1> <x2> <y2>
b) - Le texte s'étale sur un parallélogramme :
$image{*}: <image> <attribut> <texte> <x1> <y1> <x2> <y2> <x0> <y0>
c) - Le texte s'étale sur un quadrilatère quelconque :
$image{*}: <image> <attribut> <texte> <x1> <y1> <x2> <y2> <x0> <y0> <x3> <y3>
image : n° de 1 à 20 de l'image à ouvrir,
attribut : attribut du texte (description ci-dessus),
texte : chaîne de caractères à tracer. Les blancs doivent être marqués par le caractère '_' (blanc souligné),
x1, y1 : coordonnées du coin supérieur gauche du texte dans le support de diffusion.
x2, y2 : coordonnées du coin inférieur droit du texte dans le support de diffusion.
x0, y0 : coordonnées du coin inférieur gauche du texte dans le support de diffusion.
x3, y3 : coordonnées du coin supérieur droit du texte dans le support de diffusion.
Pour le moment :
Note 1 |
:
|
le texte est justifié dans tous les cas |
Note 2 |
:
|
certains attributs ne sont pas traités, la librairie TTF de donnant pas tous les éléments pour les prendre en compte. |
Exemple :
"$ttf*: 20 jq___comic.ttf ___Programme_Fortran___ 0 60 100 40"
NOTE : La primitive est en attente d'écriture en fonction de la destiné du programme
La primitive "$texte:" permet à l'utilisateur de tracer une chaîne de caractère avec une police propre au logiciel.
Pour tracer un texte dans son propre système d'unités, la primitive doit être codée comme suit :
a) - Le texte s'étale sur un rectangle :
$texte{*}: <image> <attribut> <texte> <x1> <y1> <x2> <y2>
b) - Le texte s'étale sur un parallélogramme :
$texte{*}: <image> <attribut> <texte> <x1> <y1> <x2> <y2> <x0> <y0>
c) - Le texte s'étale sur un quadrilatère quelconque :
$texte{*}: <image> <attribut> <texte> <x1> <y1> <x2> <y2> <x0> <y0> <x3> <y3>
image : n° de 1 à 20 de l'image à ouvrir,
attribut : attribut du texte (description ci-dessus),
texte : chaîne de caractères à tracer. Les blancs doivent être marqués par le caractère '_' (blanc souligné),
x1, y1 : coordonnées du coin supérieur gauche du texte dans le support de diffusion.
x2, y2 : coordonnées du coin inférieur droit du texte dans le support de diffusion.
x0, y0 : coordonnées du coin inférieur gauche du texte dans le support de diffusion.
x3, y3 : coordonnées du coin supérieur droit du texte dans le support de diffusion.
Pour le moment :
Note 1 |
:
|
le texte est justifié dans tous les cas |
Note 2 |
:
|
certains attributs ne sont pas traités, la librairie TTF de donnant pas tous les éléments pour les prendre en compte. |
Exemple :
"$texte*: 20 jn1fxlucida_handwriting.ttf Illustration_des_pseudo-terminaux 0 60 100 40
La primitive "$rafraichir:" est la primitive à appeler toutes les fois que l'on veut mettre à jour l'image du support de diffusion. La primitive doit être codée comme suit :
$rafraichir{*}: Exemple :
"$rafraichir*:"
La primitive "$palette:" permet d'affecter à un code couleur ('0'-'9', 'A'-'V') une nouvelle composition RVB pour redéfinir une nouvelle couleur. La primitive doit être codée comme suit :
$palette{*}: <code> <rrr> <vvv> <bbb>
$palette{*}: <code> #<rrvvbb>
code : code de la couleur à modifier ('0'-'9', 'A'-'V'). rrr : valeur de la composante rouge (0-255) vvv : valeur de la composante verte (0-255) bbb : valeur de la composante bleue (0-255)
rrvvbb : valeur des trois composantes en hexadécimal('00'-'FF')
Exemple :
"$palette*: B 32 255 128"
"$palette*: B #ccabed"
--ooOoo--