IdentifiantMot de passe
Loading...
Mot de passe oublié ?Je m'inscris ! (gratuit)
Navigation

Inscrivez-vous gratuitement
pour pouvoir participer, suivre les réponses en temps réel, voter pour les messages, poser vos propres questions et recevoir la newsletter

Farfelue Discussion :

[CONCEPTION] Politiques, traits et comportements orthogonaux


Sujet :

Farfelue

  1. #1
    Expert éminent sénior
    Avatar de koala01
    Homme Profil pro
    aucun
    Inscrit en
    Octobre 2004
    Messages
    11 612
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Âge : 52
    Localisation : Belgique

    Informations professionnelles :
    Activité : aucun

    Informations forums :
    Inscription : Octobre 2004
    Messages : 11 612
    Points : 30 611
    Points
    30 611
    Par défaut [CONCEPTION] Politiques, traits et comportements orthogonaux
    Salut,

    Au long de nos différentes discussions, nous avons déterminé un certain nombre de comportements qui, bien qu'étant parfois dépendant de certaines conditions, sont clairement orthogonaux.

    Si l'on veut commencer à avancer un tout petit peu, il me semble important de les recenser de manière quasi exhaustive et de s'intéresser un peu à la manière de les implémenter.

    En effet, indépendamment de la manière dont le rendu d'un élément sera fait, il est tout à fait possible de déjà définir certains comportements que l'on est en droit d'attendre des différents éléments.

    • Nous aurons dores et déjà besoin d'un système de positionnement dans l'espace.
    • Il semble intéressant de considérer les éléments à afficher comme... des formes (qu'il s'agira d'adapter au système de rendu) pour lesquelles on peut déjà déterminer les comportements attendus (création, déplacement, redimensionnement, ...)
    • Qui dit "rendu" dit... couleurs, et les couleurs, on peut déjà réfléchir aux comportements que l'on peut en attendre et à la manière de les implémenter
    • La possibilité de traduire l'ihm "à la demande" a été évoquée, et elle me semble intéressante et devrait être envisagée (quitte à ce qu'elle ne soit pas implémentée directement)
    • La connexion et la gestion des signaux émis et reçus est un gros morceau qui peut parfaitement être implémentée sans que les décisions concernant le rendu ne soient prise
    • ...
    Ce que j'attends de vous

    C'est bien simple:

    Complétez cette liste au fur et à mesure, et, surtout, trouver le moyen le plus efficace d'implémenter tout cela.

    La meta prog viendra bien à point pour tout cela...

    Bien que nous finirons fatalement par être limité sans le moteur de rendu qui nous permettra d'admirer le résultat, nous pourrions quand même commencer à mettre tout cela en place, ce qui est fait n'étant plus à faire

    Messieurs, à vos crayons
    A méditer: La solution la plus simple est toujours la moins compliquée
    Ce qui se conçoit bien s'énonce clairement, et les mots pour le dire vous viennent aisément. Nicolas Boileau
    Compiler Gcc sous windows avec MinGW
    Coder efficacement en C++ : dans les bacs le 17 février 2014
    mon tout nouveau blog

  2. #2
    Expert éminent sénior
    Avatar de koala01
    Homme Profil pro
    aucun
    Inscrit en
    Octobre 2004
    Messages
    11 612
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Âge : 52
    Localisation : Belgique

    Informations professionnelles :
    Activité : aucun

    Informations forums :
    Inscription : Octobre 2004
    Messages : 11 612
    Points : 30 611
    Points
    30 611
    Par défaut
    Allez, je commence pour montrer l'exemple:

    Un système de positionnement est absolument nécessaire.

    Peu importe le type réellement utilisé pour représenter les coordonnées, nous aurons très certainement des coordonnées "2D" et des coordonnées "3D" (ces dernières ne seront sans doute pas immédiatement nécessaires)

    On peut souhaiter comparer les coordonnées selon l'axe, ce qui nous donnerait (pour les positions 2D) quelque chose de fort proche de
    Code c++ : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    19
    20
    21
    22
    23
    24
    25
    26
    27
    28
    29
    30
    struct position2D_flag{};
    template <typename T, class Flag>
    struct TPosition;
    template <typename T>
    struct TPosition<T, position2D_flag
    {
        typedef T value_type;
        value_type x;
        value_type y;
    };
    template <typename T>
    TPosition<T, position2D_flag> makePosition2D(T x, T y)
    {
        TPosition<T, position2D_flag> p;
        p.x=x;
        p.y=y;
        return p;
    }
    template <typename T, class Flag>
    bool lessX( TPosition<T, Flag> const & first, 
                TPosition<T, Flag> const & second)
    {
        return first.x<second.x;
    }
    template <typename T, class Flag>
    bool lessY( TPosition<T, Flag> const & first, 
                TPosition<T, Flag> const & second)
    {
        return first.y<second.y;
    }
    [EDIT]
    1. je pars peut être très mal... n'hésitez pas à reprendre
    2. Cette "politique" de positionnement pourrait être utilisée par les différentes formes pour déterminer "où" les placer et si un élément de pointage est "au dessus" de la forme
    A méditer: La solution la plus simple est toujours la moins compliquée
    Ce qui se conçoit bien s'énonce clairement, et les mots pour le dire vous viennent aisément. Nicolas Boileau
    Compiler Gcc sous windows avec MinGW
    Coder efficacement en C++ : dans les bacs le 17 février 2014
    mon tout nouveau blog

  3. #3
    Membre chevronné
    Avatar de Goten
    Profil pro
    Inscrit en
    Juillet 2008
    Messages
    1 580
    Détails du profil
    Informations personnelles :
    Âge : 33
    Localisation : France

    Informations forums :
    Inscription : Juillet 2008
    Messages : 1 580
    Points : 2 205
    Points
    2 205
    Par défaut
    Je me permet de m'auto citer (mon message étant un poil passé à la trappe car en fin de page) :
    Concernant le moteur de rendu et la portabilité donc :

    Ben l'idée de base derrière la portabilité à mon avis, c'est de viré le prépocesseur pour le remplacé par des classes de traits. (enfin du prépocesseur y'en aura à l'appel).
    Je veux dire, imaginons qu'on est une classe rendu, qui s'occupe de délégué les appels aux différentes primitives des différents OS.
    il "suffit" que cette classe soit composé de méthode statique pour avoir un appel portable sans trop de contrainte :

    render<osTraits>::drawLine(//...);

    Derrière ça consisterait en spécialisation plutôt qu'en macro. Et ça permettrait de venir greffer d'autres moteur de rendu plus aisément.
    C'est une proposition, elle a ses avantages et ses inconvénients (que je n'ai encore pas trouvé ... :') )
    "Hardcoded types are to generic code what magic constants are to regular code." --A. Alexandrescu

  4. #4
    Invité
    Invité(e)
    Par défaut Positionnement, points, référentiels, zones
    Salut,

    Pour avancer sur ce que proposait Koala.

    Points et bipoints

    L'élément de base du positionnement est le point (je pars pour l'exemple d'une représentation en entiers, mais on peut parfaitement templatiser tout ca, je ne sais pas si c'est utile...)

    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    typedef pair<int,int> Point
    Les zones, et un certain nombre d'éléments graphiques, peuvent être définis comme des bipoints. Un rectangle, une ligne droite, une ellipse, peuvent être définis comme des bipoints

    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    typedef pair<Point,Point> Bipoint
    Si l'on considère qu'une zone est l'équivalent d'un rectangle (même s'il s'agit d'une ellipse... le rectangle étant son "encadrement"), on remarque qu'il y a 4 représentations possibles d'un même rectangle en terme de bipoints (les deux diagonales du rectangle, dans les deux ordres possibles). On va donc définir une fonction d'équivalence entre bipoints

    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    bool equiv(Bipoint, Bipoint)
    qui vérifie si deux bipoints représentent le même rectangle,

    et une "forme canonique" du bipoint

    qui vérifie
    - bipoint.first.first<=bipoint.second.first
    - bipoint.first.second<=bipoint.second.second
    (le premier point a ses deux coordonnées inférieures à celles du second)

    L'intérêt de la forme canonique est qu'elle simplifie singulièrement les calculs d'intersection de rectangles (qui sont à la base du clipping)


    Distances

    Sur ces deux structures, on peut définir un certain nombre de distances. Distance entre deux points, entre un point et un bipoint, entre deux bipoints.

    Pour les distances entre points, a mon avis trois distances seront nécessaires :
    - la distance euclidienne : sqrt( (p1.x-p2.x)*(p1.x-p2.x)+(p1.y-p2.y)*(p1.y-p2.y)): qui sert essentiellement pour les cercles et les ellipses
    - la distance d1 (métropolis, je crois qu'on dit aussi) abs(p1.x-p2.x)+ abs(p1.y-p2.y) (utilisée pour les distances point rectangle)
    - la distance d-inf max(abs(p1.x-p2.x),abs(p1.y-p2.y)), qui sert pour les rectangles

    La distance entre un point et un bipoint est, à peu de chose près, un test d'intersection généralisé. Ce n'est pas une distance au sens mathématique, car elle n'est pas symétrique, et probablement pas injective... Mais je pense qu'on pourrait la définir comme

    d(P,B)=0 ssi le point est sur le périmètre du rectangle (ou de l'ellipse, ou...) défini par le bipoint
    d(P,B)<0 ssi le point est à l'intérieur du rectangle, la valeur étant la distance minimale au périmètre
    d(P,B)>0 sss le point est à l'extérieur du rectangle, la valeur étant la distance au point le plus proche du périmètre (au sens d1)

    L'intérêt de cette "distance généralisée", est qu'elle permet de définir une "intersection tolérante", ou des marges autour des bordures des composants. Elle servira probablement de base aux opérations d'alignement.


    Je ne sais pas très bien comment définir une distance (ou intersection) entre deux bipoints, il faut a priori distinguer trois cas :
    - distincts (ou adjacents), la distance est alors la distance minimale entre deux points des rectangles (au sens d1)
    - inclus (l'un des rectangles est inclus dans l'autre)
    - non distincts non inclus...


    Référentiels

    Un point n'existe pas dans l'absolu, mais fait toujours référence à un système de coordonnées. Un système de coordonnées peut se définir relativement à un autre par
    - une origine (un point défini dans l'autre système de coordonnées)
    - une échelle, deux valeurs qui donnent la "taille des pixels" en X et Y, et la direction des deux axes, dans l'autre système d'unités. Ca nous donne

    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    typedef pair<int,int> Fraction
    typedef pair<Fraction,Fraction> Echelle;
    typedef pair<Point,Echelle> Referentiel;
    Pour définir uniquement un référentiel, il nous faudra un "référentiel absolu". L'intérêt des référentiels est qu'on peut vouloir définir la position d'un élément
    - dans l'absolu
    - par rapport à l'écran
    - par rapport à la fenêtre
    - par rapport à son parent...

    Il est à noter que le "sens des axes" n'est pas fixé. C'est à mon avis la bonne facon de gérer les alignements.


    Voila pour les positionnements. On peut probablement essayer d'écrire tout cela sous la forme d'un fichier de base...


    Note sur les unités

    Le "monde de l'IHM" étant somme toute assez petit (on parle peut être d'un carré de 10 000 pixels de côté, peut être le double, mais bon), il ne me parait pas nécessaire d'utiliser des flottants. En revanche, des rationnels (ou des décimaux en position fixe) pourraient être utilisés très efficacement ici. Peut être vaudrait il la peine de regarder la librairie rational de boost...

    Une question qui se posera rapidement est celle de "l'aspect" des pixels (c'est à dire le rapport entre leur "hauteur" et leur "largeur". Ceci joue de deux facons distinctes :
    - pour prendre en compte des résolutions d'écran différentes
    - lors des changements de référentiels

    A mon avis, il faut probablement partir de l'idée qu'on travaille à "aspect constant", avec des pixels carrés, ou un ratio d'aspect constant... Dans ce contexte, les facteurs d'échelle des définitions de référentiel se résument à un rationnel positif, et deux bits de signe.

    Francois
    Dernière modification par Invité ; 20/04/2010 à 01h35.

  5. #5
    Expert éminent sénior
    Avatar de koala01
    Homme Profil pro
    aucun
    Inscrit en
    Octobre 2004
    Messages
    11 612
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Âge : 52
    Localisation : Belgique

    Informations professionnelles :
    Activité : aucun

    Informations forums :
    Inscription : Octobre 2004
    Messages : 11 612
    Points : 30 611
    Points
    30 611
    Par défaut
    Citation Envoyé par Goten Voir le message
    Je me permet de m'auto citer (mon message étant un poil passé à la trappe car en fin de page) :
    Concernant le moteur de rendu et la portabilité donc :
    Ben l'idée de base derrière la portabilité à mon avis, c'est de viré le prépocesseur pour le remplacé par des classes de traits. (enfin du prépocesseur y'en aura à l'appel).
    Je veux dire, imaginons qu'on est une classe rendu, qui s'occupe de délégué les appels aux différentes primitives des différents OS.
    il "suffit" que cette classe soit composé de méthode statique pour avoir un appel portable sans trop de contrainte :

    render<osTraits>::drawLine(//...);
    Derrière ça consisterait en spécialisation plutôt qu'en macro. Et ça permettrait de venir greffer d'autres moteur de rendu plus aisément.
    C'est une proposition, elle a ses avantages et ses inconvénients (que je n'ai encore pas trouvé ... :') )
    Tout à fait, mais, bien que la proposition soit bonne, je souhaiterais que l'on avance un peu, quitte, pour l'instant, à laisser l'aspect "tracé / rendu" sur le coté (même si d'une manière ou d'une autre il faudra bien l'intégrer)

    La raison est simple: l'aspect "traçable" d'un élément visuel est, il est vrai, très important, mais il ne faut pas que cela devienne l'arbre qui cache la forêt.

    On ne pourra, à peu de chose près, déterminer ce que nous devons utiliser de GD / GD+ / xorg / autre bibliothèques tierces similaires que... quand nous saurons (à peu près) ce que nous risquons de devoir tracer et... comment nous voudrons le tracer.

    Or, pour pouvoir parler "concrètement" de ce que nous devrons tracer, il me semble utile de nous intéresser aux autres traits tout aussi transversaux des éléments graphiques (et des autres).

    Cela nous permettra de sortir de ce cercle vicieux de ne pas savoir ce qu'il faut, parce que nous ne savons pas de quoi nous avons besoin

    Une fois que nous saurons "ce qui doit être tracé", nous pourrons déterminer "comment arriver à le tracer", et donc l'interface qui doit être exposée par le moteur de rendu (et plus précisément ce qui doit être utilisé au niveau des primitives par l'interface du moteur de rendu)
    A méditer: La solution la plus simple est toujours la moins compliquée
    Ce qui se conçoit bien s'énonce clairement, et les mots pour le dire vous viennent aisément. Nicolas Boileau
    Compiler Gcc sous windows avec MinGW
    Coder efficacement en C++ : dans les bacs le 17 février 2014
    mon tout nouveau blog

  6. #6
    Invité
    Invité(e)
    Par défaut Réferentiels, zone, clips, et z-order
    Je reviens sur la notion de référentiel...

    Partons d'une interface définie à partir de "zones" rectangulaires. Je ne crois pas qu'on puisse échapper aux rectangles : nos widgets ne seront pas forcément rectangulaires, mais comme il seront finis, on peut toujours définir un 'rectangle minimal' qui les contient, à la limite les pixels sont des "rectangles atomiques".

    Un rectangle peut être défini comme un bipoint (en forme canonique, coordonnées du premier point inférieures à celles du second). On peut lui associer un "référentiel naturel" dont l'origine est son premier point. Le rectangle a donc pour coordonnées (0,0) (X,Y). X et Y sont alors la largeur et la hauteur du rectangle. Ce référentiel naturel est très important, car c'est celui qui sera utilisé par les fonctions de rendu, ou de traitement.

    Pour finir de spécifier le rectangle dans sa représentation naturelle, il nous faut définir les unités dans lesquelles sont exprimés X et Y. On a, en gros, deux types d'échelles :
    - des échelles absolues (pouces, mm, points),
    - des échelles "matérielles", qui utilisent des pixels dépendant de la résolution d'écran. Les pixels ne sont pas forcément carrés (à la différence des échelles absolues...)

    En revanche, je crois qu'on peut contraindre les 2 dimensions à avoir la même unité.

    On se retrouve avec, pour un rectangle représenté dans son référentiel naturel, la structure suivante

    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
    6
    7
    struct BaseRect {
      int Width,Height; // coordonnées du second point, le premier c'est (0,0)
      bool Pixels; // tailles en résolution écran
      double Echelle; // si taille absolue, unité, exprimée en millimètres? si zéro :échelle en pixels? comme ca on élimine le précédent?
      bool DirX,DirY; // direction des deux axes, true si vers la droite et vers le bas
    };
    Le positionnement de l'ensemble des éléments de l'interface peut se faire à partir d'un tel rectangle de base. Un rectangle sera défini par ses deux points (en forme canonique) dans ce système. Il ne sera pas nécessaire de répéter, alors, les éléments d'échelle.

    Inversement, si on se donne un rectangle et une définition d'échelle, on peut recalculer les coordonnées de tout élément d'interface.

    Trois référentiels naturels sont couramment utilisés :

    - le référentiel de l'écran (le point (0,0) est le coin de l'écran
    - le référentiel de la fenêtre en cours
    - un référentiel d'un élément d'interface

    Clips

    Une fois choisi un référentiel, le rendu d'une zone rectangulaire se fait par rapport à un second rectangle (ou groupe de rectangles) dit "de clip". On ne dessinera que la zone du premier rectangle qui se trouve "dans le second" (le second rectangle est alors une "fenêtre" par laquelle on voit le premier), ou bien la zone qui se trouve en dehors du second (le second rectangle est alors un cache qui bloque la visibilité du premier).

    Dans les systèmes d'interface traditionnels, on ne s'intéresse qu'au premier type de clip. Les éléments d'interface sont "empilés" les uns sur les autres de façon arborescente. Chaque élément est "clippé" par son parent (qui forme donc une fenêtre), et on dessine les éléments dans un ordre précis (le z-Order), chaque nouvel élément "cachant" le précédent.

    Ici, il serait sans doute intéressant de tirer parti des deux. C'est à dire de pouvoir avoir pour chaque zone un ou plusieurs clips "fenêtre", et un ou plusieurs clips "cache", les clips cache pouvant toujours être gérés au travers d'une méthode de z-order, c'est à dire en définissant un ordre sur les zones, parcouru de bas en haut lors du rendu, et de haut en bas lors des tests souris...

    Francois

  7. #7
    Membre émérite
    Inscrit en
    Avril 2010
    Messages
    1 495
    Détails du profil
    Informations forums :
    Inscription : Avril 2010
    Messages : 1 495
    Points : 2 274
    Points
    2 274
    Par défaut
    Je vais globalement dans le même sens que fcharton pour le rectangle, comme conteneur symbolique. Il faudrait peut-être ajouter aussi des éléments tels que "left", "top", "right", "bottom", et probablement aussi "center" (centre du rectangle) si on veut pouvoir utiliser facilement l'approche de koala01 concernant le positionnement ou l'alignement sur un plan. <edition: ajout> D'ailleurs, chaque forme construite pourrait retourner son propre conteneur "contener" qui ne serait rien d'autre qu'un simple rectangle ou parallélépipède </edition>

    Cela dit, ce serait bien de limiter les structures aux données brutes et parler de classes pour le reste.

    En ce qui concerne les dimensions, on pourrait partir directement sur de la 3D en définissant z à 0 par défaut pour la 2D, ainsi "makePosition" remplacerait "makePosition2D / makePosition3D".

    Enfin, la taille d'une figure peut aussi être représentée selon un rapport avec son référentiel, un pourcentage.

  8. #8
    Expert éminent sénior
    Avatar de koala01
    Homme Profil pro
    aucun
    Inscrit en
    Octobre 2004
    Messages
    11 612
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Âge : 52
    Localisation : Belgique

    Informations professionnelles :
    Activité : aucun

    Informations forums :
    Inscription : Octobre 2004
    Messages : 11 612
    Points : 30 611
    Points
    30 611
    Par défaut
    Excusez moi, j'aurais du répondre à pas mal de choses beaucoup plus tôt

    Je vais donc le faire sans *forcément* suivre l'ordre des propositions faites
    1- Je ne crois pas opportun de vouloir forcer les coordonnées à être des entiers...
    • Il me *semble* que OpenGl, par exemple, travaille avec des réels
    • Les entiers sont relativement mal adaptés à certains calculs (trigono, racine carrée, ...) dont nous *risquons* de devoir abuser, même si on peut estimer qu'avec un pixel faisant quelque dixièmes de millimètres, nous avons sans doute un peu de marge
    • On peut difficilement préjuger de quoi sera fait demain, mais je suis quand même en partie sérieux je présente le scénario de mon R&D

    2- Il est effectivement cohérent d'envisager les différentes formes comme des bipoints.

    Il faut cependant penser au fait que nous voudrions pouvoir permettre la création d'hexagones, de dodécagones, d'ellipses ou de triangles quelconques (et je ne parle ici que de l'aspect 2D)...

    Même en laissant les triangles non scalènes (qui nécessiteront définitivement la présence de trois points) sur le coté, je me demande si l'idée de se baser sur deux angles opposés d'un rectangle est réellement la meilleure des solutions

    Deux points suffisent effectivement à la définition de la plupart des formes régulières, mais n'aurions nous pas intérêt à prendre plutôt le centre et l'extrémité d'un des côtés (par exemple l'extrémité gauche du coté supérieur passant à la verticale du centre)

    Le redimensionnement s'effectuerait "dans tous les sens" par rapport au centre, et c'est le déplacement de celui-ci qui occasionnerait le déplacement "de tout le reste".

    Je ne veux pas imposer ce point de vue... je le propose comme alternative à celle qui voudrait considérer le rectangle comme conteneur de base parce qu'il me semble intéressant d'avoir un débat sur les avantages et les inconvénients comparés des deux solutions

    Cela répond en outre en partie à minnessota: il n'est à mon sens pas opportun de disposer de l'ensemble des "coins" des différentes en tant que membre formes car le calcul est *relativement* vite fait à partir du moment où tu dispose de deux points de références précis.

    Par contre, il *peut* être intéressant de récupérer les coordonnées de ceux-ci

    NOTA: Sauf erreur, l'approche initiale de OpenGL était de travailler avec des triangles, car toute forme relativement irrégulière peut être décomposée en autant de triangles dont au pire l'un des angles est le "centre" de la forme et dont le coté est... le coté correspondant de la forme.

    Peut être pourrions nous réfléchir aussi de ce point de vue pour les forme irrégulières


    3- Je n'ai pas l'impression, en première analyse, qu'il soit opportun d'introduire une coordonnée z dans les positions 2D parce que cela aurait comme résultat de permettre d'envoyer des position 2D dans un graphisme 3D, avec comme résultat le fait que tout tracé entre une position réellement 3D et une position qui aurait du rester 2D tendrait vers... la coordonnée 0 du référentiel.

    Je préfères donc avoir deux fonctions clairement distinctes makePosition2D et makePosition3D que de risquer ce mélange malencontreux.

    D'autant plus que les variadic template ou la spécialisation partielle peuvent nous venir en aide sur ce coup, et qu'il faudra de toutes façons une spécialisation partielle pour les polygones et les polyèdres

    4- Le problème du "clipping" mérite effectivement que l'on s'arrête un peu dessus

    Ce problème est effectivement important parce que, au delà du "simple" fait de le gérer correctement, il met en évidence certains besoins de conception:

    Nous aurons besoin d'un phénomène proche du pattern "visiteur" pour aller du "contenant" au "contenu", mais pour aller dans l'autre sens, il faudrait se rapprocher du pattern composite ou envisager la récursivité...

    Et, comme il y a malgré tout la contrainte d'essayer d'éviter les super objets, il est peut être temps, de réfléchir à comment implémenter ces deux patterns de manière générale (car ce seront deux patterns dont nous aurons besoin pour bien d'autres choses )

    Enfin, c'est très bien, vous vous êtes engouffrés dans mon exemple afin d'enrichir la réflexion, et c'est ce que j'attends de vous (enfin, faudra quand même finir par commencer à coder tout ca, aussi ) .

    Par contre, ce n'est pas une raison pour oublier tous les autres aspects

    N'hésitez pas à parler "du reste" (gestion des propriétés de l'objet affichable, gestion des messages, ...): Je placerai les différents aspects dans des discussions séparées
    A méditer: La solution la plus simple est toujours la moins compliquée
    Ce qui se conçoit bien s'énonce clairement, et les mots pour le dire vous viennent aisément. Nicolas Boileau
    Compiler Gcc sous windows avec MinGW
    Coder efficacement en C++ : dans les bacs le 17 février 2014
    mon tout nouveau blog

  9. #9
    Invité
    Invité(e)
    Par défaut
    Salut Koala,

    Citation Envoyé par koala01 Voir le message
    1- Je ne crois pas opportun de vouloir forcer les coordonnées à être des entiers...
    Il y a pour moi deux aspects distincts.

    1- en fin de course, les primitives systèmes raisonnent en entier, parce qu'elles comptent des pixels, , et l'utilisation d'entiers garantit des "tailles minimales", quand on va parler d'alignement, ce ne sera pas un détail.

    2- on n'est pas obligés de ce limiter à un entier "égal au pixel", mais adopter une "taille atomique" plus petite, ou alors fonctionner en fractions.

    Mon impression, c'est que, à la différence d'OpenGL, on aura en fait très peu de calculs mathématiques à faire, parce qu'on travaille dans un monde "rectangulaire". Pour les quelques uns qui restent, on pourra toujours repasser par une conversion, ce n'est pas que cela prenne beaucoup de temps.

    Mais conservons un template pour le type, on pourra décider après.

    Il faut cependant penser au fait que nous voudrions pouvoir permettre la création d'hexagones, de dodécagones, d'ellipses ou de triangles quelconques (et je ne parle ici que de l'aspect 2D)...
    Un polygone, c"est un N-point (le dernier connecté au premier), mais on devra peut être quand même lui définir un "rectangle" parent, pour pouvoir l'aligner sur l'interface (je me méfie énormément de la notion de "centre" qui ne veut rien dire, rien que pour un triangle, il y en a une demi douzaine de définitions...)

    Une ellipse, c'est une généralisation des "rectangles à coins ronds". Dans le même ordre d'idée, on pourrait ajouter des primitives qui arrondiraient des polygones, sous forme de splines ou de courbes de Bézier. Ca permettrait de sortir (lors du rendu) des modèles "carrés", sans pour autant perdre l'avantage de celui ci.

    Deux points suffisent effectivement à la définition de la plupart des formes régulières, mais n'aurions nous pas intérêt à prendre plutôt le centre et l'extrémité d'un des côtés (par exemple l'extrémité gauche du coté supérieur passant à la verticale du centre)
    On peut, mais je pense que c'est moins efficace... En pratique, on a souvent vouloir aligner les éléments d'interface : tel bouton est à 2 pixels du bord, tel autre à gauche de la liste... Et les tests "souris" portent toujours sur la notion de "rectangle de base".

    Maintenant, on peut facilement déduire le centre des bords et inversement...

    Le redimensionnement s'effectuerait "dans tous les sens" par rapport au centre, et c'est le déplacement de celui-ci qui occasionnerait le déplacement "de tout le reste".
    De quel centre? Il y en a un par élément d'interface...

    NOTA: Sauf erreur, l'approche initiale de OpenGL était de travailler avec des triangles, car toute forme relativement irrégulière peut être décomposée en autant de triangles dont au pire l'un des angles est le "centre" de la forme et dont le coté est... le coté correspondant de la forme.

    Peut être pourrions nous réfléchir aussi de ce point de vue pour les forme irrégulières
    En 3D ca fait sens, mais attention les calculs... En 2D, je ne sais pas, j'ai l'impression qu'il n'est pas plus intéressant d'approcher un cercle par des triangles que par des rectangles, et que les triangles vont nous amener un tas de calculs moches (de la trigo), pour pas grand chose.

    En 2D, si on veut renouveller le genre, on devrait plutot avoir des coordonnées polaires, et une représentation naturelle, permettant le passage d'un système à l'autre, serait les complexes, que la STL gère parfaitement...

    Mais une fois de plus, j'ai l'impression que nos interfaces demeurent et demeureront longtemps assez rectangulaires.

    Francois

  10. #10
    Membre émérite
    Inscrit en
    Avril 2010
    Messages
    1 495
    Détails du profil
    Informations forums :
    Inscription : Avril 2010
    Messages : 1 495
    Points : 2 274
    Points
    2 274
    Par défaut
    Salut koala01,
    Salut fcharton,

    Je crois qu'il y a un profond malentendu qu'il faut absolument dissiper. Lorsque tu parles de triangle koala01, tu te places dans un contexte de modélisation / rendu, le triangle est l'unité de composition d'une forme, c'est particulièrement vrai en "Geometry shaders" où le GPU est mis à profit grâce à des outils comme OpenGL ou DirectX. Lorsque ce principe est émulé (par logiciel), le microprocesseur central est littéralement mis à genoux.

    Le rectangle dont nous parlons, fcharton et moi, n'a rien à voir avec la modélisation ou le rendu d'une forme, mais seulement la manipulation de cette dernière. Il faut imaginer ce rectangle comme un calque (transparent) sur lequel tu dessines ta forme. Comme le calque et la forme sont solidaires, toute action sur le calque est systématique répercutée sur la forme. En fait, pour être précis, le calque n'a pas d'existence réelle, c'est juste une manière d'aborder la forme en réduisant les opérations à leurs stricts minimums, le microprocesseur et l'utilisateur apprécieront. Ainsi, on dit que toute forme est inscrite dans un rectangle (elle peut donc être délimitée par un rectangle, lui-même constituant une de ses propriétés) et le centre de ce rectangle est le centre de la forme.

    Voilà, en espérant que maintenant c'est plus clair.

    Cela dit, j'ai personnellement du mal à aborder des patrons de conception sans avoir préalablement défini des objets concrets avec des caractéristiques concrètes. Faute d'un réel investissement ou d'une profonde réflexion, le projet va stagner. J'espère toutefois me tromper. J'aimerais que tu nous fasses part de ton avis fcharton, si tu veux bien.

  11. #11
    Expert éminent sénior
    Avatar de koala01
    Homme Profil pro
    aucun
    Inscrit en
    Octobre 2004
    Messages
    11 612
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Âge : 52
    Localisation : Belgique

    Informations professionnelles :
    Activité : aucun

    Informations forums :
    Inscription : Octobre 2004
    Messages : 11 612
    Points : 30 611
    Points
    30 611
    Par défaut
    Citation Envoyé par minnesota Voir le message
    Salut koala01,
    Salut fcharton,

    Je crois qu'il y a un profond malentendu qu'il faut absolument dissiper. Lorsque tu parles de triangle koala01, tu te places dans un contexte de modélisation / rendu, le triangle est l'unité de composition d'une forme, c'est particulièrement vrai en "Geometry shaders" où le GPU est mis à profit grâce à des outils comme OpenGL ou DirectX. Lorsque ce principe est émulé (par logiciel), le microprocesseur central est littéralement mis à genoux.
    Je ne parlais de OpenGl que pour l'exemple, par contre
    Le rectangle dont nous parlons, fcharton et moi, n'a rien à voir avec la modélisation ou le rendu d'une forme, mais seulement la manipulation de cette dernière. Il faut imaginer ce rectangle comme un calque (transparent) sur lequel tu dessines ta forme. Comme le calque et la forme sont solidaires, toute action sur le calque est systématique répercutée sur la forme. En fait, pour être précis, le calque n'a pas d'existence réelle, c'est juste une manière d'aborder la forme en réduisant les opérations à leurs stricts minimums, le microprocesseur et l'utilisateur apprécieront. Ainsi, on dit que toute forme est inscrite dans un rectangle (elle peut donc être délimitée par un rectangle, lui-même constituant une de ses propriétés) et le centre de ce rectangle est le centre de la forme.
    C'est justement là le problème, et principalement le fait que les réactions soient rattachées au calque.

    Tant qu'à faire, je souhaiterais que le calque prenne "exactement" l'espace de la forme.

    J'ai le sentiment qu'il est possible de le faire, même si j'ai effectivement conscience que cela pourrait compliquer notre tâche

    Quand on y pense, la plupart des formes sont définissables avec un point et une distance (ou un deuxième point).

    Seuls les triangles et, selon ce que l'on prend, le rectangle font exception à cette règle, et il y a très certainement quelque chose à faire au départ de cela.

    Après tout, les template devraient nous y aider énormément
    Voilà, en espérant que maintenant c'est plus clair.

    Cela dit, j'ai personnellement du mal à aborder des patrons de conception sans avoir préalablement défini des objets concrets avec des caractéristiques concrètes.
    Tu fais sans doute allusion à l'autre discussion que j'ai lancée...

    Je te répondrai que, d'une certaine manière, il est possible de déterminer un certain nombre de comportement qui seront, de toutes manières, utilisés, quelle que soit la manière de s'y prendre...

    De plus, il y a un certain nombre de caractéristiques auxquelles nous ne couperons de toutes façons pas...

    Et c'est ces caractéristiques, ces comportements que nous risquons de rencontrer partout, que je voudrais que l'on explore.
    Faute d'un réel investissement ou d'une profonde réflexion, le projet va stagner. J'espère toutefois me tromper. J'aimerais que tu nous fasses part de ton avis fcharton, si tu veux bien.
    Une profonde réflexion est, effectivement nécessaire, et c'est la raison pour laquelle j'essaye de lancer un maximum de pistes de réflexion en même temps, car toutes sont nécessaires.

    Et ce d'autant plus qu'il n'y a pas *forcément* que les élément "visuels" à envisager
    A méditer: La solution la plus simple est toujours la moins compliquée
    Ce qui se conçoit bien s'énonce clairement, et les mots pour le dire vous viennent aisément. Nicolas Boileau
    Compiler Gcc sous windows avec MinGW
    Coder efficacement en C++ : dans les bacs le 17 février 2014
    mon tout nouveau blog

  12. #12
    Invité
    Invité(e)
    Par défaut
    Citation Envoyé par minnesota Voir le message
    Il faut imaginer ce rectangle comme un calque (transparent) sur lequel tu dessines ta forme. Comme le calque et la forme sont solidaires, toute action sur le calque est systématique répercutée sur la forme. En fait, pour être précis, le calque n'a pas d'existence réelle, c'est juste une manière d'aborder la forme en réduisant les opérations à leurs stricts minimums, le microprocesseur et l'utilisateur apprécieront.
    Il y a un autre bénéfice au modèle rectangulaire, c'est la "mise en page", ou l'alignement. Comment aligner deux lettres d'un mot, deux mots d'une phrase, une ellipse, un triangle?

    Sur ces problèmes, une excellente réference est le TexBook de Knuth, qui pose les problèmes d'alignement de manière très concrète et simple. Peut être devrions nous partir de certaines de ses idées. QUelqu'un qui l'a lu récemment et qui nous ferait un résumé des principes de base sur l'alignement?

    Citation Envoyé par minnesota Voir le message
    Cela dit, j'ai personnellement du mal à aborder des patrons de conception sans avoir préalablement défini des objets concrets avec des caractéristiques concrètes. Faute d'un réel investissement ou d'une profonde réflexion, le projet va stagner. J'espère toutefois me tromper. J'aimerais que tu nous fasses part de ton avis fcharton, si tu veux bien.
    Je suis un peu comme toi... J'ai du mal à penser quelque chose en termes de patrons de conception, même si je crois qu'ils sont utiles pour décrire un projet. Pour moi c'est souvent de l'abstraction gratuite, parce que d'implémentation, qui détourne de la vraie tâche de conception, qui est l'abstraction du problème concret...

    Maintenant, je sais qu'il y a des personnes qui fonctionnement mieux quand ils partent de concepts d'implémentation. Avoir les deux débats en parallèle ne nuit pas...

    Sur le projet, ce qui m'inquiète c'est le faible nombre de participations. En général les projets collectifs, ca démarre avec plein de monde, et pas mal qui se fatiguent assez vite. Ici, on démarre très lentement...

    Mais je vais continuer à m'astreindre à un message tous les matins. Cette réflexion sur l"IHM est de toutes façons utile.

    Francois

  13. #13
    Membre éprouvé
    Profil pro
    Inscrit en
    Mai 2006
    Messages
    780
    Détails du profil
    Informations personnelles :
    Localisation : France, Haute Garonne (Midi Pyrénées)

    Informations forums :
    Inscription : Mai 2006
    Messages : 780
    Points : 1 176
    Points
    1 176
    Par défaut
    Ca serait peut être plus clair en donnant des exemples de comment on veut que le code client ressemble au final?

  14. #14
    Expert éminent sénior
    Avatar de koala01
    Homme Profil pro
    aucun
    Inscrit en
    Octobre 2004
    Messages
    11 612
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Âge : 52
    Localisation : Belgique

    Informations professionnelles :
    Activité : aucun

    Informations forums :
    Inscription : Octobre 2004
    Messages : 11 612
    Points : 30 611
    Points
    30 611
    Par défaut
    Citation Envoyé par fcharton Voir le message
    Il y a un autre bénéfice au modèle rectangulaire, c'est la "mise en page", ou l'alignement. Comment aligner deux lettres d'un mot, deux mots d'une phrase, une ellipse, un triangle?
    Cela pourrait carrément faire partie d'une politique distincte, en suivant la forme générale ou que sais-je... (les designers ont parfois de ces idées )

    C'est pour cela que j'insiste sur le fait que le calque devrait être "aussi proche que possible" de la forme qu'il contient
    Sur ces problèmes, une excellente réference est le TexBook de Knuth, qui pose les problèmes d'alignement de manière très concrète et simple. Peut être devrions nous partir de certaines de ses idées. QUelqu'un qui l'a lu récemment et qui nous ferait un résumé des principes de base sur l'alignement?
    Est il disponible quelque part
    Je suis un peu comme toi... J'ai du mal à penser quelque chose en termes de patrons de conception, même si je crois qu'ils sont utiles pour décrire un projet. Pour moi c'est souvent de l'abstraction gratuite, parce que d'implémentation, qui détourne de la vraie tâche de conception, qui est l'abstraction du problème concret...
    Et pourtant...

    Le recours régulier aux template devrait réellement nous inciter à penser exactement en terme de patrons de conceptions, parce qu'il s'agit, justement, de définir des comportements orthogonaux et "transversaux" dont la seule variante est... le type de l'objet sur lequel nous invoquons le comportement donné.
    Maintenant, je sais qu'il y a des personnes qui fonctionnement mieux quand ils partent de concepts d'implémentation. Avoir les deux débats en parallèle ne nuit pas...
    De touts façons, et cela permettra de voir "ce qui est le mieux"
    Sur le projet, ce qui m'inquiète c'est le faible nombre de participations. En général les projets collectifs, ca démarre avec plein de monde, et pas mal qui se fatiguent assez vite. Ici, on démarre très lentement...
    Je suis, à vrai dire, un peu responsable de cet état de fait, car je n'ai encore fait aucune publicité du projet.

    Au final, seuls ceux qui lisent la discussion de départ sont au courent que le projet est lancé.

    Mais avant de faire la publicité de manière un peu plus poussée, je souhaiterais que nous finalisions au moins les grandes lignes du projet et que nous ayons au moins un peu de matière, de manière à éviter les prises de décisions à 110 où il y aura toujours quelqu'un qui n'est pas d'accord
    Mais je vais continuer à m'astreindre à un message tous les matins. Cette

    Citation Envoyé par nikko34 Voir le message
    Ca serait peut être plus clair en donnant des exemples de comment on veut que le code client ressemble au final?
    Justement, hier, j'avais commencé une réponse, et je vous la met ici:

    En fait, ce que je veux dire, c'est que l'idée de bipoint pourrait parfaitement être adaptée:
    • Pour un rectangle, le premier point pourrait etre l'angle supérieur gauche et le second l'angle inférieur droit
    • Pour un cercle, le premier point pourrait être le point où le périmètre du rayon croise l'horizontale (donc le point à l'extrême gauche du cercle)
    • pour les polygones, ce serait les deux extrémités du coté gauche croisant l'horizontale par rapport au centre du cercle dans lequel le polygone est inscrit, ou la distance entre l'endroit où le coté le plus à gauche croise l'horizontale passant par le centre de la forme
    Cela nous oblige, effectivement, à certains calculs de manière à déterminer le reste (les points auxquels se situent les différents angles, par exemple) mais on aurait donc l'avantage d'avoir des calques dont la forme reflète effectivement la forme réelle de l'objet visuel.

    L'avantage, c'est qu'il n'y a, en définitive, que trois traits particuliers à définir:
    • les formes rectangulaires (incluant les carrés)
    • les cercles et disques
    • les polygones

    Nous partirions donc d'un modèle de structure proche de
    Code c++ : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    struct point2D_flag{};
    struct point3D_flag{}; // pour quand on passe aux IHM 3D
    template <typename T >
    struct TPoint< T, point2D_flag>
    {
        typedef T value_type;
        value_type x;
        value_type y;
    };
    template <typename T >
    struct TPoint< T, point2D_flag>
    {
        typedef T value_type;
        value_type x;
        value_type y;
        value_type z;
    };
    qui est desservi par les fonctions
    Code c++ : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    19
    20
    21
    22
    23
    24
    25
    26
    27
    28
    29
    30
    31
    32
    33
    34
    35
    36
    37
    38
    39
    40
    41
    42
    43
    44
    45
    46
    47
    48
    49
    50
    51
    52
    53
    54
    55
    56
    template<typename T>
    inline TPoint<T, point2D_flag> makePoint(T const & x, T const & y)
    {
        TPoint<T, point2D_flag> p;
        p.x=x;
        p.y=y;
        return p;
    }
    /* au fait, j'ai pu remarquer que Gcc accepte une second définition sous 
     * la forme de
    inline TPoint<T, point3D_flag> makePoint(T const & x,
                                             T const & y,
                                             T const & z)
    {
        TPoint<T, point3D_flag> p;
        p.x=x;
        p.y=y;
        p.z=z;
        return p;
    }
     * pour quand on passera à l'aspect de création d'IHM 3D...
     * Quelqu'un peut il confirmer que c'est également accepté
     * par VC++ ??
     */
     
    template<typename T>
    inline T euclidian(TPoint<T, point2D_flag> const & p1,
                TPoint<T, point2D_flag> const & p2)
    {
        return sqrt( ( p1.x-p2.x )* ( p1.x-p2.x )+
                     ( p1.y-p2.y )* ( p1.y-p2.y ));
    }
    template<typename T>
    inline T distance(TPoint<T, point2D_flag> const & p1,
                TPoint<T, point2D_flag> const & p2)
    {
        return (std::abs( p1.x-p2.x )+ std::abs( p1.y-p2.y ));
    }
    template<typename T>
    inline T distanceInf(TPoint<T, point2D_flag> const & p1,
                TPoint<T, point2D_flag> const & p2)
    {
        return max( abs( p1.x-p2.x ), abs( p1.y-p2.y ) );
    }
    template <typename T>
    inline bool operator==( TPoint<T, point2D_flag> const & p1,
                            TPoint<T, point2D_flag> const & p2)
    {
        return ( p1.x==p2.x && p1.y==p2.y );
    }
    template <typename T>
    inline bool operator!=( TPoint<T, point2D_flag> const & p1,
                            TPoint<T, point2D_flag> const & p2)
    {
        return ! p1 == p2;
    }
    et d'un modèle de structure bipoint proche de
    Code c++ : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
    6
    7
    8
    template<typename T, class Flag>
    struct TBipoint
    {
        typedef TPoint<T, Flag> point_type;
        typedef point_type::value_type value_type;
        point_type first; // toujours un point extérieur
        point_type second;
    };
    qui serait desservi par (entre autres) les fonctions
    Code c++ : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    template <typename T, class Flag>
    TBipoint<T,Flag> makeBipoint(TPoint<T,Flag> const & first, TPoint<T, Flag> const & second)
    /* operator== ?? */
    template<typename T, class Flag>
    bool equal(TBipoint<T, Flag const & b1, TBipoint<T, Flag> const & b2)
    {
        return (b1.first==b2.first && b1.second==b2.second );
    }
    template<typename T, class Flag>
    TBipoint<T, Flag> canonicalize(TBipoint<T, Flag> b)
    {
        if( ! ( b.first.x <= b.second.x &&
                b.first.y <= b.second.y) )
            std::swap(b.first,b.second);
        return b;
    }
    Et nous aurions enfin un modèle de classe TShape proche de
    Code c++ : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    19
    20
    21
    22
    23
    24
    25
    26
    27
    28
    29
    30
    31
    32
    33
    34
    35
    36
    37
    38
    39
    40
    41
    42
    43
    44
    45
    46
    47
    48
    49
    50
    51
    52
    53
    54
    55
    56
    57
    58
    59
    60
    61
    62
    63
    64
    65
    66
    67
    68
    69
    70
    71
    72
    73
    74
    75
    76
    77
    78
    79
    80
    81
    82
    83
    84
    85
    86
    87
    88
    89
    90
    91
    92
    93
    94
    95
    96
    97
    struct circle_flag{};
    struct rectangle_flag{};
    template<typename T, class PointFlag, class ShapeFlag>
    class TShape;
    template<typename T, class PointFlag>
    class TShape<T, PointFlag, circle_flag>
    {
        public:
            typedef TBipoint<T, PointFlag> bipoint_type;
            typedef typename bipoint_type::point_type point_type;
            typedef typename bipoint_type::value_type value_type;
            TShape(bipoint_type const & bt):bt_(bt)
            {
                assert(bt.first.y==bt.second.y);
                canonicalize(bt_);
            }
            point_type const & leftLimit() const
            {
                return bt_.first;
            }
            point_type const & center() const
            {
                return bt_.second;
            }
            T radius() const{return bt_.second.x-bt_.first.x;}
            void resize(T rad)
            {
                bt_.second.x=rad;
                canonicalize(bt_);
            }
            void move(point_type const & c)
            {
                T r=radius();
                bt_.second=c;
                bt_.first.x=bt_.second.x-r;
                bt_.first.y=bt_.second.y;
            }
            int compare(point_type const & p)
            {
                value_type px=(p.x<bt_.second.x? bt_.second.x-p.x:p.x-bt_.second.x);
                value_type py=(p.y<bt_.second.y? bt_.second.y-p.y:p.y-bt_.second.y);
                value_type hp=std::sqrt((px*px)+(py*py));
                value_type cp=px/hp;
                value_type sp=py/hp;
                value_type rad=radius();
                T res=euclidian(bt_.second,makePoint<value_type>(cp*rad, sp*rad));
                value_type pdist=euclidian(bt_.second,makePoint(px,py));
                return pdist-res;
            }
        private:
            bipoint_type bt_;
     
    };
    template<typename T, class PointFlag>
    class TShape<T, PointFlag,rectangle_flag >
    {
        public:
            typedef TBipoint<T, PointFlag> bipoint_type;
            typedef typename bipoint_type::point_type point_type;
            typedef typename bipoint_type::value_type value_type;
            TShape(bipoint_type const & bt):bt_(bt)
            {
                assert(bt.first.y==bt.second.y);
                canonicalize(bt_);
            }
     
            point_type const & topLfeft() const
            {
                return bt_.first;
            }
            point_type const & bottomRight() const
            {
                return bt_.second;
            }
            value_type width()const
            {
                return bt_.second.x-bt_.first.x;
            }
            value_type heigth()const
            {
                return bt_.second.y-bt_.first.y;
            }
            void resize(T rad)
            {
                bt_.second.x=rad;
                canonicalize(bt_);
            }
            void move(point_type const & c)
            {
                T r=this->radius();
                bt_.second=c;
                bt_.first.x=bt_.second.x-r;
                bt_.first.y=bt_.second.y;
            }
        private:
            bipoint_type bt_;
    };
    Ceci dit, je le rappelle encore une fois, il y a quantité d'autres aspects auxquels il faudra réfléchir... Et je voudrais que vous m'aidiez à en dresser la liste
    A méditer: La solution la plus simple est toujours la moins compliquée
    Ce qui se conçoit bien s'énonce clairement, et les mots pour le dire vous viennent aisément. Nicolas Boileau
    Compiler Gcc sous windows avec MinGW
    Coder efficacement en C++ : dans les bacs le 17 février 2014
    mon tout nouveau blog

  15. #15
    Invité
    Invité(e)
    Par défaut
    Une petite liste d'idées pas forcément très organisées... (koala, va falloir t'habituer à me trier...)

    En préambule, le TeXbook, c'est chez Addison Wesley, il y a une traduction en francais chez Vuibert (http://www-cs-faculty.stanford.edu/~knuth/abcde.html). On doit le trouver dans les bonnes bibliothèques, sinon, il y a, comme toujours, des pdf pirates qui trainent un peu partout. J'en recommande la lecture, comme toute l'oeuvre de Knuth, d'ailleurs...

    Les idées en vrac, maintenant...

    1- Symétrie

    Depuis qu'on parle de positionnement, et qu'on s'oriente vers un système rectangulaire (c'est à dire où tout se positionne par rapport à deux axes orthogonaux), je me dis qu'il y a, dans ces systèmes, des symétries dont on aurait intérêt à profiter dès la conception...

    En fait, dans ces modèles les deux axes sont parfaitement interchangeables : un alignement vertical, c'est comme un alignement horizontal, etc... On commence même à voir des plateformes sur lesquelles on peut les echanger très naturellement (iphone).

    Le sens de ces axes est également conventionnel : ca va vers la droite et vers le bas chez nous, parce que c'est comme ca qu'on écrit, mais on a des plate formes ou l'horizontal est orienté dans l'autre sens: l'arabe et l'hébreu par exemple, mais aussi le chinois et le japonais classiques, qui s'écrivent en colonne de la droite vers la gauche...

    Je ne sais pas très bien comment on modélise ca, mais il me semble qu'il faudrait y réfléchir... En gros, c'est un peu bête de parler de x et de y si on veut pouvoir les échanger comme on veut...


    2- Alignement

    Au delà du positionnement par coordonnées, la forme la plus courante de définition d'une IHM c'est le positionnement d'éléments les uns par rapport aux autres. Le bouton 123 n'est pas en position (42, 57), mais à 2 pixels à gauche du bouton 122... Le panel 32 ne fait pas 500 par 220, mais 220 de haut, en occupant tout l'espace horizontal allant du panel 31 au panel 33... Et ainsi de suite.

    Cette notion d'alignement est importante quand on redimensionne une fenêtre, car c'est lui qui décide du déplacement des éléments d'interface. Si on le programme correctement, l'utilisateur n'a pas besoin de gérer les redimensionnements...

    Elle joue également un rôle quand on ajoute des éléments dans un conteneur : c'est l'alignement du parent qui décide(entre autres) de l'apparition de barres de défilement...

    Dans la pratique, la présence d'un trait d'alignement provoquera le recalcul des coordonnées d'un (ou plusieurs) éléments d'interface...

    En général, l'alignement va se définir selon trois principes (je suis sur ce sujet Borland et Adobe/Flex):

    - les alignements de base : ce sont des lignes qui permettent de positionner l'élément : 4 pixels à gauche du bouton, centré au milieu de la fenêtre, etc... A priori, il y en a 2 : un horizontal, un vertical
    - les ancrages, déterminent la façon dont l'élément se déplace ou se redimensionne quand la taille de la fenêtre ou d'un de ses composants change : sur l'axe horizontal, un composant ancré sur sa gauche "suivra" le composant à gauche, un ancré à droite suivra le composant à sa droite, un ancré des deux côtés se redimensionnera horizontalement quand ses ancrages bougent
    - les contraintes, qui déterminent les tailles minimales et maximales d'un composant, elles empêchent le redimensionnement

    On pourrait éventuellement imaginer d'autres politiques de redimensionnement...

    Ces aspects se retrouvent en horizontal et en vertical... Ils ne sont pas parfaitement orthogonaux au positionnement : en fait, quand on a alignement, le positionnement initial est recalculé en fonction de l'alignement


    3- Fontes et texte

    Un certain nombre d'éléments d'interface se verront affecter du texte (une légende, des données...). Le texte doit pouvoir se définir selon trois axes :

    - le texte à afficher
    - une police d'affichage (avec sa taille)
    - un point de départ

    Un certain nombre de fonctions de base doivent être rendues disponibles, notamment le calcul de l'espace occuppé par un texte, le clipping (ou les ellipses), éventuellement les primitives permettant l'écriture sur plusieurs lignes).

    L'affichage du texte est presque un sujet à part...

    4- Formes de base

    Comme Koala en parlait, je suggérerais bien que l'on considère dans un premier temps, comme éléments de base

    - les points
    - les lignes (définies par un bipoint, une épaisseur, des paramètres de dessin)
    - les arcs (on a plusieurs choix, là : arcs de cercle, splines, courbes de bézier, NURBS, chacun plus riche que le précédent, mais plus complexe pour l'utilisateur aussi)

    - les rectangles (parallèles aux axes), un carré c'est un rectangle, et les coins ronds, ca fait partie du rectangle
    - les ellipses (parallèles aux axes aussi), un cercle c'est une ellipse
    - les polygones, qui sont une liste de points, engendrant un polygone, ou une suite d'arcs fermés
    Toutes ces surfaces ont une bordure (éventuellement transparente), et un intérieur (pareil)
    (je ne fais pas de différence entre cercles et disques : un cercle, c'est un disque dont l'intérieur est transparent...)

    - les caractères et les chaines de texte

    5- Pointage, souris, clavier

    On a, en gros, deux types de dispositifs :

    - des dispositifs "non pointants" (clavier, joystick, ...) qui envoient des messages à l'application toute entière (généralement à un composant actif, via une notion de "focus" géré au niveau de l'appli)
    - des dispositifs pointants (souris, et autres), qui envoient des messages (généralement plus simples), et une information de position (éventuellement de mouvement, les "gestures"), l'IHM doit alors déterminer le récepteur de ce message...

    En fait, toute la gestion "globale" de ces dispositifs se limite à deux notions :

    - une notion de "focus" : composant d'interface qui recoit en ce moment, les messages du clavier
    - une fonction permettant d'attribuer à chaque point de l'écran (ou de la zone "pointable" de celui ci, un élement d'interface qui recevra le message.

    Au niveau des éléments, je pense qu'on devra définir un certain nombre de traits de base, correspondant aux interactions les plus fréquentes (clic souris, survol, bouton relaché/enfoncé, frappe d'une touche), et permettre la redéfinition d'évènements supplémentaires.


    Francois
    Dernière modification par Invité ; 23/04/2010 à 00h28.

  16. #16
    Expert éminent sénior
    Avatar de koala01
    Homme Profil pro
    aucun
    Inscrit en
    Octobre 2004
    Messages
    11 612
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Âge : 52
    Localisation : Belgique

    Informations professionnelles :
    Activité : aucun

    Informations forums :
    Inscription : Octobre 2004
    Messages : 11 612
    Points : 30 611
    Points
    30 611
    Par défaut
    Citation Envoyé par fcharton Voir le message
    Une petite liste d'idées pas forcément très organisées... (koala, va falloir t'habituer à me trier...)
    Ne t'en fais pas, je sais ce que c'est

    Et toi, il faudra que tu t'habitue en retour au fait que je réfléchis souvent "tout haut" (ou, sur le forum, "par écrit")... et que tu n'hésite surtout pas à reprendre les points qui ne te paraissent incorrect ou peu clairs... C'est un deal
    En fait, dans ces modèles les deux axes sont parfaitement interchangeables : un alignement vertical, c'est comme un alignement horizontal, etc... On commence même à voir des plateformes sur lesquelles on peut les echanger très naturellement (iphone).

    Le sens de ces axes est également conventionnel : ca va vers la droite et vers le bas chez nous, parce que c'est comme ca qu'on écrit, mais on a des plate formes ou l'horizontal est orienté dans l'autre sens: l'arabe et l'hébreu par exemple, mais aussi le chinois et le japonais classiques, qui s'écrivent en colonne de la droite vers la gauche...

    Je ne sais pas très bien comment on modélise ca, mais il me semble qu'il faudrait y réfléchir... En gros, c'est un peu bête de parler de x et de y si on veut pouvoir les échanger comme on veut...
    Peut être en définissant:
    • une politique "orientation " (l'axe des X va de gauche à droite ou de haut en bas et l'axe des y va... perpendiculairement)
    • une politique "sens horizontal"
    • une politique "sens vertical"

    A mon sens, le bipoint est le mieux placé pour prendre cela en charge... Mais ai-je raison de le penser Faut-il en faire des politiques "globale" (dans le sens où tous les objets suivent par défaut les mêmes) ou une politique "particulière", en donnant la possibilités à deux éléments visuels d'une même "fenêtre" la possibilité d'avoir des politiques différentes (et parfois totalement opposées)

    Quelque part, s'il est possible d'avoir des politiques différentes pour chaque objet, cela ouvre des horizons innombrables... et implique des casses tête pour ce qui est de la définition des référenciels

    2- Alignement

    Au delà du positionnement par coordonnées, la forme la plus courante de définition d'une IHM c'est le positionnement d'éléments les uns par rapport aux autres. Le bouton 123 n'est pas en position (42, 57), mais à 2 pixels à gauche du bouton 122... Le panel 32 ne fait pas 500 par 220, mais 220 de haut, en occupant tout l'espace horizontal allant du panel 31 au panel 33... Et ainsi de suite.
    Ce qui, de manière assez marrante, implique qu'il faut prendre la distance entre... le coté droit (quel que soit le sens que l'on donne à "droit" dans notre cas ) d'un des élément et... le coté gauche de l'autre
    Cette notion d'alignement est importante quand on redimensionne une fenêtre, car c'est lui qui décide du déplacement des éléments d'interface. Si on le programme correctement, l'utilisateur n'a pas besoin de gérer les redimensionnements...
    Effectivement...

    Mais, tant qu'à faire, je souhaiterait quelque chose de plus souple que ce qui est proposé par Qt, par exemple, où lorsque l'on travaille avec une grille, il n'est pas possible de mettre un élément tenant sur deux lignes à coté de deux éléments tenant sur une ligne sans passer par un "canevas" supplémentaire...

    Elle joue également un rôle quand on ajoute des éléments dans un conteneur : c'est l'alignement du parent qui décide(entre autres) de l'apparition de barres de défilement...
    Elle intervient, effectivement, partout

    Dans la pratique, la présence d'un trait d'alignement provoquera le recalcul des coordonnées d'un (ou plusieurs) éléments d'interface...
    ou, en tout cas, de tous les éléments "enfant" de l'élément auquel le trait est appliqué, effectivement (et il pourrait être "hérité" par les enfants, mais pas forcément )
    En général, l'alignement va se définir selon trois principes (je suis sur ce sujet Borland et Adobe/Flex):

    - les alignements de base : ce sont des lignes qui permettent de positionner l'élément : 4 pixels à gauche du bouton, centré au milieu de la fenêtre, etc... A priori, il y en a 2 : un horizontal, un vertical
    - les ancrages, déterminent la façon dont l'élément se déplace ou se redimensionne quand la taille de la fenêtre ou d'un de ses composants change : sur l'axe horizontal, un composant ancré sur sa gauche "suivra" le composant à gauche, un ancré à droite suivra le composant à sa droite, un ancré des deux côtés se redimensionnera horizontalement quand ses ancrages bougent
    - les contraintes, qui déterminent les tailles minimales et maximales d'un composant, elles empêchent le redimensionnement
    Hé oui...

    On pourrait éventuellement imaginer d'autres politiques de redimensionnement...
    Et de positionnement...

    Tu avais émis l'idée (dans la discussion qui a précédé le lancement du projet) me semble-t-il de pouvoir faire en sorte qu'un élément soit dépende d'un autre sans pour autant qu'il ne soit limité en terme de positionnement par l'espace occupé par celui-ci... (en gros, avoir une boite à outil à gauche et un des boutons de celle-ci à droite)

    Faudra relire la discussion, mais c'était une idée qui m'avait charmé

    Ces aspects se retrouvent en horizontal et en vertical... Ils ne sont pas parfaitement orthogonaux au positionnement : en fait, quand on a alignement, le positionnement initial est recalculé en fonction de l'alignement
    Effectivement, ils travaillent de concert dans une certaine mesure et sont sans doute parfois exlusifs


    3- Fontes et texte

    Un certain nombre d'éléments d'interface se verront affecter du texte (une légende, des données...). Le texte doit pouvoir se définir selon trois axes :

    - le texte à afficher
    - une police d'affichage (avec sa taille)
    - un point de départ
    Je rajouterais la forme...

    Un peu (si tu as déjà utilisé le genre d'outils auxquels je pense) à la manière des logiciels de création de bannières, de cartes postales, ou de couvertures de boite de CD, qui permettent d'avoir une écriture en forme de vague, de serpent, ou qui suit un arc de cercle.

    Evidemment, cela ne peut réellement fonctionner, dans le meilleur des cas, qu'avec des polices vectorielles

    Un certain nombre de fonctions de base doivent être rendues disponibles, notamment le calcul de l'espace occuppé par un texte, le clipping (ou les ellipses), éventuellement les primitives permettant l'écriture sur plusieurs lignes).

    L'affichage du texte est presque un sujet à part...
    Oui, outre le tracé des forme et la transmission des messages, l'affichage de texte fera partie des gros morceaux

    N'hésite pas à ouvrir une discussion sur le sujet

    4- Formes de base

    Comme Koala en parlait, je suggérerais bien que l'on considère dans un premier temps, comme éléments de base

    - les points
    - les lignes (définies par un bipoint, une épaisseur, des paramètres de dessin)
    - les arcs (on a plusieurs choix, là : arcs de cercle, splines, courbes de bézier, NURBS, chacun plus riche que le précédent, mais plus complexe pour l'utilisateur aussi)
    donc, ton bipoint n'avait pas pour objectif de définir en lui-même un "rectangle de base", mais bien, simplement, de définir... un "segment de droite" (y a-t-il un meilleur terme ) que l'on assigne en définitive à ce qu'on veut (comme j'en ai montré l'exemple), c'est bien ca (je commence à fatiguer, et j'hésite sur le sens à donner à ta phrase )

    - les rectangles (parallèles aux axes), un carré c'est un rectangle, et les coins ronds, ca fait partie du rectangle
    Effectivement, un carré n'est (ici du moins) jamais qu'un rectangle particulier... Par contre, il serait alors sympa d'avoir un moyen de vérifier H == L lorsque l'utilisateur veut garantir que c'est un carré (mais bon, cela peut n'être qu'un booléen placé à true ou à false )
    - les ellipses (parallèles aux axes aussi), un cercle c'est une ellipse
    Cela implique, malheureusement, d'avoir... deux rayons (un rayon sur chacun des axes)... encore une fois, quitte à ce que le cercle soit considéré comme une éclipse dont les deux rayons sont de taille identique (encore une fois, un booléen peut y suffire )

    Et cela nous mène, finalement, à un choix "crucial"...

    Qu'est ce qui est préférable, selon vous:
    1. De se dire que le cercle ou le carré ne sont que des "aberrations" (dans le sens de "particularités, voulues ou non, susceptibles de changer "à tout moment") des ellipses / rectangles
    2. De se dire que l'on donne le choix à l'utilisateur de placer un cercle ou une éclipse (un carré ou un rectangle), mais qu'il ne peut revenir sur sa décision par la suite
    3. de se dire que l'utilisateur peut placer une ellipse ou un rectangle et décider à n'importe quel moment de placer... ou retirer une restriction supplémentaire les faisant devenir cercle ou carré.

    Le (3) me semble le plus approprié, mais il faut alors décider de la manière dont on organise la transition:
    1. Choisi-t-on de réduire le rayon / coté, pour le rectangle le plus grand à la taille du rayon / coté le plus petit
    2. choisi-t-on d'agrandir le rayon /coté le plus petit à la taille du rayon / coté le plus grand
    3. choisi-t-on d'adapter les deux tailles en fonction de l'espace utile disponible le plus grand possible entre les deux rayons /cotés
    4. Pourrait-on envisager la mise au point de traits de politiques qui permettent au développeur avancé de choisir lui-même la réaction qui lui convient le mieux


    - les polygones, qui sont une liste de points, engendrant un polygone, ou une suite d'arcs fermés
    Là, par contre, cela peut poser problème...

    Si l'on déplace un des angles, est-ce que les autres se déplacent en proportion dans les directions adéquates afin de "simplement" redimensionner l'objet, ou admet-on que l'utilisateur puisse "tout aussi simplement" décider d'écarter un seul angle où bon lui semble (autrement dit, doit on se limiter aux polygones convexes, ou peut on envisager les polygones concave, voir croisés )

    D'une certaine manière, avec mon étoile à cinq branches, il semblerait que je milite pour permettre les polygones concave et / ou croisés
    Toutes ces surfaces ont une bordure (éventuellement transparente), et un intérieur (pareil)
    (je ne fais pas de différence entre cercles et disques : un cercle, c'est un disque dont l'intérieur est transparent...)
    Je partais du même principe pour les disques...

    Pour ce qui est de la bordure, si je te comprend bien, on en revient au bipoint et à son épaisseur afin de pouvoir "jouer" avec


    5- Pointage, souris, clavier

    On a, en gros, deux types de dispositifs :

    - des dispositifs "non pointants" (clavier, joystick, ...) qui envoient des messages à l'application toute entière (généralement à un composant actif, via une notion de "focus" géré au niveau de l'appli)
    - des dispositifs pointants (souris, et autres), qui envoient des messages (généralement plus simples), et une information de position (éventuellement de mouvement, les "gestures"), l'IHM doit alors déterminer le récepteur de ce message...

    En fait, toute la gestion "globale" de ces dispositifs se limite à deux notions :

    - une notion de "focus" : composant d'interface qui recoit en ce moment, les messages du clavier
    - une fonction permettant d'attribuer à chaque point de l'écran (ou de la zone "pointable" de celui ci, un élement d'interface qui recevra le message.

    Au niveau des éléments, je pense qu'on devra définir un certain nombre de traits de base, correspondant aux interactions les plus fréquentes (clic souris, survol, bouton relaché/enfoncé, frappe d'une touche), et permettre la redéfinition d'évènements supplémentaires.
    Rien à dire sur ce point (enfin, pour l'instant )
    A méditer: La solution la plus simple est toujours la moins compliquée
    Ce qui se conçoit bien s'énonce clairement, et les mots pour le dire vous viennent aisément. Nicolas Boileau
    Compiler Gcc sous windows avec MinGW
    Coder efficacement en C++ : dans les bacs le 17 février 2014
    mon tout nouveau blog

  17. #17
    Invité
    Invité(e)
    Par défaut
    Citation Envoyé par koala01 Voir le message
    Et toi, il faudra que tu t'habitue en retour au fait que je réfléchis souvent "tout haut" (ou, sur le forum, "par écrit")... et que tu n'hésite surtout pas à reprendre les points qui ne te paraissent incorrect ou peu clairs... C'est un deal
    J'achète, et pour bien commencer, une petite remarque sur la forme canonique du bipoint (qui, soit dit en passant, ne s'appliquera pas aux lignes ni d'ailleurs aux polygones):

    au lieu de
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
    6
    7
    8
    template<typename T, class Flag>
    TBipoint<T, Flag> canonicalize(TBipoint<T, Flag> b)
    {
        if( ! ( b.first.x <= b.second.x &&
                b.first.y <= b.second.y) )
            std::swap(b.first,b.second);
        return b;
    }
    je crois que c'est
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
    6
    7
    template<typename T, class Flag>
    TBipoint<T, Flag> canonicalize(TBipoint<T, Flag> b)
    {
    return MakeBipoint(
       MakePoint(std::min(b.first.x,b.second.x),std::min(b.first.y,b.second.y),
       MakePoint(std::max(b.first.x,b.second.x),std::max(b.first.y,b.second.y))
    }

    Peut être en définissant:
    • une politique "orientation " (l'axe des X va de gauche à droite ou de haut en bas et l'axe des y va... perpendiculairement)
    • une politique "sens horizontal"
    • une politique "sens vertical"
    Je me disait que peut être qu'il faudrait définir la "dimension" (x et y sont des dimensions) comme un type de base, qu'on pourrait passer aux traits qui en ont besoin... On aurait donc un trait alignement qui serait paramétré par une "dimension", ie vertical ou horizontal...

    Après, je disais des bêtises sur l'échange des dimensions...

    Si les politiques, il va falloir faire attention à un truc... Eliminer la complexité verticale que crée le super objet et la hiérarchie de classes associée, c'est bien. Le remplacer par un fouillis de micropolitiques même pas orthogonales, c'est mal... Honnêtement je soupconne que le sens, c'est un paramétrage de rendu qu'on délèguera joyeusement au moteur.

    Faut-il en faire des politiques "globale" (dans le sens où tous les objets suivent par défaut les mêmes) ou une politique "particulière", en donnant la possibilités à deux éléments visuels d'une même "fenêtre" la possibilité d'avoir des politiques différentes (et parfois totalement opposées)
    Dans le cas des sens des axes, je crois que les contraintes d'alignement et de recalcul de position rendent l'approche locale compliquée... Ce qu'on peut imaginer, néanmoins, c'est d'avoir une approche hierarchique: un peu comme un quotidien japonais, dans lequel certains titrres sont verticaux, des articles à l'occidentale, etc... Au niveau le plus haut, on a des "blocs" qui s'organisent selon une politique globale. Dans chaque bloc, on peut avoir des politiques différentes (tiens, ca nous ramène au composite, ca...)

    Mais, tant qu'à faire, je souhaiterait quelque chose de plus souple que ce qui est proposé par Qt, par exemple, où lorsque l'on travaille avec une grille, il n'est pas possible de mettre un élément tenant sur deux lignes à coté de deux éléments tenant sur une ligne sans passer par un "canevas" supplémentaire...
    Oui... J'ai eu la sensation que Flex se débrouillait assez bien... Je vais regarder également ce que font les versions modernes de Borland. La difficulté est double, ici, il faut à la fois avoir quelque chose de flexible, et de facile à prendre en main...

    Tu avais émis l'idée (dans la discussion qui a précédé le lancement du projet) me semble-t-il de pouvoir faire en sorte qu'un élément soit dépende d'un autre sans pour autant qu'il ne soit limité en terme de positionnement par l'espace occupé par celui-ci... (en gros, avoir une boite à outil à gauche et un des boutons de celle-ci à droite)
    Oui, ca c'est un truc que je fais pas mal avec Borland... En fait, ils ont deux hiérarchies composites : l'une qui concerne "l'ownership" (qui alloue, qui libère), l'autre qui concerne la parenté (qui clippe, qui affiche). Du coup, tu peux bâtir une "forme" unique (donc un module en terme d'allocation), mais affecter ses composants à des "bouts différents" de l'interface.

    C'est très sympa, mais bon, ca cause aussi des bugs assez spectaculaires...

    Un peu (si tu as déjà utilisé le genre d'outils auxquels je pense) à la manière des logiciels de création de bannières, de cartes postales, ou de couvertures de boite de CD, qui permettent d'avoir une écriture en forme de vague, de serpent, ou qui suit un arc de cercle.
    D'accord pour cela, mais je ne crois pas qu'il faille en faire une "propriété par défaut"... C'est un peu comme les polygones ou les arcs, si tu veux. Il nous en faut, mais ce n'est pas l'outil par défaut... En général du texte, c'est bêtement linéaire (et du coup tu peux utiliser toutes les polices de la mort qui ne sont même pas vectorielles, mais indispensables à ton activité)

    Oui, outre le tracé des forme et la transmission des messages, l'affichage de texte fera partie des gros morceaux
    Mais c'est là que l'OS fournit des primitives détaillées... On est dans un domaine de wrappers. Je vais essayer d'ouvrir des fils sur les primitives Windows, en espérant que Goten vienne y causer de Linux...

    donc, ton bipoint n'avait pas pour objectif de définir en lui-même un "rectangle de base", mais bien, simplement, de définir... un "segment de droite" (y a-t-il un meilleur terme ) que l'on assigne en définitive à ce qu'on veut (comme j'en ai montré l'exemple), c'est bien ca (je commence à fatiguer, et j'hésite sur le sens à donner à ta phrase )
    Un bipoint, c'est juste deux points... C'est une structure qui revient partout... Ca peut définir une ligne, un rectangle, une ellipse, ou... deux points.

    Ce qu'il y a, et j'ai probablement un peu tout mélangé dans mon post précédent, c'est qu'il va nous falloir des lignes et des arcs, comme primitives de dessin, et des rectangles et des cercles comme formes de base (sachant que le "cadre" du rectangle est quelque part une primitive de dessin...)


    Cela implique, malheureusement, d'avoir... deux rayons (un rayon sur chacun des axes)... encore une fois, quitte à ce que le cercle soit considéré comme une éclipse dont les deux rayons sont de taille identique (encore une fois, un booléen peut y suffire )
    En fait, tu peux définir une ellipse (aux axes parallèles aux coordonnées) par le rectangle qui l'inclut. Ses "rayons" ont pour taille les demi dimensions du rectangle.

    Dans ce modèle, un carré ou un cercle, c'est une contrainte particulière sur le rectangle : dimensions égales... On peut la forcer comme une "politique d'alignement" (ce sont des dimensions qui se recalculent, en fait)


    Si l'on déplace un des angles, est-ce que les autres se déplacent en proportion dans les directions adéquates afin de "simplement" redimensionner l'objet, ou admet-on que l'utilisateur puisse "tout aussi simplement" décider d'écarter un seul angle où bon lui semble (autrement dit, doit on se limiter aux polygones convexes, ou peut on envisager les polygones concave, voir croisés )
    Pour moi, un polygone, c'est juste une ligne brisée, dont on décide qu'elle se referme à la fin...

    Pour ce qui est de la bordure, si je te comprend bien, on en revient au bipoint et à son épaisseur afin de pouvoir "jouer" avec
    Oui, côté rendu, on retrouve les deux primitives usuelles des OS : le PEN (crayon) qui sert à dessiner les contours, et le BRUSH (pinceau) qui sert à peindre les intérieurs. (Pour un polygone compliqué, la notion d'intérieur sera un peu complexe à définir...) Le PEN a une épaisseur, les deux ont un pattern (texture?), une ou plusieurs couleurs unies par des gradients (c'est ce que GDI+ fait nativement...), sachant que la couleur, chez nous, a 4 composantes RGBA : le dernier étant la transparence...


    Bon, deux choses me paraissent importantes à ce stade :

    1- il faut qu'on commence à regarder les primitives des OS, c'est notre reality check
    2- il faut qu'on pose la question du modèle général : le composite et les widgets...

    Francois

  18. #18
    Expert éminent sénior
    Avatar de koala01
    Homme Profil pro
    aucun
    Inscrit en
    Octobre 2004
    Messages
    11 612
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Âge : 52
    Localisation : Belgique

    Informations professionnelles :
    Activité : aucun

    Informations forums :
    Inscription : Octobre 2004
    Messages : 11 612
    Points : 30 611
    Points
    30 611
    Par défaut
    Citation Envoyé par fcharton Voir le message
    J'achète, et pour bien commencer, une petite remarque sur la forme canonique du bipoint (qui, soit dit en passant, ne s'appliquera pas aux lignes ni d'ailleurs aux polygones):

    au lieu de
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
    6
    7
    8
    template<typename T, class Flag>
    TBipoint<T, Flag> canonicalize(TBipoint<T, Flag> b)
    {
        if( ! ( b.first.x <= b.second.x &&
                b.first.y <= b.second.y) )
            std::swap(b.first,b.second);
        return b;
    }
    je crois que c'est
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
    6
    7
    template<typename T, class Flag>
    TBipoint<T, Flag> canonicalize(TBipoint<T, Flag> b)
    {
    return MakeBipoint(
       MakePoint(std::min(b.first.x,b.second.x),std::min(b.first.y,b.second.y),
       MakePoint(std::max(b.first.x,b.second.x),std::max(b.first.y,b.second.y))
    }
    Ah, j'avais mal compris



    Je me disait que peut être qu'il faudrait définir la "dimension" (x et y sont des dimensions) comme un type de base, qu'on pourrait passer aux traits qui en ont besoin... On aurait donc un trait alignement qui serait paramétré par une "dimension", ie vertical ou horizontal...

    Après, je disais des bêtises sur l'échange des dimensions...

    Si les politiques, il va falloir faire attention à un truc... Eliminer la complexité verticale que crée le super objet et la hiérarchie de classes associée, c'est bien. Le remplacer par un fouillis de micropolitiques même pas orthogonales, c'est mal...
    En fait, c'est peut être beaucoup plus orthogonal que tu ne l'imagine...

    La première défini "l'horizontale" et la "verticale" et donc quelle valeur intervient comme X et quelle autre intervient comme Y d'un point
    La deuxième permet de définir la valeur la plus petite entre deux valeur X
    La troisième permet de définir la valeur la plus petite entre deux valeurs Y

    Nous avons donc bien trois aspects différents (en fait deux aspect différents, dont un auquel on donne un double sens) proposant chacun deux possibilités qui, lorsqu'on les regroupe nous permettent de... définir 8 situations clairement différentes.

    A l'extrême limite, une fois que nous aborderons l'aspect 3D, il "suffira" d'utiliser deux fois la politique d'horizontalité (en veillant à ce que les traits utilisés soient exclusifs) pour ajouter la profondeur, et obtenir nos... 64 possibilités de sens et d'orientation

    Nous pourrions donc partir (free style intégral ) sur des traits proches de:
    Code c++ : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    19
    20
    21
    22
    23
    24
    25
    26
    27
    28
    29
    30
    31
    32
    33
    34
    35
    36
    37
    38
    39
    40
    41
    42
    43
    44
    45
    46
    47
    48
    49
    50
    51
    52
    53
    54
    55
    56
    57
    58
    59
    60
    61
    62
    63
    64
    65
    66
    67
    68
    69
    70
    71
    72
    73
    74
    75
    76
    77
    78
    79
    80
    81
    82
    83
    84
    85
    86
    87
    /* l'horizontale réelle */
    struct horizontal_flag{enum {value=0};}; 
    /* la verticale réelle */
    struct vertical_flag{enum{value =1};};
    /* la profondeur réelle (quand en 3D) */
    struct depth_flag{{enum{value =2};};
    /* lecture "de gauche à droite" */
    struct letf2Right_flag{};
    /* lecture "de droite à gauche" */
    struct right2Left_flag{};
    /* la comparaison "classique" */
    template<typename T,class Flag>
    struct less
    {
        bool operator()(T const & v1, T const &v2)
        {
            return v1<v2;
        }
    };
    /* la comparaison "de droite à gauche" */
    template<typename T>
    struct less<T, right2Left_flag>
    {
        bool operator()(T const & v1, T const &v2)
        {
            return v1>v2;
        }
     
    };
    /* le point est modifié en 
     * (faudra que je vérifie les variadic template, mais je crois que c'est
     *  comme ca que ca marche :P )
     */
    template <typename T,class point_flag, class ... Flag>
    class TPoint;
    /* le point 2D devient */
    template<typename T, class XAxis>
    class TPoint<T, point2D_flag, XAxis>
    {
        public:
            enum 
            {
                xValue = XAxis::value,
                yValue = (xValue==0 ? 1 : 0)
            };
            TPoint(T const & x, T const & y)
            {
                values_[xValue]=x;
                values_[yValue]=y;
            }
            T const x()const{return values_[xValue];}
            T const y()const{return values_[yValue];}
        private:
        T values_[2];
     
    };
    /* je ne sais pas si on peut donner des valeurs par défaut ici...
     */
    template< typename T, class XAxis = horizontal_flag, 
              class YAxis = vertical_flag, class ZAxis = depth_flag >
    class TPoint<T, point3D_flag, XAxis, YAxis, ZAxis>
    {
        public:
            static_assert( XAxis::value!= YAxis::value && 
                           XAxis::value!=ZAxis::value &&
                           YAxis::value!=ZAxis::value);
            enum 
            {
                xValue = XAxis::value,
                yValue = xValue==0 ? 1 : 0;
            };
            TPoint(T const &x, T const & y, T const & z)
            {
                values_[xValue]=x;
                values_[yValue]=y;
                values_[zValue]=z;
            }
            T const x()const{return values_[xValue];}
            T const y()const{return values_[yValue];}
            T const z()const{return values_[zValue];}
        private:
        T values_[3];
     
    };
    /* les différentes fonctions relatives aux points étant modifiées afin 
     * d'appeler les fonctions respectives x(), y() et z()
     */
    Bipoint serait modifié en:
    Code c++ : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    19
    20
    21
    22
    23
    24
    25
    26
    27
    28
    29
    30
    31
    32
    33
    34
    35
    36
    37
    template <typename T, class PointFlag, class ...Flags>
    class bipoint;
    /* de cette manière, nous devrions pouvoir créer un sur base
     * de points utilisant des référenciels différents
     * (et même pouvoir décider de choisir un référenciel différents
     * des deux points d'origine :D)
     */
    template<typename T, class X1, class X2=X1, class Final=X1 >
    class TBipoint<T, point2D_flag, X1, X2, Final>
    {
        public:
            enum 
            {
                xValue = Final::xValue;
                yValue = Final::yValue;
                firstValue = xValue;
                secondValue= yValue;
            };
            typedef TPoint< T, Point2D_flag, Final> point_type;
            typedef typename point_type::value_type value_type;
            TBipoint( TPoint<T point2D_flag, X1> const & p1,
                     TPoint<T point2D_flag,X2> const & p2)
            {
                T x1= p1.x();
                T x2=p2.x();
                T y1=p1.x();
                T y2.p2.x();
                point_[firstValue] = point_type( (x1<=x2? x1 : x2), 
                                                 (y1<=y2? y1:y2));
                point_[secondValue] = point_type( (x1>x2? x1 : x2), 
                                                  (y1>y2? y1:y2));
            }
            point_type const & firstPoint() const{return point_[firstValue];}
            point_type const & secondPoint() const{return point_[secondValue];}
        private:
            point_type point_[2];
    }
    Je l'ai dit, c'est du "free style" non testé... Mais l'idée est là

    Honnêtement je soupconne que le sens, c'est un paramétrage de rendu qu'on délèguera joyeusement au moteur.
    En fait je ne crois même pas... ca permet réellement de définir... lequel des points d'un bipoint est considéré comme le premier et lequel est considéré comme... deuxième.

    Cela s'applique donc à tout ce qui peut nécessiter la comparaisons entre deux points


    Dans le cas des sens des axes, je crois que les contraintes d'alignement et de recalcul de position rendent l'approche locale compliquée... Ce qu'on peut imaginer, néanmoins, c'est d'avoir une approche hierarchique: un peu comme un quotidien japonais, dans lequel certains titrres sont verticaux, des articles à l'occidentale, etc... Au niveau le plus haut, on a des "blocs" qui s'organisent selon une politique globale. Dans chaque bloc, on peut avoir des politiques différentes (tiens, ca nous ramène au composite, ca...)
    Oui... J'ai eu la sensation que Flex se débrouillait assez bien... Je vais regarder également ce que font les versions modernes de Borland. La difficulté est double, ici, il faut à la fois avoir quelque chose de flexible, et de facile à prendre en main...
    Je pensais en fait à la grille borland (du moins, borland 6), qui, exception faite de l'agrandissement de la fenêtre, permet de placer un élément visuel "n'importe où"...

    Mais (et je recommence à réfléchir tout haut ) si on réfléchissait en fait à... ce qu'est et ce que fait la grille

    En fait, c'est référentiel composé... d'un bipoint <edit> dont le point d'origine relatif à son parent est fixé (0,0) et correspond au point d'origine du parent et dont le point terminal correspond à la position relative par rapport au poin d'origine qu'est le point terminal de son parent)</edit> à qui peut forcer... les bipoints qui se trouvent sur "sa zone d'influence" à se redimensionner ou à se déplacer en fonctions des autres et de l'espace occupé par le bipoint de référence, non ?

    Autrement dit, ce n'est "qu'un" visiteur qui:
    • peut utiliser un pas déterminé (mais un simple modulo permet de le gérer )
    • se base sur son bipoint pour déterminer les limites "globales" admise
    • calcule l'espace disponible entre deux bipoints passant par les même coordonnées sur un axe donné
    • se base sur les contraintes de taille des bipoints qu'il visite pour les forcer à se redimensionner
    • se base sur les contraintes de position des bipoints qu'il visite pour les forcer à se repositionner
    • se base sur l'éventuel "dépassement" des bipoints qu'il visite pour en forcer certains à apparaitre, ou à disparaitre (je parle des ascenseurs ici )

    Ses contraintes sont:
    de permettre (ou non) l'apparition d'ascenseurs verticaux et horizontaux
    de ne pouvoir être redimensionné que dans les limites de son parent

    Enfin, n'importe quel bipoint utilisé comme composant visuel pourrait agir comme un grille pour son contenu

    N'y aurait-il pas quelque chose à faire de ce coté
    Oui, ca c'est un truc que je fais pas mal avec Borland... En fait, ils ont deux hiérarchies composites : l'une qui concerne "l'ownership" (qui alloue, qui libère), l'autre qui concerne la parenté (qui clippe, qui affiche). Du coup, tu peux bâtir une "forme" unique (donc un module en terme d'allocation), mais affecter ses composants à des "bouts différents" de l'interface.

    C'est très sympa, mais bon, ca cause aussi des bugs assez spectaculaires...
    En fait, il faut "blinder" les chose pour que ce soit le propriétaire qui décide de détruire l'objet et que l'objet signale sa destruction à son parent...

    Et cet manière de faire doit être automatique
    D'accord pour cela, mais je ne crois pas qu'il faille en faire une "propriété par défaut"... C'est un peu comme les polygones ou les arcs, si tu veux. Il nous en faut, mais ce n'est pas l'outil par défaut... En général du texte, c'est bêtement linéaire (et du coup tu peux utiliser toutes les polices de la mort qui ne sont même pas vectorielles, mais indispensables à ton activité)
    Tout à fait...
    Mais c'est là que l'OS fournit des primitives détaillées... On est dans un domaine de wrappers. Je vais essayer d'ouvrir des fils sur les primitives Windows, en espérant que Goten vienne y causer de Linux...
    Exccccellente initiative
    Un bipoint, c'est juste deux points... C'est une structure qui revient partout... Ca peut définir une ligne, un rectangle, une ellipse, ou... deux points.
    Ok... je m'étais très mal exprimé, mais c'est effectivement ce que je pensais (comme le laissait transparaitre mon code )
    Ce qu'il y a, et j'ai probablement un peu tout mélangé dans mon post précédent, c'est qu'il va nous falloir des lignes et des arcs, comme primitives de dessin, et des rectangles et des cercles comme formes de base (sachant que le "cadre" du rectangle est quelque part une primitive de dessin...)
    ouaip... A rajouter à la liste de la facade utilisée pour faire le lien avec l'OS
    En fait, tu peux définir une ellipse (aux axes parallèles aux coordonnées) par le rectangle qui l'inclut. Ses "rayons" ont pour taille les demi dimensions du rectangle.
    Pourquoi je n'y ai pas pensé
    Dans ce modèle, un carré ou un cercle, c'est une contrainte particulière sur le rectangle : dimensions égales... On peut la forcer comme une "politique d'alignement" (ce sont des dimensions qui se recalculent, en fait)
    Donc, une fois que l'utilisateur a décidé que c'est un carré et que c'est compilé, ca reste un carré...
    Pour moi, un polygone, c'est juste une ligne brisée, dont on décide qu'elle se referme à la fin...
    Ok... donc mon étoile à cinq branches entre bel et bien dans la catégorie des polygones
    Oui, côté rendu, on retrouve les deux primitives usuelles des OS : le PEN (crayon) qui sert à dessiner les contours, et le BRUSH (pinceau) qui sert à peindre les intérieurs. (Pour un polygone compliqué, la notion d'intérieur sera un peu complexe à définir...) Le PEN a une épaisseur, les deux ont un pattern (texture?), une ou plusieurs couleurs unies par des gradients (c'est ce que GDI+ fait nativement...),
    OK... une forme est donc "délimitée" (au niveau du rendu) par
    son "périmetre" (les différentes ligne qui finissent par se refermer), qui dispose d'un "crayon" associé à une couleur ou une texture
    par ce qui se trouve "à l'intérieur" du périmetre, et qui dispose d'un pinceau associé à une (ou plusieurs) couleur ou à une texture
    sachant que la couleur, chez nous, a 4 composantes RGBA : le dernier étant la transparence...
    A vrai dire, je me demandais s'il n'était pas utile de permettre les "anciennes" méthodes de gestion de couleurs, et permettre d'utiliser :
    • (celles dont je suis sur de l'existence)
      • le noir et blanc
      • les couleurs 8 bits (1 bits "clignotant", 3 bits de fond, 4 bits d'écriture)
      • les tons de gris
      • le RGB "classique" (couleurs 24 bits)
      • le RGBA (couleurs 32 bits)
    • (celles dont il me semble me rappeler)
      • YUV :qustion:
      • y en a pas une basée sur la teinte, la luminosité et (le gama?)
    • Et celles que j'aurais oubliées
    Ce ne seraient en fait évidemment que des politiques qui ne prendraient que ce qui les intéresse au niveau des primitives OS
    Bon, deux choses me paraissent importantes à ce stade :

    1- il faut qu'on commence à regarder les primitives des OS, c'est notre reality check
    2- il faut qu'on pose la question du modèle général : le composite et les widgets...
    Pour pouvoir aller plus loin en ce qui concerne le rendu des éléments visuels, effectivement
    A méditer: La solution la plus simple est toujours la moins compliquée
    Ce qui se conçoit bien s'énonce clairement, et les mots pour le dire vous viennent aisément. Nicolas Boileau
    Compiler Gcc sous windows avec MinGW
    Coder efficacement en C++ : dans les bacs le 17 février 2014
    mon tout nouveau blog

  19. #19
    Membre éclairé Avatar de metagoto
    Profil pro
    Hobbyist programmateur
    Inscrit en
    Juin 2009
    Messages
    646
    Détails du profil
    Informations personnelles :
    Localisation : France

    Informations professionnelles :
    Activité : Hobbyist programmateur

    Informations forums :
    Inscription : Juin 2009
    Messages : 646
    Points : 845
    Points
    845
    Par défaut
    Citation Envoyé par fcharton Voir le message
    Bon, deux choses me paraissent importantes à ce stade :

    1- il faut qu'on commence à regarder les primitives des OS, c'est notre reality check
    2- il faut qu'on pose la question du modèle général : le composite et les widgets...
    Oui, notamment le système de messages loop de l'OS, parce que à mon sens, tout se construit autour. Certains patrons de conception (ça veut dire design patterns?) seront fortement contraints par ce facteur inhérent.

  20. #20
    Expert éminent sénior
    Avatar de koala01
    Homme Profil pro
    aucun
    Inscrit en
    Octobre 2004
    Messages
    11 612
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Âge : 52
    Localisation : Belgique

    Informations professionnelles :
    Activité : aucun

    Informations forums :
    Inscription : Octobre 2004
    Messages : 11 612
    Points : 30 611
    Points
    30 611
    Par défaut
    Citation Envoyé par metagoto Voir le message
    Oui, notamment le système de messages loop de l'OS, parce que à mon sens, tout se construit autour. Certains patrons de conception (ça veut dire design patterns?) seront fortement contraints par ce facteur inhérent.
    Les patrons de conception sont effectivement les "design patterns" (entre autres)...

    Mais l'idée est:
    1. de fournir une façade commune au différents OS
    2. de partir de cette façade commune pour faire tout le reste

    On peut donc à l'extrême limite faire tout le reste en se disant que la façade s'occupe de centraliser et d'adapter le tout pour l'envoyer à l'OS.

    De plus, il faut malgré tout essayer de voir ce dont "tout le reste" aura besoin au niveau de la façade, ne serait-ce que pour éviter de se "casser la tête" à fournir au travers de la façades des fonctionnalités qui... ne nous intéressent nullement.

    L'idéal reste donc de travailler de manière plus ou moins itérative: on part de la fonctionnalité que l'on veut proposer dans la bibliothèque, sur base de ce que la façade fournit déjà et, si nous avons besoin de quelque chose que la façade ne fournit pas, nous voyons comment il est possible de l'y rajouter.

    Plus nous aurons une idée claire de ce qu'implique "tout le reste", plus nous aurons la possibilité de fournir une façade de base utile et un temps soit peu complète (et cohérente), et, dans l'autre sens, plus la façade sera complète et cohérente, moins nous devrons y revenir pour y rajouter "quelque chose qui manque" éventuellement.

    Ce que j'essaye de mettre en évidence, c'est que, effectivement, les primitives OS et la façade qui fait le raccord sont d'une importance capitale, mais que, d'un autre coté, il n'est pas forcément sain ni intéressant d'attendre d'avoir cette façade avant de faire "tout le reste", parce que beaucoup de chose peuvent être faites indépendamment de la façade et que d'autres influeront sur la manière dont la façade sera envisagée.

    Enfin, n'oublions quand même pas que nous avons décidé de nous reposer sur boost pour une série de choses, et que l'on peut malgré tout lui faire confiance pour, justement, avoir pris le coté "bas niveau" relatif à ces choses en compte (par exemple, en ce qui concerne les threads)
    A méditer: La solution la plus simple est toujours la moins compliquée
    Ce qui se conçoit bien s'énonce clairement, et les mots pour le dire vous viennent aisément. Nicolas Boileau
    Compiler Gcc sous windows avec MinGW
    Coder efficacement en C++ : dans les bacs le 17 février 2014
    mon tout nouveau blog

Discussions similaires

  1. Intel TBB et conception par politiques
    Par arthurG dans le forum Threads & Processus
    Réponses: 3
    Dernier message: 12/10/2011, 21h16
  2. [ODBC] requête :comment on traite les noms des attributs comportant d'espace
    Par razily dans le forum PHP & Base de données
    Réponses: 1
    Dernier message: 14/05/2010, 20h58
  3. [Conception] Traits, RTTI & méta-classes
    Par mchk0123 dans le forum C++
    Réponses: 5
    Dernier message: 03/05/2007, 01h11
  4. [Concept] Réplication
    Par melinda dans le forum Décisions SGBD
    Réponses: 4
    Dernier message: 31/03/2003, 18h29
  5. [Concept] Stabilité d'une base de donnée
    Par lassmust dans le forum Décisions SGBD
    Réponses: 3
    Dernier message: 03/07/2002, 17h16

Partager

Partager
  • Envoyer la discussion sur Viadeo
  • Envoyer la discussion sur Twitter
  • Envoyer la discussion sur Google
  • Envoyer la discussion sur Facebook
  • Envoyer la discussion sur Digg
  • Envoyer la discussion sur Delicious
  • Envoyer la discussion sur MySpace
  • Envoyer la discussion sur Yahoo