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

Langage Delphi Discussion :

Graphisme : problème de mode de combinaisons de couleurs


Sujet :

Langage Delphi

  1. #41
    Modérateur

    Homme Profil pro
    Ingénieur retraité
    Inscrit en
    Octobre 2005
    Messages
    2 396
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Localisation : France, Rhône (Rhône Alpes)

    Informations professionnelles :
    Activité : Ingénieur retraité

    Informations forums :
    Inscription : Octobre 2005
    Messages : 2 396
    Points : 3 263
    Points
    3 263
    Par défaut
    Re-bonjour,

    Voici le projet en pièce jointe.

    A mon avis seule une partie du problème provient du fait de l'utilisation du canal Alpha le reste du problème provient probablement du fait que pour tracer une droite dépaisseur supérieure à 1 pixel la procedure DrawLine transmet à la procedure DrawSegmentBis des paramètres de droites, certes parallèles, mais qui se chevauchent partiellement dans certaines zones du fait de l'utilisation de la trigonométrie dans DrawLine dont les résultats nécessitent d'être arrondis et comme on ne trace pas des droites mais des séries de pixels disposés en escalier il y a de forte chances que les pixels de certains nez de marche d'une première parallèle soient recouverts en mode NotXor par des nez de marche de la parralèle suivante et dans ce cas avec l'utilisation du canal Alpha on reste en mode tmAffiche ... alors qu'avec l'astuce des couleurs décalées ce problème se trouve en quelque sorte "maquillé".

    A+.
    Fichiers attachés Fichiers attachés
    N'oubliez pas de consulter les FAQ Delphi et les cours et tutoriels Delphi

  2. #42
    Expert éminent sénior
    Avatar de Paul TOTH
    Homme Profil pro
    Freelance
    Inscrit en
    Novembre 2002
    Messages
    8 964
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Âge : 54
    Localisation : France, Paris (Île de France)

    Informations professionnelles :
    Activité : Freelance
    Secteur : High Tech - Éditeur de logiciels

    Informations forums :
    Inscription : Novembre 2002
    Messages : 8 964
    Points : 28 445
    Points
    28 445
    Par défaut
    ah ben ça EVIDEMMENT si tu utilises un code 32bits sur un bitmap en pf24bit, ça va pas très bien fonctionner ^^

    donc en ligne 369 tu remplaces pf24bit par pf32bit et ça fonctionne
    Developpez.com: Mes articles, forum FlashPascal
    Entreprise: Execute SARL
    Le Store Excute Store

  3. #43
    Modérateur

    Homme Profil pro
    Ingénieur retraité
    Inscrit en
    Octobre 2005
    Messages
    2 396
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Localisation : France, Rhône (Rhône Alpes)

    Informations professionnelles :
    Activité : Ingénieur retraité

    Informations forums :
    Inscription : Octobre 2005
    Messages : 2 396
    Points : 3 263
    Points
    3 263
    Par défaut
    Re-bonjour,

    Paul TOTH ah ben ça EVIDEMMENT si tu utilises un code 32bits sur un bitmap en pf24bit, ça va pas très bien fonctionner
    .
    ... Oups, que je suis bête !
    ... Mais avec ta retification l'effacement est enfin complet.
    ... Il ne me reste maintenant plus qu'à trouver une astuce permettant de supprimer les points blancs parsemés parmi les points colorés en mode Display afin d'obtenir un tracé bien net.

    En tous cas merci pour cette rectification.

    A+.
    N'oubliez pas de consulter les FAQ Delphi et les cours et tutoriels Delphi

  4. #44
    Modérateur

    Homme Profil pro
    Ingénieur retraité
    Inscrit en
    Octobre 2005
    Messages
    2 396
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Localisation : France, Rhône (Rhône Alpes)

    Informations professionnelles :
    Activité : Ingénieur retraité

    Informations forums :
    Inscription : Octobre 2005
    Messages : 2 396
    Points : 3 263
    Points
    3 263
    Par défaut
    Bonjour,

    J'ai pu améliorer un peu le problème des points blancs parsemés parmi les points colorés en mode NotXor lors du Display : il en reste encore mais au moins ils sont répartis de façon très régulière donc c'est plus net, par contre en mode tmCopy (utilisé en phase terminale) le rendu est impeccable par la même occasion j'ai gagné 187 lignes de code : voici le code de DrawLineBis (128 lignes) qui remplace le tandem DrawLine + DrawSegmentBis (315 lignes en tout). On gagne grosso modo toutes les lignes de l'algo de Bresenham.

    Code : 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
    98
    99
    100
    101
    102
    103
    104
    105
    106
    107
    108
    109
    110
    111
    112
    113
    114
    115
    116
    117
    118
    119
    120
    121
    122
    123
    124
    125
    126
    127
    128
    129
    procedure DrawLineBis( BMP : TBitMap; xo,yo,xe,ye, epTrait : integer; CoulPen : TColor; TraceMode : tTraceMode);
    type      PCardinal = ^Cardinal;
    var       Theta,miEp,si,co,mis,mic,sinco,cosco,
              ep,x,y,dx,dy,xo1,yo1,xe1,ye1,xo2,yo2,xe2,ye2,a,b,xorMin,xerMax,yorMin,yerMax,rr,d,u : Extended;
              iy,ix,iyp,ixp,yoMin,yeMax,xoMin,xeMax,r,i,j,xoc,xec,yoc,yec : integer;
              // Le BitMap :
              W,H     : integer;
              Scan0   : Integer;       //Valeur du pointeur d'entrée dans le Bitmap.
              Scan    : Integer;       //Pointeur temporaire destiné à être incrémenté.
              MLS     : Integer;       //Memory Line Size (en bytes) du Bitmap.
              Bpp     : Integer;       //Byte per pixel du Bitmap.
              PixMin,PixMax : Integer; //Bornes de l'intervalle d'appartenance du pointeur au BitMap
              pCoulPen: TRGBQuad;      //Pointe sur la couleur du crayon
     
              procedure GSPixel;
              begin     Scan := Scan0;
                        Inc(Scan, iy*MLS + ix*Bpp);
                        if not ((Scan>=PixMin) and (Scan<=PixMax)) then EXIT; // Si on se trouve en-dehors du BMP
                        case TraceMode of
                             tmAffiche : if PRGBQuad(scan)^.rgbReserved = 0 then
                                            PCardinal(scan)^ := not (PCardinal(scan)^ XOR coulPen);
                             tmEfface  : if PRGBQuad(scan)^.rgbReserved = $FF then
                                         PCardinal(scan)^ := not (PCardinal(scan)^ XOR coulPen);
                             else PRGBQuad(Scan)^:=pCoulPen; //<- pmCopy (utilisé uniquement lors d'un appel pour un tracé de finition)
                        end;
              end; // GSPixel
     
    begin     // INITIALISATION DES VARIABLES :
              BMP.PixelFormat:=pf32bit; Bpp:=4; //<- vu que le code est du 32 bit pour le canal Alpha (si pf24bit alors Bpp:=3)
              with pCoulPen do begin
                   pCoulPen.rgbBlue :=GetBValue(CoulPen);
                   pCoulPen.rgbGreen:=GetGValue(CoulPen);
                   pCoulPen.rgbRed  :=GetRValue(CoulPen);
              end;
     
              Scan0 := Integer(BMP.ScanLine[0]);
              MLS   := Integer(BMP.ScanLine[1]) - Scan0; //Memory Line Size
              W     := BMP.Width ;
              H     := BMP.Height;
              Bpp   := Abs(MLS div W);
              if Integer(BMP.ScanLine[H-1]) < Scan0 then begin  //Si c'est un  Bottom-Up DIB...
    	     PixMin := Integer(BMP.ScanLine[H-1]);
      	     PixMax := Scan0 + Bpp*W - Bpp;
              end else begin //sinon c'est un Top-Down DIB...
      	      PixMin := Scan0;
                  PixMax :=Integer(BMP.ScanLine[H-1]) + Bpp*W - Bpp;
              end;
     
              dx:=xe-xo; dy:=ye-yo;
              miep:=epTrait/2; rr:=miEp; ep:=0;
              if dx=0 then // Verticale
              begin xo1:=xo - miep; xo2:=xo + miep; yo1:=min(yo,ye); ye1:=max(yo,ye);
                    for ix:=trunc(xo1) to trunc(xo2) do begin
                        // Embouts arrondis :
                        d:=abs(rr-ep); if rr>d then u:=sqrt(sqr(rr)-sqr(d)) else u:=0;
                        yoMin:=trunc(yo1-u); yeMax:=trunc(ye1+u);
                        // Tracé du segment incluant les prolongements pour embouts arrondis :
                        for iy:=yoMin to yeMax do GSPixel; // EXIT DrawSegmentBis
                        ep:=ep+1;
                    end;
                    EXIT;
              end;
              if ye=yo then // Horizontale
              begin yo1:=yo - miep; yo2:=yo + miep; xo1:=min(xo,xe); xe1:=max(xo,xe);
                    for iy:=trunc(yo1) to trunc(yo2) do begin
                        // Embouts arrondis :
                        d:=abs(rr-ep); if rr>d then u:=sqrt(sqr(rr)-sqr(d)) else u:=0;
                        xoMin:=trunc(xo1-u); xeMax:=trunc(xe1+u);
                        // Tracé du segment incluant les prolongements pour embouts arrondis :
                        for ix:=xoMin to xeMax do GSPixel; // EXIT DrawSegmentBis
                        ep:=ep+1;
                    end;
                    EXIT;
              end;
              // Droites inclinées
              Theta:=arcTan2(ye-yo,xe-xo);      a:=tan(Theta);
              si:=sin(Theta);   co:=cos(Theta); mis:=miep*si;  mic:=miep*co;
              xo1:=xo + mis;    yo1:=yo - mic;  xo2:=xo - mis; yo2:=yo + mic;
              xe1:=xe + mis;    ye1:=ye - mic;  xe2:=xe - mis; ye2:=ye + mic;
              sinco:=sin(Pi/2-theta);           cosco:=cos(Pi/2-theta);
              dy:=abs(ye-yo); dx:=abs(xe-xo);
              if dy>=dx then // "y = a.x + b" --> x:= (y - b)/a
              begin yorMin:=min(yo1,ye1); yerMax:=max(yo1,ye1);
                    b:=ye1 - a*xe1; ep:=0; si:=abs(si);
                    repeat // Embouts arrondis :
                           d:=abs(rr-ep); if rr>d then u:=si*sqrt(sqr(rr)-sqr(d)) else u:=0;
                           xoc:=trunc((yorMin-u-b)/a);
                           xec:=trunc((yerMax+u-b)/a);
                           // Tracé du segment incluant les prolongements pour embouts arrondis :
                           yoMin:=round(yorMin-u); xoMin:=round((yoMin - b)/a);
                           for iy:=round(yorMin-u) to round(yerMax+u) do
                           begin x:= (iy - b)/a; ix:=round(x); GSPixel; end; // EXIT DrawSegmentBis
                           if TraceMode<>tmCopy then begin
                               ep:=ep+1;
                               b:=b+1/sinco;
                               yorMin:=yorMin+sinco;
                               yerMax:=yerMax+sinco;
                           end else begin // si tmCopy alors passe de finition resserrée
                               ep:=ep+0.5;
                               b:=b+0.5/sinco;
                               yorMin:=yorMin+0.5*sinco;
                               yerMax:=yerMax+0.5*sinco;
                           end;
                    until (ep>=epTrait);
                    EXIT;
              end else // dy < dx -> y = a.x + b
              begin b:=yo1 - a*xo1; ep:=0; co:=abs(co);
                    xo2:=min(xo1,xe1); xe2:=max(xo1,xe1); xorMin:=xo2; xerMax:=xe2;
                    repeat // Embouts arrondis :
                           d:=abs(rr-ep); if rr>d then u:=co*sqrt(sqr(rr)-sqr(d)) else u:=0;
                           // Tracé du segment incluant les prolongements pour embouts arrondis :
                           yoc:=trunc(a*(xorMin-u) + b);
                           yec:=trunc(a*(xerMax+u) + b);
                           for ix:=round(xorMin-u) to round(xerMax+u) do // EXIT DrawSegmentBis
                           begin y:= a*ix + b; iy:=round(y); GSPixel; end;
                           if TraceMode<>tmCopy then begin
                               ep:=ep+1;
                               b:=b+1/sinco;
                               xorMin:=xorMin-cosco;
                               xerMax:=xerMax-cosco;
                           end else begin // si tmCopy alors passe de finition resserrée
                               ep:=ep+0.5;
                               b:=b+0.5/sinco;
                               xorMin:=xorMin-0.5*cosco;
                               xerMax:=xerMax-0.5*cosco;
                           end;
                    until (ep>=epTrait);
              end;
    end; // DrawLineBis
    A+.
    N'oubliez pas de consulter les FAQ Delphi et les cours et tutoriels Delphi

  5. #45
    Expert éminent sénior
    Avatar de Paul TOTH
    Homme Profil pro
    Freelance
    Inscrit en
    Novembre 2002
    Messages
    8 964
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Âge : 54
    Localisation : France, Paris (Île de France)

    Informations professionnelles :
    Activité : Freelance
    Secteur : High Tech - Éditeur de logiciels

    Informations forums :
    Inscription : Novembre 2002
    Messages : 8 964
    Points : 28 445
    Points
    28 445
    Par défaut
    en #23 je t'ai donné une simplification de Bresenham

    au lieu de tester dx > 0, dy > 0, etc... tu détermines ix et iy qui valent +1 ou -1 selon le signe de dx et dy. Ensuite tu utilises Inc(x, ix) et Inc(y, iy) qui incrémenteront ou décrémenteront selon le cas. Tu n'as alors plus qu'un seul if sur dx > dy ou dx < dy.
    Developpez.com: Mes articles, forum FlashPascal
    Entreprise: Execute SARL
    Le Store Excute Store

  6. #46
    Modérateur

    Homme Profil pro
    Ingénieur retraité
    Inscrit en
    Octobre 2005
    Messages
    2 396
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Localisation : France, Rhône (Rhône Alpes)

    Informations professionnelles :
    Activité : Ingénieur retraité

    Informations forums :
    Inscription : Octobre 2005
    Messages : 2 396
    Points : 3 263
    Points
    3 263
    Par défaut
    Re-bonjour,

    Paul TOTH en #23 je t'ai donné une simplification de Bresenham
    ... Oui mais, en #29 j'avais répondu :
    ... je n'ai pas réussi à raccorder la simplification à la suite du code où je me perds dans le labyrinthe.
    De plus comme cette simplification ne va pas modifier le fonctionnement de l'algo qui produit des "points blancs" parsemés et désordonnés en mode NotXor je préfere conserver le code de 12h31 qui est également une simplification où je gagne 187 lignes pour un résultat légèrement meilleur avec une seule procedure au lieu des deux précédentes.

    A+.
    N'oubliez pas de consulter les FAQ Delphi et les cours et tutoriels Delphi

  7. #47
    Membre confirmé
    Homme Profil pro
    Santé
    Inscrit en
    Septembre 2010
    Messages
    290
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Localisation : France, Nord (Nord Pas de Calais)

    Informations professionnelles :
    Activité : Santé
    Secteur : Santé

    Informations forums :
    Inscription : Septembre 2010
    Messages : 290
    Points : 534
    Points
    534
    Par défaut
    Je voudrais juste préciser, pour ceux qui s'inspireraient des codes présentés dans ce topic, que l'algo de Bresenham donné en #13 est optimisé pour la rapidité d'exécution.
    La simplification du code proposée en #23, très spectaculaire, dégrade malheureusement légèrement les performances (environ 10%).

    Il fallait le préciser, je pense, pour ne pas provoquer de fausses idées. Car, comme toujours, nous nous trouvons devant l'éternel dilemme lorsqu'on recherche les performances où il faut énormément sacrifier la lisibilité du code à quelques millisecondes laborieusement grappillées.

  8. #48
    Expert éminent sénior
    Avatar de Paul TOTH
    Homme Profil pro
    Freelance
    Inscrit en
    Novembre 2002
    Messages
    8 964
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Âge : 54
    Localisation : France, Paris (Île de France)

    Informations professionnelles :
    Activité : Freelance
    Secteur : High Tech - Éditeur de logiciels

    Informations forums :
    Inscription : Novembre 2002
    Messages : 8 964
    Points : 28 445
    Points
    28 445
    Par défaut
    en fait, pour dessiner un trait avec une épaisseur, il vaudrait mieux passer par un algorithme de remplissage de polygone

    car tu pourrais difficilement avoir des lignes qui ne laissent pas de trou entre elles.
    Developpez.com: Mes articles, forum FlashPascal
    Entreprise: Execute SARL
    Le Store Excute Store

  9. #49
    Modérateur

    Homme Profil pro
    Ingénieur retraité
    Inscrit en
    Octobre 2005
    Messages
    2 396
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Localisation : France, Rhône (Rhône Alpes)

    Informations professionnelles :
    Activité : Ingénieur retraité

    Informations forums :
    Inscription : Octobre 2005
    Messages : 2 396
    Points : 3 263
    Points
    3 263
    Par défaut
    Bonjour,

    Caribensila : Je voudrais juste préciser, pour ceux qui s'inspireraient des codes présentés dans ce topic, que l'algo de Bresenham donné en #13 est optimisé pour la rapidité d'exécution.
    La simplification du code proposée en #23, très spectaculaire, dégrade malheureusement légèrement les performances (environ 10%).
    ... OK, mais je ne me plains pas de la vitesse d'exécution je recherchais tout simplement la possibilité d'obtenir des traits nets et sans "trous".

    Il fallait le préciser, je pense, pour ne pas provoquer de fausses idées. Car, comme toujours, nous nous trouvons devant l'éternel dilemme lorsqu'on recherche les performances où il faut énormément sacrifier la lisibilité du code à quelques millisecondes laborieusement grappillées.
    ... Absolument d'accord.

    Paul TOTH : en fait, pour dessiner un trait avec une épaisseur, il vaudrait mieux passer par un algorithme de remplissage de polygone
    ... Oui, c'est peut être une piste à creuser, d'ailleurs j'avais un jour cherché à touver l'algo qui réalise le FloodFill mais sans succès mais je vais voir si je trouve qq chose pour le remplissage de polygone.

    A+.
    N'oubliez pas de consulter les FAQ Delphi et les cours et tutoriels Delphi

  10. #50
    Membre confirmé
    Homme Profil pro
    Santé
    Inscrit en
    Septembre 2010
    Messages
    290
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Localisation : France, Nord (Nord Pas de Calais)

    Informations professionnelles :
    Activité : Santé
    Secteur : Santé

    Informations forums :
    Inscription : Septembre 2010
    Messages : 290
    Points : 534
    Points
    534
    Par défaut
    OK, mais je ne me plains pas de la vitesse d'exécution je recherchais tout simplement la possibilité d'obtenir des traits nets et sans "trous".
    Je sais, mais c'étais juste pour faire remarquer que je ne fourguais pas des trucs pourris.

    j'avais un jour cherché à touver l'algo qui réalise le FloodFill mais sans succès
    J'ai une procedure FloodFill en chantier qui fonctionne, mais elle n'est pas assez optimisée à mon goût et ne prend pas encore les bords du Bitmap comme frontières. Cependant, si ça t'intéresse comme point de départ, je te l'envoie en MP (mais ne tarde pas car je pars en déplacement demain PM).

  11. #51
    Expert éminent sénior
    Avatar de Paul TOTH
    Homme Profil pro
    Freelance
    Inscrit en
    Novembre 2002
    Messages
    8 964
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Âge : 54
    Localisation : France, Paris (Île de France)

    Informations professionnelles :
    Activité : Freelance
    Secteur : High Tech - Éditeur de logiciels

    Informations forums :
    Inscription : Novembre 2002
    Messages : 8 964
    Points : 28 445
    Points
    28 445
    Par défaut
    non le floodfill c'est pas terrible

    tes lignes étant des polygones convexes ce n'est pas très compliqué à faire. il suffit d'appliquer Bresenham (au pif) pour parcourir le contour de ta forme et de stocker pour chaque ligne (y) les positions min/max de X, ensuite il suffit de dessiner des lignes horizontales de ymin à ymax avec les xmin, xmax de la ligne en question.

    prenons un exemple trivial, le triangle, on peut facilement calculer ymin et ymax, maintenant on a besoin d'un tableau
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
     
     var lignes: Array[ymin..ymax] of record xmin, xmax: Integer end;
    bon évidemment on aura plutôt

    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
     
     var lignes: Array[0..(ymax-ymin) + 1] of record xmin, xmax: Integer end;
    et ce sera dynamique...mais qu'importe

    ensuite on calcul les points de la ligne (x1, y1) - (x2, y2) et pour chaque point x,y on renseigne lignes[y].xmin et xmax en fonction de x; on n'a donc pas de tracé à ce moment là, on sauvegarde simplement la position des points

    idem pour p2 vers p3 et p3 vers p1 (les points)

    reste plus qu'à dessiner
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
    6
     
    for y := ymin to ymax do
    begin
      moveto(y, line[y].xmin);
      lineto(y, line[y].xmax);
    end;
    et voila un rendu impeccablement
    Developpez.com: Mes articles, forum FlashPascal
    Entreprise: Execute SARL
    Le Store Excute Store

  12. #52
    Membre confirmé
    Homme Profil pro
    Santé
    Inscrit en
    Septembre 2010
    Messages
    290
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Localisation : France, Nord (Nord Pas de Calais)

    Informations professionnelles :
    Activité : Santé
    Secteur : Santé

    Informations forums :
    Inscription : Septembre 2010
    Messages : 290
    Points : 534
    Points
    534
    Par défaut
    Ah ouais !

    Et on peut même remplir avec un dégradé...

  13. #53
    Modérateur

    Homme Profil pro
    Ingénieur retraité
    Inscrit en
    Octobre 2005
    Messages
    2 396
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Localisation : France, Rhône (Rhône Alpes)

    Informations professionnelles :
    Activité : Ingénieur retraité

    Informations forums :
    Inscription : Octobre 2005
    Messages : 2 396
    Points : 3 263
    Points
    3 263
    Par défaut
    Bonjour,

    Caribensila : J'ai une procedure FloodFill en chantier qui fonctionne, mais elle n'est pas assez optimisée à mon goût et ne prend pas encore les bords du Bitmap comme frontières. Cependant, si ça t'intéresse comme point de départ, je te l'envoie en MP (mais ne tarde pas car je pars en déplacement demain PM).
    ... OK, cela m'intéresse pour la suite. Par contre je ne pense pas l'utiliser pour le tracé d'une droite épaisse car me recherches sur les remplissages de polygone m'ont donné une autre idée (voir plus bas).

    Paul TOTH : tes lignes étant des polygones convexes ce n'est pas très compliqué à faire. il suffit d'appliquer Bresenham (au pif) pour parcourir le contour de ta forme et de stocker pour chaque ligne (y) les positions min/max de X, ensuite il suffit de dessiner des lignes horizontales de ymin à ymax avec les xmin, xmax de la ligne en question.

    prenons un exemple trivial, le triangle, on peut facilement calculer ymin et ymax, maintenant on a besoin d'un tableau.
    ... En fait comme mes lignes sont des rectangles on connaît l'équation de leur axe donc on connaît les équations des droites de leur périmètre ce qui va me donner les xmin et xmax des segments horizontaux à tracer.
    ... Mais l'utilisation du tableau var lignes: Array[ymin..ymax] of record xmin, xmax: Integer end; va certainement simplifier le code.
    ... Je ferai cela à partir de lundi.

    Bon week-end et à +.
    N'oubliez pas de consulter les FAQ Delphi et les cours et tutoriels Delphi

  14. #54
    Modérateur

    Homme Profil pro
    Ingénieur retraité
    Inscrit en
    Octobre 2005
    Messages
    2 396
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Localisation : France, Rhône (Rhône Alpes)

    Informations professionnelles :
    Activité : Ingénieur retraité

    Informations forums :
    Inscription : Octobre 2005
    Messages : 2 396
    Points : 3 263
    Points
    3 263
    Par défaut
    Bonjour,

    Voici le nouveau code qui utilise l'idée de Paul TOTh :

    Code : 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
    98
    99
    100
    101
    102
    103
    104
    105
    106
    107
    108
    109
    110
    111
    112
    113
    114
    115
    116
    117
    118
    119
    120
    121
    122
    123
    124
    125
    126
    127
    128
    129
    130
    131
    132
    133
    134
    135
    136
    137
    138
    139
    140
    141
    142
    143
    144
    145
    146
    147
    148
    149
    150
    151
    152
    153
    154
    155
    156
    157
    158
    159
    160
    161
    162
    163
    164
    165
    166
    167
    168
    169
    170
    171
    172
    173
    174
    175
    176
    177
    178
    179
    180
    181
    182
    183
    184
    185
    186
    187
    188
    189
    190
    191
    192
    193
    194
    195
    196
    197
    198
    199
    200
    201
    202
    203
    204
    205
    206
    207
    208
    209
    210
    211
    212
    213
    214
    procedure DrawLineTer( BMP : TBitMap; xo,yo,xe,ye, epTrait : integer; CoulPen : TColor; TraceMode : tTraceMode; BoutsRonds : boolean);
    type      PCardinal = ^Cardinal;
    var       Theta,miEp,si,co,mis,mic,
              ep,x,y,dx,dy,xo1,yo1,xe1,ye1,xo2,yo2,xe2,ye2,xorMin,xerMax,yorMin,yerMax,rr,d,u : Extended;
              ap,bp,ad,bds,bdi,bdg,bdd : Extended;
              iy,ix,iyp,ixp,yoMin,yeMax,xoMin,xeMax,r,i,j,xoc,xec,yoc,yec : integer;
              // Le BitMap :
              W,H     : integer;
              Scan0   : Integer;       //Valeur du pointeur d'entrée dans le Bitmap.
              Scan    : Integer;       //Pointeur temporaire destiné à être incrémenté.
              MLS     : Integer;       //Memory Line Size (en bytes) du Bitmap.
              Bpp     : Integer;       //Byte per pixel du Bitmap.
              PixMin,PixMax : Integer; //Bornes de l'intervalle d'appartenance du pointeur au BitMap
              pCoulPen: TRGBQuad;      //Pointe sur la couleur du crayon
              ymin1,ymax1,ymin2,ymax2,ymin,ymax : integer;
              lignes    : array of record xmin, xmax: Integer; end; // Le contour
              Q         : byte;        // Les quadrants
     
     
              procedure GSPixel;
              begin     Scan := Scan0;
                        Inc(Scan, iy*MLS + ix*Bpp);
                        if not ((Scan>=PixMin) and (Scan<=PixMax)) then EXIT; // Si on se trouve en-dehors de la mem du BMP
                        if not ((ix>=0) and (iy>=0) and (ix<=W-1) and (iy<=H-1)) then EXIT; // Si la droite dépasse les bords du Bmp
                        case TraceMode of
                             tmAffiche : if PRGBQuad(scan)^.rgbReserved = 0 then
                                            PCardinal(scan)^ := not (PCardinal(scan)^ XOR coulPen);
                             tmEfface  : if PRGBQuad(scan)^.rgbReserved = $FF then
                                         PCardinal(scan)^ := not (PCardinal(scan)^ XOR coulPen);
                             else PRGBQuad(Scan)^:=pCoulPen; //<- pmCopy (utilisé uniquement lors d'un appel pour un tracé de finition)
                        end;
              end; // GSPixel
     
              procedure Rond(xc,yc,R : integer); // Embouts arrondis
              var       x,y : integer; e,u : Extended;
              begin     for y:=yc-R to yc+R do begin
                            e:=y-(yc-R); u:=sqrt(sqr(R)-sqr(R-e)); iy:=y;
                            for x:=xc-floor(u) to xc+floor(u) do begin ix:=x; GSPixel; end;
                        end;
              end;
     
    begin     // INITIALISATION DES VARIABLES :
              BMP.PixelFormat:=pf32bit; Bpp:=4; //<- vu que le code est du 32 bit pour le canal Alpha (si pf24bit alors Bpp:=3)
              with pCoulPen do begin
                   pCoulPen.rgbBlue :=GetBValue(CoulPen);
                   pCoulPen.rgbGreen:=GetGValue(CoulPen);
                   pCoulPen.rgbRed  :=GetRValue(CoulPen);
              end;
     
              Scan0 := Integer(BMP.ScanLine[0]);
              MLS   := Integer(BMP.ScanLine[1]) - Scan0; //Memory Line Size
              W     := BMP.Width ;
              H     := BMP.Height;
              Bpp   := Abs(MLS div W);
              if Integer(BMP.ScanLine[H-1]) < Scan0 then begin  //Si c'est un  Bottom-Up DIB...
    	     PixMin := Integer(BMP.ScanLine[H-1]);
      	     PixMax := Scan0 + Bpp*W - Bpp;
              end else begin //sinon c'est un Top-Down DIB...
      	      PixMin := Scan0;
                  PixMax :=Integer(BMP.ScanLine[H-1]) + Bpp*W - Bpp;
              end;
     
              dx:=xe-xo; dy:=ye-yo;
              miep:=epTrait/2; rr:=miEp; ep:=0;
              if dx=0 then // Verticale
              begin xo1:=xo - miep; xo2:=xo + miep; yo1:=min(yo,ye); ye1:=max(yo,ye);
                    for ix:=trunc(xo1) to trunc(xo2) do begin
                        // Embouts arrondis :
                        if BoutsRonds then begin
                           d:=abs(rr-ep); if rr>d then u:=sqrt(sqr(rr)-sqr(d)) else u:=0;
                        end else u:=0;
                        yoMin:=trunc(yo1-u); yeMax:=trunc(ye1+u);
                        // Tracé du segment incluant les prolongements pour embouts arrondis :
                        for iy:=yoMin to yeMax do GSPixel;
                        ep:=ep+1;
                    end;
                    EXIT;
              end;
              if ye=yo then // Horizontale
              begin yo1:=yo - miep; yo2:=yo + miep; xo1:=min(xo,xe); xe1:=max(xo,xe);
                    for iy:=trunc(yo1) to trunc(yo2) do begin
                        // Embouts arrondis :
                        if BoutsRonds then begin
                           d:=abs(rr-ep); if rr>d then u:=sqrt(sqr(rr)-sqr(d)) else u:=0;
                        end else u:=0;
                        xoMin:=trunc(xo1-u); xeMax:=trunc(xe1+u);
                        // Tracé du segment incluant les prolongements pour embouts arrondis :
                        for ix:=xoMin to xeMax do GSPixel;
                        ep:=ep+1;
                    end;
                    EXIT;
              end;
              // Droites inclinées
     try
              Theta:=arcTan2(ye-yo,xe-xo);      ad:=tan(Theta); // Pente de l'axe de la droite
              si:=sin(Theta);   co:=cos(Theta); mis:=miep*si;  mic:=miep*co;
              xo1:=xo + mis;    yo1:=yo - mic;  xo2:=xo - mis; yo2:=yo + mic;
              xe1:=xe + mis;    ye1:=ye - mic;  xe2:=xe - mis; ye2:=ye + mic;
              dy:=abs(ye-yo);   dx:=abs(xe-xo);
              Q:=0;
              if (xe>xo) and (ye<yo) then Q:=1 else // Quadrants
              if (xe<xo) and (ye<yo) then Q:=2 else
              if (xe<xo) and (ye>yo) then Q:=3 else
              if (xe>xo) and (ye>yo) then Q:=4;
              bds:=yo1 - ad*xo1;   // Ordonnée à l'origine du bord supérieur
              bdi:=yo2 - ad*xo2;   // Ordonnée à l'origine du bord inférieur
              ap:=-1/ad;           // Pente des petits côtés perpendiculaires
              bdg:=-ap*xo1 + yo1;  // Ordonnée à l'origine du bord gauche
              bdd:=-ap*xe1 + ye1;  // Ordonnée à l'origine du bord droit
              ymin1:=min(round(ye1),round(yo2)); ymax1:=max(round(ye1),round(yo2));
              ymin2:=min(round(ye2),round(yo1)); ymax2:=max(round(ye2),round(yo1));
              ymin :=min(ymin1,ymin2);           ymax :=max(ymax1,ymax2);
              SetLength(lignes,ymax-ymin+2); // +2 sinon VA
              for iy:=Low(lignes) to High(lignes) do begin
                  lignes[iy].xmin:=0; lignes[iy].xmax:=0;
              end;
              if BoutsRonds then begin // Embouts arrondis
                 Rond(xo,yo,round(miep)); Rond(xe,ye,round(miep));
              end;
              if dy>=dx then // Droites très inclinées par rapport à l'horizontale
              begin // Les xmin et xmax :
                    yoMin:=round(min(yo1,ye1)); yeMax:=round(max(yo1,ye1));
                    for iy:=yoMin to yeMax do // x:= (y - b)/a
                    begin x:= (iy - bds)/ad; ix:=round(x);
                          case Q of
                               1,2 : lignes[iy-ymin].xmin:=ix;
                               3,4 : lignes[iy-ymin].xmax:=ix;
                          end
                    end;
                    xoMin:=round(min(xo1,xo2)); xeMax:=round(max(xo1,xo2));
                    for ix:=xoMin to xeMax do // y = a.x + b
                    begin y:=ap*ix + bdg; iy:=round(y);
                          case Q of
                               1,4 : lignes[iy-ymin].xmin:=ix;
                               2,3 : lignes[iy-ymin].xmax:=ix;
                          end;
                    end;
                    yoMin:=round(min(yo2,ye2)); yeMax:=round(max(yo2,ye2));
                    for iy:=yoMin to yeMax do // x:= (y - b)/a
                    begin x:= (iy - bdi)/ad; ix:=round(x);
                          case Q of
                               1,2 : lignes[iy-ymin].xmax:=ix;
                               3,4 : lignes[iy-ymin].xmin:=ix;
                          end;
                    end;
                    xoMin:=round(min(xe1,xe2)); xeMax:=round(max(xe1,xe2));
                    for ix:=xoMin to xeMax do // y = a.x + b
                    begin y:= ap*ix + bdd; iy:=round(y);
                          case Q of
                               1,4 : lignes[iy-ymin].xmax:=ix;
                               2,3 : lignes[iy-ymin].xmin:=ix;
                          end;
                    end;
                    // Eviter les xmin et xmax restés à 0 :
                    for iy:=1 to High(lignes) do begin
                        if lignes[iy].xmin=0 then lignes[iy].xmin:=lignes[iy-1].xmin;
                        if lignes[iy].xmax=0 then lignes[iy].xmax:=lignes[iy-1].xmax;
                    end;
                    if lignes[0].xmin=0 then lignes[0].xmin:=lignes[1].xmin;
                    if lignes[0].xmax=0 then lignes[0].xmax:=lignes[1].xmax;
                    // Tracé final :
                    for iy := ymin to ymax
                    do  for ix:=lignes[iy-ymin].xmin to lignes[iy-ymin].xmax do GSPixel;
                    SetLength(lignes,1);
                    EXIT;
              end else // Droites inclinées à moins de 45° par rapport à l'horizontale
              begin // Les xmin et xmax :
                    xoMin:=round(min(xo1,xe1)); xeMax:=round(max(xo1,xe1));
                    for ix:=xoMin to xeMax do // y = a.x + b
                    begin y:= ad*ix + bds; iy:=round(y);
                          case Q of
                               1,2 : lignes[iy-ymin].xmin:=ix;
                               3,4 : lignes[iy-ymin].xmax:=ix;
                          end;
                    end;
                    yoMin:=round(min(yo1,yo2)); yeMax:=round(max(yo1,yo2));
                    for iy:=yoMin to yeMax do // x:= (y - b)/a
                    begin x:= (iy - bdg)/ap; ix:=round(x);
                          case Q of
                               1,4 : lignes[iy-ymin].xmin:=ix;
                               2,3 : lignes[iy-ymin].xmax:=ix;
                          end;
                    end;
                    xoMin:=round(min(xo2,xe2)); xeMax:=round(max(xo2,xe2));
                    for ix:=xoMin to xeMax do // y = a.x + b
                    begin y:= ad*ix + bdi; iy:=round(y);
                          case Q of
                               1,2 : lignes[iy-ymin].xmax:=ix;
                               3,4 : lignes[iy-ymin].xmin:=ix;
                          end;
                    end;
                    yoMin:=round(min(ye1,ye2)); yeMax:=round(max(ye1,ye2));
                    for iy:=yoMin to yeMax do // x:= (y - b)/a
                    begin x:= (iy - bdd)/ap; ix:=round(x);
                          case Q of
                               1,4 : lignes[iy-ymin].xmax:=ix;
                               2,3 : lignes[iy-ymin].xmin:=ix;
                          end;
                    end;
                    // Eviter les xmin et xmax restés à 0 :
                    for iy:=1 to High(lignes) do begin
                        if lignes[iy].xmin=0 then lignes[iy].xmin:=lignes[iy-1].xmin;
                        if lignes[iy].xmax=0 then lignes[iy].xmax:=lignes[iy-1].xmax;
                    end;
                    if lignes[0].xmin=0 then lignes[0].xmin:=lignes[1].xmin;
                    if lignes[0].xmax=0 then lignes[0].xmax:=lignes[1].xmax;
                    // Tracé final :
                    for iy := ymin to ymax
                    do for ix:=lignes[iy-ymin].xmin to lignes[iy-ymin].xmax do GSPixel;
                    SetLength(lignes,1);
              end;
      except
      end;
    end; // DrawLineTer
    ... et voir plus bas le résultat
    ... le rendu est "sans trous"
    ... mais il y a deux trucs bizarres :

    1) le dessin de la croix du bas a été commandé par :
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    DrawLineTer(BMP,xc-40,600,xc+40,400, 40, clGreen, TraceMode, False); // montant vers droite
              DrawLineTer(BMP,xc-40,400,xc+40,600, 40, clBlue,  TraceMode, False); // descendant vers la droite
    or le NotXor a bien tracé la droite verte en vert sur fond blanc, mais bizarrement la droite commandée en Bleu a été rendue en Rouge (!!!???) : une bizarrerie du canal Alpha ???

    2) le dessin de la croix du bas a été lancé après celui de la rosace polychrome donc il devrait recouvrir partiellement la rosace, mais bizarrement c'est le cas inverse (!!! ???). : mystère et boule de gomme.

    A+.
    Images attachées Images attachées  
    N'oubliez pas de consulter les FAQ Delphi et les cours et tutoriels Delphi

  15. #55
    Expert éminent sénior
    Avatar de Paul TOTH
    Homme Profil pro
    Freelance
    Inscrit en
    Novembre 2002
    Messages
    8 964
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Âge : 54
    Localisation : France, Paris (Île de France)

    Informations professionnelles :
    Activité : Freelance
    Secteur : High Tech - Éditeur de logiciels

    Informations forums :
    Inscription : Novembre 2002
    Messages : 8 964
    Points : 28 445
    Points
    28 445
    Par défaut
    pour la couleur, il est possible qu'il faille swaper les couleurs pour alimenter directement le bitmap...passer de RGB à BGR...je sais pas

    pour le fait que la croix ne se dessiner pas par dessus, c'est assez logique en fait le canal alpha interdit deux mises à jours d'un même pixel...du coup la croix n'est PAS dessinée en superposition...il faudrait remettre à blanc le canal alpha entre deux appel à DrawLine...mais dans ce cas l'effacement ne fonctionnera plus

    ça devient compliqué tu ne veux pas qu'un pixel sur lequel tu dessines deux fois la même couleur redevienne blanc, mais tu veux qu'il change de couleur si tu dessine avec une autre couleur ... c'est des fois oui, des fois non
    Developpez.com: Mes articles, forum FlashPascal
    Entreprise: Execute SARL
    Le Store Excute Store

  16. #56
    Rédacteur/Modérateur
    Avatar de Andnotor
    Inscrit en
    Septembre 2008
    Messages
    5 694
    Détails du profil
    Informations personnelles :
    Localisation : Autre

    Informations forums :
    Inscription : Septembre 2008
    Messages : 5 694
    Points : 13 130
    Points
    13 130
    Par défaut
    Citation Envoyé par Paul TOTH Voir le message
    ça devient compliqué
    ça ne devient pas compliqué, la donnée n'est pas applicable dès le départ
    On ne peut pas obtenir le résultat voulu sans passer par des bitmaps intermédiaires (Layers).

    Vos algorithmes peuvent certainement accélérer leurs traitements, mais pas les remplacer.

  17. #57
    Modérateur

    Homme Profil pro
    Ingénieur retraité
    Inscrit en
    Octobre 2005
    Messages
    2 396
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Localisation : France, Rhône (Rhône Alpes)

    Informations professionnelles :
    Activité : Ingénieur retraité

    Informations forums :
    Inscription : Octobre 2005
    Messages : 2 396
    Points : 3 263
    Points
    3 263
    Par défaut
    Re-bonjour,

    Paul TOTH : pour la couleur, il est possible qu'il faille swaper les couleurs pour alimenter directement le bitmap...passer de RGB à BGR...je sais pas
    ... tu veux dire permute le rouge avec le bleu ???
    ... bon je peux toujours essayer pour voir.

    pour le fait que la croix ne se dessiner pas par dessus, c'est assez logique en fait le canal alpha interdit deux mises à jours d'un même pixel...du coup la croix n'est PAS dessinée en superposition...il faudrait remettre à blanc le canal alpha entre deux appel à DrawLine...mais dans ce cas l'effacement ne fonctionnera plus
    .
    ... je n'ai posé cette question que pour mieux piger car rien ne m'interdit d'inverser les ordres d'appel de la procedure si je veux faire apparaître la croix par dessus et il vaut mieux conserver l'effacement.

    En tous cas le reste est impeccable avec l'idée du tableau des xmin et xmax.
    Je vais bidouiller pour essayer de trouver une parade à ce pb de changement de couleurs.

    A+.
    N'oubliez pas de consulter les FAQ Delphi et les cours et tutoriels Delphi

  18. #58
    Modérateur

    Homme Profil pro
    Ingénieur retraité
    Inscrit en
    Octobre 2005
    Messages
    2 396
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Localisation : France, Rhône (Rhône Alpes)

    Informations professionnelles :
    Activité : Ingénieur retraité

    Informations forums :
    Inscription : Octobre 2005
    Messages : 2 396
    Points : 3 263
    Points
    3 263
    Par défaut
    Re-bonjour,

    Andnotor : On ne peut pas obtenir le résultat voulu sans passer par des bitmaps intermédiaires (Layers).
    ... je n'en suis pas convaincu pour la bonne et simple raison qu'avec polyline cela marche dans les zones de croisement sans faire appel à des bitmaps intermédiaires.
    ... donc je m'accroche.
    ... pour l'instant je n'utilise de bitmap intermédiaire que pour ajouter une ombre aussi réelle que possible à du texte mais pas pour tracer un simple trait.

    A+.
    N'oubliez pas de consulter les FAQ Delphi et les cours et tutoriels Delphi

  19. #59
    Rédacteur/Modérateur
    Avatar de Andnotor
    Inscrit en
    Septembre 2008
    Messages
    5 694
    Détails du profil
    Informations personnelles :
    Localisation : Autre

    Informations forums :
    Inscription : Septembre 2008
    Messages : 5 694
    Points : 13 130
    Points
    13 130
    Par défaut
    C'est une erreur de croire que Polyline est une simple suite d'appels à LineTo.
    Polyline passe aussi par un buffer intermédiaire et construit la forme complète avant de la rendre en une fois

  20. #60
    Expert éminent sénior
    Avatar de Paul TOTH
    Homme Profil pro
    Freelance
    Inscrit en
    Novembre 2002
    Messages
    8 964
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Âge : 54
    Localisation : France, Paris (Île de France)

    Informations professionnelles :
    Activité : Freelance
    Secteur : High Tech - Éditeur de logiciels

    Informations forums :
    Inscription : Novembre 2002
    Messages : 8 964
    Points : 28 445
    Points
    28 445
    Par défaut
    Citation Envoyé par Andnotor Voir le message
    C'est une erreur de croire que Polyline est une simple suite d'appels à LineTo.
    Polyline passe aussi par un buffer intermédiaire et construit la forme complète avant de la rendre en une fois
    Je ne comprend pas bien ta remarque...l'usage de layer ne change rien à la donne, si tu appliques deux layers de même couleur en XOR, l'effet s'annule, que ce soit un pixel, une ligne ou un layer n'y change rien.
    Developpez.com: Mes articles, forum FlashPascal
    Entreprise: Execute SARL
    Le Store Excute Store

+ Répondre à la discussion
Cette discussion est résolue.
Page 3 sur 4 PremièrePremière 1234 DernièreDernière

Discussions similaires

  1. Réponses: 0
    Dernier message: 03/10/2007, 13h11
  2. form en mode continu et detail couleur
    Par lolothom dans le forum VBA Access
    Réponses: 5
    Dernier message: 20/07/2007, 10h31
  3. Problème "ON_CONTROL_RANGE" mode release
    Par BoyzInDaProject dans le forum MFC
    Réponses: 5
    Dernier message: 11/05/2007, 17h24
  4. Problèmes en mode Debug
    Par pracede2005 dans le forum Eclipse Java
    Réponses: 1
    Dernier message: 03/05/2007, 16h29
  5. problème en mode release
    Par Polux95 dans le forum Qt
    Réponses: 20
    Dernier message: 25/04/2007, 09h58

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