begin process at 2013 05 26 03:51:03
  Trouver un code source :
 
dans
 
Accueil > 

Code

 > 

Graphique

 > REMPLISSAGE D'UNE COURBE DE BÉZIER

REMPLISSAGE D'UNE COURBE DE BÉZIER


 Information sur la source

Note :
10 / 10 - par 2 personnes
10,00 / 10

  • 1

  • 2

  • 3

  • 4

  • 5

  • 6

  • 7

  • 8

  • 9

  • 10
Catégorie :Graphique Classé sous :remplissage, courbe, bézier, patate Niveau :Initié Date de création :18/05/2010 Vu / téléchargé :4 235 / 258

Auteur : barbichette

Ecrire un message privé
Site perso
Commentaire sur cette source (24)
Ajouter un commentaire et/ou une note

 Description

Cliquez pour voir la capture en taille normale
Il existe une API pour tracer un polygone rempli. Mais pas pour les courbes de Bézier.

En voici une, avec les explications (un peu matheuse...)
En gros, une courbe de Bézier, c'est une série de points, et pour chaque point, deux poignées, indiquant comment la courbe doit arrivé et partir.
Je parle bien d'une courbe fermée, sinon, pas de remplissage bien sur...
Le but étant de savoir si se trouve à l'intérieur de la patate ou à l'extérieur...
Car une simple courbe avec 2 points (et 2 poignées), on peut déjà provoquer une jolie boucle, à l'inverse d'un polygone où le trait droit est un élément simple.
Pour cela, je procède en plusieurs étapes :
1 - je découpe la courbe en arc plus simple, et surtout en arc qui ne change jamais de direction.
En gros, la courbe monte ou descend, mais jamais elle monte puis redescend.
Bien sur, elle peut monter en décrivant un arc.
Pourquoi faire ça ?
Parce que je vais ensuite saucissonner ma patate en tranche de 1 pixel de hauteur, mes arcs ne couperont JAMAIS plus d'une seule fois une ligne donnée (à l'inverse d'une boucle qui peut couper une ligne 2 voir 3 ou 4 fois).
En clair, je dérive ma fonction et je regarde quand elle s'annule. (ce qui signifie que la courbe change de direction)
2 - Pour chaque arc, en le tronçonnant, en tranche de 1 pixel, j'obtiens ainsi un simple segment horizontal d'une certaine largeur, mais UN seul, pas plus. Je considère que le milieu de ce segment est à limite en l'intérieur et l'extérieur.
3 - maintenant que je connais la direction de chaque arc, les segments qui le constitue, et ses limites, je peut tracer l'intérieur et les contours

Vous remarquerez que l'on peut, en plus, tracer le contour en connaissant l'ordre exacte des points entre le départ de la courbe et l'arrivée... Ce que j'ai traduit par un dégradé de couleurs.


 Conclusion

il y a surement quelques optimisations à faire car, dans l'état, on recherche plusieurs fois les solutions d'une même équation du 3ième degré (en extended), ce qui n'est pas forcement très performant... Ou encore la recherche des intersections pourrait être mieux faite...

 Fichier Zip

Les Membres Club peuvent télécharger directement un fichier contenu dans le zip sans télécharger le zip en entier !

Télécharger le zip


 Sources du même auteur

Source avec Zip Source avec une capture SEAM CARVING V2
Source avec Zip Source avec une capture SEAM CARVING
Source avec Zip Source avec une capture DÉFORMATION D'UN VISAGE
Source avec Zip COMPTER LES COULEURS D'UNE IMAGE
Source avec Zip Source avec une capture DESKTOP EN SABLE

 Sources de la même categorie

Source avec Zip Source avec une capture SEAM CARVING V2 par barbichette
Source avec Zip Source avec une capture SEAM CARVING par barbichette
Source avec Zip Source avec une capture EFFET MATRIX DANS UN PANEL par soldier8514
Source avec Zip Source avec une capture REDIMENSIONNEMENT XBR AVEC DES FACTEURS D'ÉCHELLE QUELCONQUE... par pseudo3
Source avec Zip Source avec une capture DÉFORMATION D'UN VISAGE par barbichette

 Sources en rapport avec celle ci

Source avec Zip Source avec une capture TRIANGLE DE TROIS COULEURS par barbichette
Source avec Zip Source avec une capture REMPLISSAGE DE POLYGONE par barbichette
Source avec Zip Source avec une capture COMMENT REMPLIR UN POLYGONE SANS UTILISER LE GDI DE WINDOWS par sivaller
Source avec Zip Source avec une capture OUTIL DE CALCUL NUMÉRIQUE (MAJ 2) ( PARSER COMPLEXE + TRACÉ... par JnBiz
Source avec Zip Source avec une capture OSCILLOSCOPE AVEC DELPHI par aymenk

Commentaires et avis

Commentaire de MAURICIO le 19/05/2010 18:03:32 administrateur CS 10/10

Salut Barbichette,

content de voir que tu nous poste encore des sources :)

Pour ceux qui se demandent qu' est-ce que cette histoire de poignets, c' est par ici que ça se passe:
http://www.delphifr.com/codes/MANIPULER-COURBES-BEZIER-SUPER-SIMPLE_22698.aspx

J' ai pas analysé le code mais ça semble organisé, conci, bien pensé et commenté, de ce côté là je te fais confiance.
Le rendu est très rapide mais c' est peut-être dû à mon PC de compet' :)

Au final, encore une très bonne source de notre ami Barbichette et pour ceux qui ne le connaissent pas, faites un tour voir ces autres posts plus interessants les uns que les autres!!!

Maurício

Commentaire de Bacterius le 24/05/2010 12:14:21

Salut Barbichette,
très bonne source, c'est rare en ces temps difficiles :(

Le rendu est joli chez moi, seulement il est un peu long quand l'aire devient trop importante.
Il y a des optimisations simples à faire (et d'autres plus complexes) : par exemple, as-tu besoin d'une précision de plus de 20 chiffres décimaux ? Tu peux alors laisser de côté le Extended (assez gourmand en temps de calcul) et opter pour un Single qui offre une précision décente (bien suffisante pour nos besoins humains) à un coût relativement faible par rapport à celui de l'Extended.

Une autre optimisation plus efficace serait de véritablement tester les points qui sont susceptibles d'être "à la limite" de la courbe de Bézier. Par exemple, tu peux te fixer une borne autour de la courbe de quelques pixels, et traiter uniquement ces pixels avec les formules mathématiques. Le reste, qui est certain de faire partie du remplissage, peut se remplir rapidement avec une fonction standard au prix de quelques calculs bien moins importants. Le gain y sera alors gigantesque car tu ne seras pas obligé de repasser sur les calculs coûteux pour chaque pixel du remplissage.

Evidemment, ça me semble nettement plus difficile à coder :/

Néanmoins, un 10 pour une source innovante (jamais vu de remplissage de courbes de Bézier !) et fonctionnelle.

Cordialement, Bacterius !

Commentaire de Bacterius le 24/05/2010 12:14:41 10/10

Désolé, j'ai oublié la note ...

Cordialement, Bacterius !

Commentaire de MAURICIO le 24/05/2010 12:21:55 administrateur CS

Peut-être en calculant 4 points sur la courbe pour peindre un polygone dont 2 seraient les extremités...
Ensuite, on a plus qu' à tester les points restants entre la courbe et le polygone.

Bref, peut-être est-ce trop compliqué pour quelques chose qui tourne très bien sur un PC de moins de 2 ans.

Mauricio

Commentaire de Bacterius le 24/05/2010 12:27:58

Oui voilà c'est ce que je proposais.

"Bref, peut-être est-ce trop compliqué pour quelques chose qui tourne très bien sur un PC de moins de 2 ans."
Mon ordinateur est un ordinateur portable de moins d'un an, plutôt décent niveau puissance de calcul. Seulement, je maintiens, essaye de faire glisser la souris vers l'extrémité bas/gauche de la fiche, tu verras (à moins que ton ordinateur soit en effet un bolide) un petit ralentissement. Donc oui, ça tourne bien, mais pas "très bien" pour des grandes surfaces et je pense qu'il est quand même possible d'améliorer un petit peu. Faire simplement un polygone qui économiserait déjà 50% des calculs serait déjà un gain énorme. Non ?

Cordialement, Bacterius !

Commentaire de barbichette le 24/05/2010 17:31:12

merci pour ces tuyaux. Et merci pour ces éloges,...
Je suis honnête, je n'ai pas cherché à optimiser le programme, mais à tester sont fonctionnement et voir si ça tournait...
Et en plus, j'avais besoin de ce code pour le remplissage et surtout pour le tracé des contours  dans le bon ordre.
Pour réduire la courbe à 4 points, c'était ma première piste. Piste que j'ai mis en pratique dans un logiciel "commercial" mais où je ne suis pas très content.
Par contre, lorsque la courbe fait des grandes circonvolutions, les segments apparaissent clairement. Pour limiter la chose, je mesure les distances entre les 4 points de la courbe (le départ, l'arrivée et les 2 poignées), ce qui me donne une grossière approximation de la longueur de la courbe, et je peux ainsi diviser non pas en 4 mais en un nombre de point plus important qui dépends de la longueur de la courbe. Mais même avec cette solution, le résultat n'est pas top top...


Enfin, si j'ai le courage, j'ai la même chose pour tracer des ellipses en travers, des camemberts,...
Mais il faut que je réécrive certains passages...

Barbichette

Commentaire de barbichette le 27/05/2010 16:47:09

Pour l'histoire de la rapidité, j'ai déjà fait des essais en utilisant "Scanline" au lieu de "Pixels", je ne vois plus de ralentissement (sur ma machine de compétition...)

Barbichette

Commentaire de Caribensila le 04/06/2010 23:03:08

Salut Barbichette,

Etait-ce bien la peine de dessiner une 'Bézier' avec les équations paramétrées du 3ème degré sans utiliser les APIs ou méthodes de TCanvas comme 'PolyBezier', par exemple ?
Ces méthodes, et surtout la méthode 'FloodFill' de TCanvas n'étaient-elles pas suffisantes et même plus souples ?

Ceci dit, ce code-source est super intéressant pour ceux qui veulent entrer dans les arcanes du dessin d'une 'Bézier', qui est nativement plutôt assez pauvre je trouve.  

Commentaire de barbichette le 06/06/2010 20:22:08

Salut Cari,
Polybezier ne remplit effectivement pas la courbe, et le problème de FloodFill, c'est de trouver où lancer le remplissage car les courbes de Béziers on la fâcheuse tendance à faire des boucles, voir des courbes qui se frôlent de façon tangentielle.  

Il est en effet acceptable de faire le remplissage à ma façon et le contour avec PolyBezier, mais je ne suis pas sûr à 100% que les deux sont bien superposable.
De plus, ma source propose les deux (contour+remplissage). Libre aux gens d'en prendre que la moitié...

Enfin, il n'est pas toujours intéressant de dessiner directement dans un Tcanvas et il est parfois nécessaire de tout réécrire soit même.
L'exemple le plus flagrant étant un logiciel de dessin que je développe actuellement et qui ne permet pas, en l'occurrence de dessiner dans un tcanvas, surtout si l'on veux des bords perso (comme des pointillées de différente tailles). Ce qui n'est d'ailleurs pas possible avec les api, même avec une simple ligne droite.

Barbichette

Commentaire de pseudo3 le 29/06/2010 12:21:31

Bonjour,

Je m'apprêtais à tester le code mais comme j'utilise Delphi-5 je ne dispose pas de la function 'sign' utilisée pour le calcul de mode:=(sign(p2.x-p1.x)+1)+(sign(p2.y-p1.y)+1)*3;

Quel est le calcul effectué par sign ou par quoi puis-je remplacer sign. S.V.P. Merci

A+

Commentaire de Caribensila le 29/06/2010 12:36:04

Bonjour,

Sign,fonction
Indique si une valeur numérique est positive,négative ou nulle.

Unité
Math

Description
Utilisez Sign pour tester le signe d'une valeur numérique.
Sign renvoie :
0  si AValue vaut zéro.
1  si AValue est supérieure àzéro.
-1  si AValue est inférieure àzéro.

Commentaire de pseudo3 le 29/06/2010 13:41:18

Re-bonjour,

Merci Caribensila : j'ai donc créé la fonction sign et du coup le code marche, je vais donc pouvoir le tester.

A+.

Commentaire de barbichette le 29/06/2010 18:33:16

Merci Caribensila, tu as été plus rapide que moi.

Barbichette

Commentaire de pseudo3 le 30/06/2010 16:55:02

Bonjour,

La remarque de Barbichette disant en introduction "Parce que je vais ensuite saucissonner ma patate en tranches de 1 pixel de hauteur" m'a donné une idée qui permet de simplifier énormément la partie mathématique du problème au point de pouvoir se passer entièrement de la résolution d'une éqquation du 3ième degré à chaque tour de boucle.

Voici l'idée dans ses grandes lignes :
- 1ière étape : On calcule les coordonnées de tous les points du contour de la courbe et on les sauve dans un tableau.
- 2ième étape : On trie ce tableau de façon à en classer les points en ordre décroissant des Y et des X comme dans l'exemple çi-après où les Y sont formés par le premier nombre :
0041:0056  <-- ici Y=41 et X=56
0041:0057

0042:0055 <-- ici pour Y = 42 on a Xmin=55 et Xmax=57
0042:0056
0042:0057 <-- Xmax=57
N.B : ce tri-double a été obtenu par utilisation d'une StringList.
- 3ième étape : Pour chaque valeur de Y on trace un trait de remplissage reliant horizontalement Xmin à Xmax.
Testé : ça marche sauf qu'il faut modifier la 3ième étape pour ajouter des traits de remplissage intermédiaires par interpolation entre deux rayures disjointes lorsque dans le tableau des Y,X on saute d'un Y vers un Y+DeltaDifférendDeUn.

Mon test a révélé qu'en partant de 360 points répartis sur le contour de la courbe il reste des rayures blanches du background à combler, mais je pense quand même qu'une simple interpolation ça doit être un peu plus simple que de résoudre une équa du 3ième degré. Je verrai cela dans les jours qui viennent.

A+.

Commentaire de pseudo3 le 06/07/2010 13:18:06

Bonjour,

Finalement j'ai abandonné la piste évoquée dans mon msg précédent et voici le code d'une solution hyper-simple utilisant FloodFill :

unit Unit1;

interface

uses
  Windows, Messages, SysUtils, Classes, Graphics, Controls, Forms,
  Dialogs, StdCtrls, Math, ComCtrls;

type
  TForm1 = class(TForm)
    procedure FormCreate(Sender: TObject);
    procedure FormMouseMove(Sender: TObject; Shift: TShiftState; X,
      Y: Integer);
    procedure FormResize(Sender: TObject);
  private
  public
  end;

var
  Form1: TForm1;

  type TBezier = record
                     PC  : array of TPoint; // Points de contrôle
                     nPC : integer;         // nb de Points de contrôle
                     R   : tRect; //Rectangle incluant enveloppe convexe des points de contrôle
                  end;

var  MaBeziers : TBezier;
     Bmp : tBitMap; //<- BitMap de travail

implementation

{$R *.dfm}

function CreeBezier( iPC : array of TPoint) : TBezier;
var      i : integer;
begin    with Result do
         begin nPC:=length(iPC);
               SetLength(PC,nPC);
               for i:=low(PC) to High(PC) do PC[i]:=iPC[i];
         end;
end;

procedure TraceContourBezier(var bmp : TBitMap; var cBezier : TBezier; epTrait : byte; clTrait : tColor);
var       i : integer;
begin     with bmp.canvas do begin
               pen.width:=epTrait;
               pen.color:=clTrait;
               brush.Style:=bsClear;
               PolyBezier(cBezier.PC);
          end;
          // Rectangle délimitant l'enveloppe convexe des points de contrôle et incluant la courbe.
          with cBezier do begin
               R:=Rect(MaxInt,MaxInt,0,0);
               for i:=low(PC) to High(PC) do begin
                   R.Left:=min(R.Left,PC[i].x);
                   R.Top :=min(R.Top,PC[i].y);
                   R.Right:=max(R.Right,PC[i].x);
                   R.Bottom:=max(R.Bottom,PC[i].y);
               end;
               // Recadrage si R déborde du BitMap
               if R.Left<0 then R.Left:=0; if R.Top<0 then R.Top:=0;
               if R.Right>bmp.Width-1 then R.Right:=bmp.Width-1;
               if R.Bottom>bmp.Height-1 then R.Bottom:=bmp.Height-1;
          end;
end; // TraceContourBezier

type     pLigScan = ^tLigScan;
         tLigScan = array[Word] of TRGBTriple;

procedure FloodFillBezier(var bmpBez : TBitMap; cBezier : TBezier; clBord, clFill : tColor);
var       x,y,yDeb,ipi,ipiMax,TotNbInter,numBord,R,G,B : integer;
          nbInterSect : array of Longint;
          Lig : pLigScan; SurBord : boolean;
          PointsF : array of tPoint;
begin     SetLength(nbInterSect,bmpBez.Height);
          // Parcours de Reconnaissance du BitMap dans la zone du Rectangle de délimitation :
          R:=GetRValue(clBord);
          G:=GetGValue(clBord);
          B:=GetBValue(clBord);
          y:=-1;
          repeat inc(y); x:=-1; nbInterSect[y]:=0; // zone de lignes sans intersection
                 Lig:=bmpBez.ScanLine[y];
             repeat inc(x);
                    SurBord:=(Lig[x].rgbtRed=R) and (Lig[x].rgbtGreen=G) and (Lig[x].rgbtBlue=B);
             until (x=cBezier.R.Right) or SurBord;
          until (y=cBezier.R.Bottom) or SurBord;
          yDeb:=y; TotNbInter:=0;

          with bmpBez.canvas do begin
               // Comptage du nombre d'intersections de la courbe avec chaque horizontale
               for y:=yDeb to cBezier.R.Bottom do begin
                   nbInterSect[y]:=0;
                   for x:=1 to bmpBez.width-1 do begin
                       if (Pixels[x-1,y]=clBord) and (Pixels[x,y]<>clBord) then
                       begin inc(nbInterSect[y]); inc(TotNbInter); end;
                   end;
               end;
               // Récup des positions des points d'amorçage :
               SetLength(PointsF,TotNbInter); ipi:=0; ipiMax:=0;
               for y:=yDeb to cBezier.R.Bottom do begin
                   numBord:=1;
                   if Odd(nbInterSect[y]) then Continue; // on évite les lignes à nombre impair d'intersections
                   if (nbInterSect[y]=nbInterSect[y-1]) then Continue;  // on évite aussi les doublons
                   for x:=1 to cBezier.R.Right do begin
                       // Sur les lignes horizontales comportant un nombre pair d'intersections avec la courbe
                       // le point d'amorçage de FloodFill est le point situé immédiatement à droite
                       // de chaque intersection de numéro impair
                       if (Pixels[x-1,y]=clBord) and (Pixels[x,y]<>clBord) then begin
                          if Odd(numBord) then begin
                             PointsF[ipi].x:=x; PointsF[ipi].y:=y;
                             ipiMax:=ipi;
                             inc(ipi);
                          end;
                          inc(numBord);
                       end;
                   end;
             end;
             brush.Color:=clFill;
             pen.color:=clBlue;
             for ipi:=0 to ipiMax do begin
                 x:=PointsF[ipi].x; y:=PointsF[ipi].y;
                 FloodFill(x,y,clBord,fsBorder);
                 // Marquage avec une croix du point d'amorçage de FloodFill :
                 // MoveTo(x-3,y);  LineTo(x+3,y);
                 // MoveTo(x,y-3);  LineTo(x, y+3);
             end;
         end;
end; // FloodFillBezier

procedure BezierFermeeInit; // Initialisation de la Courbe avec le nombre voulu de points
// de contrôle et de valeurs initiales quelconques :
var       pt : Array of TPoint;
begin     setlength(pt,10);
          pt[0]:=point(10,10);   pt[1]:=point(50,50); pt[2]:=point(35,35);
          pt[3]:=point(45,35);   pt[4]:=point(55,35); pt[5]:=point(18,42);
          pt[6]:=point(14,75);   pt[7]:=point( 2,50); pt[8]:=point(41,56);
          pt[9]:=pt[0]; //<- fermeture boucle
          MaBeziers:=CreeBezier( Pt );
end;

procedure TForm1.FormCreate(Sender: TObject);
begin     bmp:=tbitmap.Create;
          with bmp do begin
               PixelFormat:=pf24bit;
               Width:=ClientWidth;
               Height:=ClientHeight;
          end;
          BezierFermeeInit;
end;

// Traitement des messages
//==============================================================================
// mouvement de la souris, on affiche la courbe de bezier
procedure TForm1.FormMouseMove(Sender: TObject; Shift: TShiftState; X,Y: Integer);
begin     // on actualise le tableau des points de contrôle de la courbe
          with MaBeziers do begin
               PC[0]:=point(x-15,y-15);
               PC[1]:=point(x-50,y-100);
               PC[2]:=point(35 + x,35 + y);
               PC[3]:=point(45 + y,35 + x);
               PC[4]:=point(width div 2,height div 2);
               PC[5]:=point( 100+x div 2,50+x*y div (x+y));
               PC[6]:=point( 50+x div 2,50+x*y div (x+y));
               PC[7]:=point(    x div 2,50+x*y div (x+y));
               PC[8]:=point(x+50,y+100);
               PC[9]:=PC[0]; // <- Courbe refermée
          end;
          // on efface le bitmap temporaire de dessin
          bmp.Canvas.Brush.Color:=clWhite;
          bmp.Canvas.FillRect(clientrect);
          // on y trace la courbe et son remplissage
          TraceContourBezier(Bmp, MaBeziers, 1, clRed);
          FloodFillBezier(Bmp, MaBeziers, clRed, clAqua);

          // on affiche le résultat
          canvas.Draw(0,0,bmp);
end;

// redimensionnement de la fenêtre => on redimensionne le bitmap temporaire
procedure TForm1.FormResize(Sender: TObject);
begin     bmp.Width:=clientwidth;
          bmp.Height:=clientheight;
end;

END. ///////////////////////////////////////////////////////////////////////////

A+.

Commentaire de pseudo3 le 13/07/2010 12:25:57

Bonjour,

Voici une version corrigée du code de mon message précédent qui foirait dans certains cas particuliers de courbes qui rebouclaient fortement sur elles-mêmes.
Le code ci-après ne fait que 220 lignes soit environ deux fois moins que celui de Barbichette ... et il est peut-être possible de le simplifier encore davantage.

unit uFloodFillBezier;   // Remplissage d'une courbe de Béziers avec FloodFill(x,y,clBord,fsBorder)
                         // Les coordonnées x,y du point d'amorçage de FloddFill sont ici obtenues
interface                // simplement, graphiquement et par utilisation de ScanLine pour la vitesse.

uses
  Windows, Messages, SysUtils, Classes, Graphics, Controls, Forms,
  Dialogs, StdCtrls, Math, ComCtrls, Buttons;

type
  TForm1 = class(TForm)
    Label1: TLabel;
    procedure FormCreate(Sender: TObject);
    procedure FormMouseMove(Sender: TObject; Shift: TShiftState; X, Y: Integer);
    procedure FormResize(Sender: TObject);
  private
  public
  end;

var
  Form1: TForm1;

  type TBezier = record  PC  : array of TPoint; // Points de contrôle de la courbe
                         nPC : integer;         // nb de Points de contrôle
                         Courbe : array [0..360] of tPoint; //<- contour de la courbe mémorisé en un polygone de points en nombre réduit
                  end;

var  MaBezier : TBezier;
     Bmp : tBitMap; //<- BitMap de travail

implementation

{$R *.dfm}

function  CombinaisonsCpn(n,p : integer) : integer;
//        Result = (n!)/((p!)*(n-p)!) mais sans utiliser les factorielles pour éviter autant que possible l'overflow
var       i,eli,num,deno : integer;
begin     num:=1; deno:=1; eli:=n-(2*p); if eli<0 then eli:=0;
          try    for i:=p+1+eli to n do num:=num*i;
                 for i:=1 to n-p-eli do deno:=deno*i;
                 if deno=0 then deno:=1; // car convention 0!=1
                 Result:=num div deno;
          except on EOverflow
                 do begin Result:=-1; showMessage( 'EOverflow dans CombinaisonsCpn pour'+#13#10
                                                  +'n = '+intToStr(n)+#13#10
                                                  +'p = '+intToStr(p));
                 end;
          end;
end; // CombinaisonsCpn

const   nMax = 30; // nombre  maxi de points de contrôle de la courbe
type    tCoeff = array [0..nMax,0..nMax] of integer;
var     kBin : tCoeff;

procedure PreCalculCoeffsBezier;
var       i,n : byte;
begin     for i:=0 to nMax do for n:=0 to nMax do kBin[i,n]:=CombinaisonsCpn(n,i);
end;

procedure TraceContourBezier(var bmp: tBitMap; var cBezier : TBezier; epTrait : byte; clTrait : tColor);
var       iu,iuMax,i : integer;
          xp,yp,binu,xB,yB,u : Single;
begin     with cBezier do
          begin xp:=0; yp:=0; xB:=0; yB:=0; iuMax:=High(cBezier.Courbe);
                with bmp.canvas do
                begin pen.width:=epTrait; pen.color:=clTrait; brush.style:=bsClear;
                      for iu:=0 to iuMax do
                      begin u:=iu/iuMax;
                            for i:=0 to npc-1 do
                            begin binu:=kBin[i,npc-1]*Power(u,i)*Power(1-u,npc-1-i);
                                  if i=0 // xb,yb = Point sur la courbe de Bézier
                                  then begin xb:=PC[i].x*binu; yb:=PC[i].y*binu; end
                                  else begin xb:=xb+PC[i].x*binu; yb:=yb+PC[i].y*binu; end;
                            end;
                            if iu = 0 then begin xp:=xb;  yp:=yb; end;
                            Courbe[iu].x:=round(xb); Courbe[iu].y:=round(yb); //<- Polygone de points sur la courbe
                            MoveTo(round(xp),round(yp)); LineTo(round(xb),round(yb)); // points reliés par LineTo pour fermer la courbe
                            xp:=xb; yp:=yb;
                      end;
                end;
          end;
end; // TraceContourBezier

function PointDansPolygone(const x,y : integer; Polygone : array of TPoint): boolean;
//       Renvoie True si le point x,y est à l'intérieur du Polygone de points
var      Handle : HRGN;
begin    Handle := CreatePolygonRgn(Polygone[0],length(Polygone),Winding);
         Result := PtInRegion(Handle,X,Y);
         DeleteObject(Handle);
end;

type     TRGBArray = ARRAY[0..0] OF TRGBTriple;   // Elément de bitmap (API windows)
         pRGBArray = ^TRGBArray;                  // Type pointeur vers tableau 3 octets 24 bits

procedure FloodFillBezier(const bmp : TBitMap; var cBezier : TBezier; clBord, clFill : tColor);
label     Saut;
var       Scans : array[0..2047] of pRGBArray; //< Tableau de ScanLines pour BitMap's d'au plus 2048 lignes
          i,h,w,x,y,xMin,yMin,xMax,yMax,ipi,ipiMax,TotNbInter,numBord : integer;
          nbInterSect : array of Longint;       cl1,cl2 : tColor;
          PointsDAmo : array of tPoint;

          function cl(xi,yi : integer) : tColor;
          begin    Result:=RGB(Scans[yi,xi].rgbtRed,Scans[yi,xi].rgbtGreen,Scans[yi,xi].rgbtBlue);
          end;

          function EstPointEnclave(ix,iy : integer) : boolean; // Point interne entouré de clBord
          var      clxy,clN,clO,clS,clE : tColor;
          begin    Result:=false;
                   if (ix-1<0) or (iy-1<0) or (ix+1>w-1) or (iy+1>h-1) then EXIT;
                   clxy:=cl(ix,iy);
                   clN:=cl(ix  ,iy-1); // Nord
                   clO:=cl(ix-1,iy);   // Ouest
                   clS:=cl(ix  ,iy+1); // Sud
                   clE:=cl(ix+1,iy);   // Est
                   Result:=(clxy<>clBord) and (clN=clBord) and (clO=clBord)
                                          and (clS=clBord) and (clE=clBord);
          end;

begin     W:=bmp.width; H:=bmp.height;
          for y := 0 to h-1 do Scans[y]:=bmp.ScanLine[y];
          SetLength(nbInterSect,h);
          // Parcours de reconnaissance du BitMap :
          // a) Limitation de la zone à scanner au rectangle [xMin,yMin .. xMax,yMax] entourant la courbe
          xMin:=MaxInt; yMin:=MaxInt; xMax:=0; yMax:=0;
          for i:=0 to High(cBezier.Courbe) do begin
              xMin:=min(xMin,cBezier.Courbe[i].x); yMin:=min(yMin,cBezier.Courbe[i].y);
              xMax:=max(xMax,cBezier.Courbe[i].x); yMax:=max(yMax,cBezier.Courbe[i].y);
          end;
          if xMax>W-1 then xMax:=W-1; if yMax>H-1 then yMax:=H-1;
          if xMin<0   then xMin:=0;   if yMin<0   then yMin:=0;
          TotNbInter:=0;
          // b) Comptage du nombre d'intersections de la courbe avec chaque horizontale :
          y:=yMin-1;
        Saut :
          repeat inc(y);
              nbInterSect[y]:=0;
              for x:=xMin+1 to xMax do begin
                  cl1:=cl(x-1,y); cl2:=cl(x,y);
                  if (cl1=clBord) and (cl2<>clBord) then // nombre d'intersections sauf lignes à cas de points enclavés
                  begin if Not EstPointEnclave(x,y)
                        then begin inc(nbInterSect[y]); inc(TotNbInter); end
                        else begin nbInterSect[y]:=1; //<- Nb impair : marque les lignes à éviter par la suite
                                   Goto Saut;
                        end;
                  end;
              end;
          until y = yMax;
          // c) Récup des positions des points d'amorçage utiles à FloodFill :
          SetLength(PointsDAmo,TotNbInter); ipi:=0; ipiMax:=0;
          for y:=yMin to yMax do begin
              numBord:=1;
              if Odd(nbInterSect[y]) then Continue; // on évite les lignes à nombre impair d'intersections
              if (nbInterSect[y]=nbInterSect[y-1]) then Continue;  // on évite aussi les doublons
              for x:=xMin+1 to xMax do begin
                  cl1:=cl(x-1,y); cl2:=cl(x,y);
                  // Sur les lignes horizontales comportant un nombre pair d'intersections avec la courbe
                  // le point d'amorçage sélectionné pour FloodFill est le point situé immédiatement à droite
                  // de chaque intersection de numéro impair vu que la numérotation commence ici par numBord:=1
                  if (cl1=clBord) and (cl2<>clBord) then begin
                     if Odd(numBord) then begin
                        PointsDAmo[ipi].x:=x; PointsDAmo[ipi].y:=y;
                        ipiMax:=ipi;
                        inc(ipi);
                     end;
                     inc(numBord);
                  end;
              end;
        end;
        // d) Utilisation des points d'amorçage par FlooFill
        with bmp.canvas do begin
             brush.Color:=clFill;
             for ipi:=0 to ipiMax do begin
                 x:=PointsDAmo[ipi].x; y:=PointsDAmo[ipi].y;
                 if PointDansPolygone(x,y, cBezier.Courbe) then begin
                    FloodFill(x,y,clBord,fsBorder);
                 end;
             end;
       end;
end; // FloodFillBezier

// Utilisation : ---------------------------------------------------------------

// Initialisations :
procedure TForm1.FormCreate(Sender: TObject);
begin     bmp:=tbitmap.Create;
          with bmp do begin PixelFormat:=pf24Bit; Width:=ClientWidth; Height:=ClientHeight; end;
          with MaBezier do begin nPC:=10;  SetLength(PC,nPC); end;
          PrecalculCoeffsBezier;
end;

// redimensionnement de la fenêtre => on redimensionne le bitmap temporaire
procedure TForm1.FormResize(Sender: TObject);
begin     bmp.Width:=clientwidth; bmp.Height:=clientheight;
end;

// Mouvement de la souris, on affiche la nouvelle courbe de bezier
procedure TForm1.FormMouseMove(Sender: TObject; Shift: TShiftState; X,Y: Integer);
begin     // on actualise le tableau des points de contrôle de la courbe
          with MaBezier do begin
               pc[0]:=point(x-15,y-15);
               pc[1]:=point(x+50,y-100);
               pc[2]:=point(150-y,350);
               pc[3]:=point(-250,350+(y div 3));
               pc[4]:=point(850-x,350-y);
               pc[5]:=point( 100+x div 2,-50+x*y div (x+y));
               pc[6]:=point( 50+x div 2,-50+x*y div (x+y));
               pc[7]:=point(    15,-50+x*y div (x+y));
               pc[8]:=point(x+50,bmp.height-20);
               pc[9]:=PC[0];
          end;
          // on efface le bitmap temporaire de dessin
          bmp.Canvas.Brush.Color:=clWhite;
          bmp.Canvas.FillRect(clientrect);
          // on y trace la courbe puis son remplissage
          TraceContourBezier(Bmp, MaBezier, 1, clRed);
          FloodFillBezier(Bmp, MaBezier, clRed, clAqua); //<- la couleur du contour ici clRed doit être identique à celle utilisée par TraceContourBezier sinon Violation d'accès
          // on affiche le résultat
          Canvas.Draw(0,0,bmp);
end;

END. ///////////////////////////////////////////////////////////////////////////

A+.

Commentaire de barbichette le 13/07/2010 18:35:40

Bonjour,

Merci pour cette simplification, mais je préciserai que mon but n'était pas d'utiliser au maximum les API Windows mais bien de montrer le mécanisme qui se cache derrière.
Je rappelle qu'en utilisant de façon astucieuse scanline au lieu de pixels, mon code tourne presque aussi rapidement que le fait photoshop.
De plus, il n'est pas possible, il me semble de produire des courbes comme la mienne, à savoir avec un dégradé personnalisable, avec les API, et le remplissage ne marche avec floodfill ne marche bien que si le fond est uni ou si le contour est uni, il me semble.

Mais, toutes les idées sont bonne à prendre et je pense qu'un crack en mathématique pourrai trouver une solution en simplifiant les équations du 3° degrés par des calcules plus simple...

Barbichette

Commentaire de pseudo3 le 14/07/2010 12:17:20

Bonjour,

Je tiens à préciser que mon seul objectif est de trouver une solution qui résoud ce problème en un nombre minimal de lignes ... donc je m'accroche tant que j'ai la conviction que l'on pourrait gratter encore des lignes.

Barbichette, tu dis : "De plus, il n'est pas possible, il me semble de produire des courbes comme la mienne, à savoir avec un dégradé personnalisable, avec les API, et le remplissage ne marche avec floodfill ne marche bien que si le fond est uni ou si le contour est uni, il me semble".

Objection, votre honneur, car :

1) Concernant le dégradé personnalisable : Dans mon code je l'ai viré car c'était hors sujet. Mais comme le contour de la courbe est mémorisé dans le tableau nommé Courbe : array [0..360] of tPoint, rien n'empêcherait de réaliser ce dégradé à la fin du remplissage de la courbe en re-traçant le contour (par dessus-le contour initial uniforme) avec une boucle de 361 MoveTo..LineTo entre lesquels on place un pen.color:=Palette[i] ...

2) Concernant le "floodfill ne marche bien que si le fond est uni" : Pour éviter ceci j'ai utilisé le FlodFill du style fsBorder et j'ai fait un test de bon fonctionnement en traçant des ellipses sur le bitMap avant la courbe de Bézier et il suffit que les couleurs des contours des diverses courbes présentes sur le même Bmp soient numériquement différentes (un rouge RGB(255,1,1) est différent d'un rouge RGB(254,2,2) mais visuellement ils sont kif-kif) pour éviter les embrouilles.

Ceci étant je suis persuadé que l'on devrait pouvoir simplifier encore davantage en utilisant l'API cité dans la première ligne de la "Description" et qui dit "Il existe une API pour tracer un polygone rempli. Mais pas pour les courbes de Bézier" ... or dans mon cas la courbe de Bézier n'est rien d'autre qu'un polygone de 361 points.

Cordialement, et à +.

Commentaire de pseudo3 le 14/07/2010 16:36:03

Re-bonjour,

En final l'API signalée par Barbichette permet d'effectuer le remplissage en seulement 15 lignes de codes : voir la procédure RemplirBezier dans le code final ci-après où pour faire plaisir à Barbichette j'ai remis sa palette et ajouté la routine ContourBezierDegrade(Bmp, MaBezier, 2, Palette) pour le tracé final du bord aux couleurs dégradées de l'arc-en-ciel.
(Palette + ContourBezierDegrade coûte 30 lignes ça fait beaucoup)

unit uRemplirBezier;   // Remplissage d'une courbe de Béziers avec API Polygon

interface

uses   Windows, Messages, SysUtils, Classes, Graphics, Controls, Forms,
       Dialogs, StdCtrls, Math, ComCtrls, Buttons;

type
  TfrmBezier = class(TForm)
    Label1: TLabel;
    procedure FormCreate(Sender: TObject);
    procedure FormMouseMove(Sender: TObject; Shift: TShiftState; X, Y: Integer);
    procedure FormResize(Sender: TObject);
  private
  public
  end;

var
  frmBezier: TfrmBezier;

const indexMax = 360;

  type TBezier = record  PC  : array of TPoint; // Points de contrôle de la courbe
                         nPC : integer;         // nb de Points de contrôle
                         Courbe : array [0..indexMax] of tPoint; //<- contour de la courbe mémorisé en un polygone de points en nombre réduit
                  end;

var  MaBezier : TBezier;
     Bmp : tBitMap; //<- BitMap de travail

type tpalette = array[0..indexMax] of longint;
var  palette : tpalette;

implementation

{$R *.dfm}

procedure PrecalculPalette; // palette de couleur pour contour dégradé arc-en-ciel
var       i:integer;
begin     for i:=0 to indexMax do
           Case (i div 60) of
              0,6:palette[i]:=rgb(255,(i Mod 60)*255 div 60,0);
              1: palette[i]:=rgb(255-(i Mod 60)*255 div 60,255,0);
              2: palette[i]:=rgb(0,255,(i Mod 60)*255 div 60);
              3: palette[i]:=rgb(0,255-(i Mod 60)*255 div 60,255);
              4: palette[i]:=rgb((i Mod 60)*255 div 60,0,255);
              5: palette[i]:=rgb(255,0,255-(i Mod 60)*255 div 60);
           end;
end;

function  CombinaisonsCpn(n,p : integer) : integer;
//        Result = (n!)/((p!)*(n-p)!) mais sans utiliser les factorielles pour éviter autant que possible l'overflow
var       i,eli,num,deno : integer;
begin     num:=1; deno:=1; eli:=n-(2*p); if eli<0 then eli:=0;
          try    for i:=p+1+eli to n do num:=num*i;
                 for i:=1 to n-p-eli do deno:=deno*i;
                 if deno=0 then deno:=1; // car convention 0!=1
                 Result:=num div deno;
          except on EOverflow
                 do begin Result:=-1; showMessage( 'EOverflow dans CombinaisonsCpn pour'+#13#10
                                                  +'n = '+intToStr(n)+#13#10
                                                  +'p = '+intToStr(p));
                 end;
          end;
end; // CombinaisonsCpn

const   nMax = 30; // nombre  maxi de points de contrôle de la courbe
type    tCoeff = array [0..nMax,0..nMax] of integer;
var     kBin : tCoeff;

procedure PreCalculCoeffsBezier;
var       i,n : byte;
begin     for i:=0 to nMax do for n:=0 to nMax do kBin[i,n]:=CombinaisonsCpn(n,i);
end;

procedure TraceContourBezier(var bmp: tBitMap; var cBezier : TBezier; epTrait : byte; clTrait : tColor);
var       iu,i : integer;
          xp,yp,binu,xB,yB,u : Single;
begin     with cBezier do
          begin xp:=0; yp:=0; xB:=0; yB:=0;
                with bmp.canvas do
                begin pen.width:=epTrait; pen.color:=clTrait; brush.style:=bsClear;
                      for iu:=0 to indexMax do
                      begin u:=iu/indexMax;
                            for i:=0 to npc-1 do
                            begin binu:=kBin[i,npc-1]*Power(u,i)*Power(1-u,npc-1-i);
                                  if i=0 // xb,yb = Point sur la courbe de Bézier
                                  then begin xb:=PC[i].x*binu; yb:=PC[i].y*binu; end
                                  else begin xb:=xb+PC[i].x*binu; yb:=yb+PC[i].y*binu; end;
                            end;
                            if iu = 0 then begin xp:=xb;  yp:=yb; end;
                            Courbe[iu].x:=round(xb); Courbe[iu].y:=round(yb); //<- Polygone de points sur la courbe
                            MoveTo(round(xp),round(yp)); LineTo(round(xb),round(yb)); // points reliés par LineTo pour fermer la courbe
                            xp:=xb; yp:=yb;
                      end;
                end;
          end;
end; // TraceContourBezier

procedure RemplirBezier(var bmp: tBitMap; var cBezier : TBezier; clRempli : tColor);
var   dc : HDC; AncBrush,NouvBrush : HBRUSH;
begin     dc := bmp.canvas.Handle;
          // initialisation de la couleur de remplissage
          NouvBrush := CreateSolidBrush(clRempli);
          AncBrush := SelectObject(dc,NouvBrush);
          // le contexte doit être transparent
          SetBkMode(dc,TRANSPARENT);
          SetPolyFillMode(dc,Winding);
          Polygon(dc,cBezier.Courbe,length(cBezier.Courbe));
          // Restauration objets et libération mémoire
          SelectObject(dc,AncBrush);
          DeleteObject(NouvBrush);
end;

procedure ContourBezierDegrade(var bmp: tBitMap; var cBezier : TBezier; epTrait : integer; Pal : tpalette);
var       iu : integer;
begin     with cBezier do
          begin with bmp.canvas do
                begin pen.width:=epTrait; brush.style:=bsClear;
                      for iu:=1 to indexMax do
                      begin pen.color:=Pal[iu];
                            MoveTo(Courbe[iu-1].x,Courbe[iu-1].y);
                            LineTo(Courbe[iu].x,Courbe[iu].y);
                      end;
                end;
          end;
end; // ContourBezierDegrad

// Utilisation : ---------------------------------------------------------------

// Initialisations :
procedure TfrmBezier.FormCreate(Sender: TObject);
begin     bmp:=tbitmap.Create;
          with bmp do begin PixelFormat:=pf24Bit; Width:=ClientWidth; Height:=ClientHeight; end;
          with MaBezier do begin nPC:=10;  SetLength(PC,nPC); end;
          PrecalculCoeffsBezier;
          PrecalculPalette;
end;

// redimensionnement de la fenêtre => on redimensionne le bitmap temporaire
procedure TfrmBezier.FormResize(Sender: TObject);
begin     bmp.Width:=clientwidth; bmp.Height:=clientheight;
end;

// Mouvement de la souris, on affiche la nouvelle courbe de bezier
procedure TfrmBezier.FormMouseMove(Sender: TObject; Shift: TShiftState; X,Y: Integer);
begin     // on actualise le tableau des points de contrôle de la courbe
          with MaBezier do begin
               pc[0]:=point(x-15,y-15);
               pc[1]:=point(x+50,y-100);
               pc[2]:=point(150-y,350);
               pc[3]:=point(-250,350+(y div 3));
               pc[4]:=point(850-x,350-y);
               pc[5]:=point( 100+x div 2,-50+x*y div (x+y));
               pc[6]:=point( 50+x div 2,-50+x*y div (x+y));
               pc[7]:=point(    15,-50+x*y div (x+y));
               pc[8]:=point(x+50,bmp.height-20);
               pc[9]:=PC[0];
          end;
          // on efface le bitmap temporaire de dessin
          bmp.Canvas.Brush.Color:=clWhite;
          bmp.Canvas.FillRect(clientrect);
          // on y trace d'abord une ellipse pour garnir le fond
          bmp.canvas.pen.color:=RGB(254,5,5); //<- un rouge numériqement différent de clRed
          bmp.canvas.Ellipse( 100,50, 200,300);
          // on y dessine la courbe de bézier puis son remplissage
          TraceContourBezier(Bmp, MaBezier, 1, clRed);
          RemplirBezier(Bmp, MaBezier, clAqua);
          // et pour faire un contour dégradé :
          ContourBezierDegrade(Bmp, MaBezier, 2, Palette);
          // on affiche le résultat
          Canvas.Draw(0,0,bmp);
end;

END. ///////////////////////////////////////////////////////////////////////////

Cordialement, et à plus.

Commentaire de barbichette le 14/07/2010 19:41:38

La fonction RemplirBezier
peut ressembler à ça :

procedure RemplirBezier(var bmp: tBitMap; var cBezier : TBezier; clRempli : tColor);
begin
with bmp.Canvas do begin
   Brush.Color:= clRempli;
   SetBkMode(Handle,TRANSPARENT);
   SetPolyFillMode(Handle,WINDING);
   Polygon(cBezier.Courbe);
end;
end;

Par contre, une petite explication sur SetPolyFillMode :
C'est une fonction qui gère la règle à appliquer pour définir l'intérieur de l'extérieur du dessin
WINDING : règle de l'enroulement (on dessine du premier bord gauche au bord droit sans interruption)
ALTERNATE : règle du pair/impair (on entre dans le dessin au bord gauche, on en ressort au bord suivant, on y rentre au bord suivant.... jusqu'au bord droit)

une petite explication sur SetBkMode :
et bien je n'en vois pas l'utilité ici, mais bon,
OPAQUE : dessine l'arrière plan avec la couleur de fond
TRANSPARENT : ne touche rien à l'arrière plan
Ici, la fonction polygon ne touche rien à l'arrière plan à l'extérieur du polygone... Donc, on peut le supprimer

Barbichette

Commentaire de pseudo3 le 15/07/2010 11:00:34

Salut Barbichette,

Je pensais qu'avec sa quinzaine de lignes la procedure RemplirBezier ne pourrait plus être simplifiée.

Je vois que t'as pu la ramener à 9 lignes. C'est quand même considérablement plus simple que nos premiers codes.

Juste une remarque, pour ma part je vais la rebaptiser et la modifier légèrement comme suit, vu qu'elle n'est pas réservée aux courbes Bézier :
procedure RemplirPolyCourbe(var bmp: tBitMap; var PolyCourbe : array of tPoint; clRempli : tColor); histoire de se souvenir qu'elle est utilisable pour tout type de polygone ou de courbe fermée.

Ok sur tes explications concernant SetPolyFillMode : On pourrait ajouter aux paramètres d'appel de la procedure un boolean qui fait utiliser soit WINDING, soit ALTERNATE.  

SetBkMode : exact je n'avais pas essayé de le supprimer : En fait j'étais parti d'une procedure qui permet de dessiner une fonte bi-colore (ex : jaune bordé de bleu) en y supprimant ce qui visait la fonte et en y ajoutant ce qui concerne les courbes ... et j'étais tellement content de voir que cela marchait avec si peu de lignes que j'en suis resté là.

Concernant ta source : Comme tu dis en 1ière ligne de la Description "Il existe une API pour tracer un polygone rempli. Mais pas pour les courbes de Bézier" et qu'on vient de prouver le contraire vu que cette API peut tracer le remplissage des Bézier il faudrait au moins corriger ceci. Pour le reste à toi de voir si tu veux conserver l'ancien code style "usine à gaz matheuse" ou si tu veux proposer la solution finale simple et concise.

Cordialement et à +.

Commentaire de barbichette le 15/07/2010 21:23:46

Salut Pseudo3.

Je te propose plutôt de créer une nouvelle source avec ta solution mais je garderai la mienne ainsi.
Pour plusieurs raisons.
- Elle permet de voir comment tracer une courbe de Bézier et de la remplir, de façon mathématique.
- Utiliser une approximation d'une courbe ne revient pas à tracer une courbe. Si une boucle est grande, on verra les segments. Sauf si on augmente ton "nMax", mais dans ce cas, je ne trouve pas très judicieux de couper en 40 ou 50 une petite courbe.
- Uitliser l'API "polygon" en disant que ça prouve que l'on peut tracer une courbe de Bezier, ce n'est pas vrai (de mon point de vu).
- il y a de nombreux cas où l'on ne veut pas tracer une courbe dans un canvas (ce qui est mon cas) et dans ce cas, les API windows ne nous sont pas d'une grande aide. Donc, mieux vaut savoir ce qu'il y a derrière.

Barbichette

Commentaire de pseudo3 le 16/07/2010 11:26:13

Salut Barbichette,

1) "Je te propose plutôt de créer une nouvelle source avec ta solution" : OK, tu peux le faire.

2) "mais je garderai la mienne ainsi. Pour plusieurs raisons" : Le coeur a ses raisons que la raison n'a pas (lol). Mais je te signale une autre raison : avec ta solution le remplissage se fait "pixel par pixel" donc il suffit d'une légère modif si on veut réaliser un remplissage en mode NotXor car avec ma solution le NotXor n'est applicable qu'à Pen.Mode et Brush.Mode n'existe pas.

3) "Uitliser l'API "polygon" en disant que ça prouve que l'on peut tracer une courbe de Bezier, ce n'est pas vrai (de mon point de vu)" : Pas tout à fait d'accord, car toute courbe fermée, tracée par quelque technique informatique que ce soit forme un ensemble de points que l'on nomme "polygone" lorsqu'il y a des angles ou courbe lorsque les points sont assez rapporchés et disposés en arc ... et dans tous ces cas l'API "polygon" permet non seulement d'en tracer le contour mais également son remplissage. Donc pour des courbes particulières rien n'interdit de prendre 3600 points de contour au lieu des 360 du code... sans oublier que si on tombe sur une zone de courbe où il est techniquement impossible que les points théoriques se matérialisent par des pixels situés côte à côte, zones où la fonction est fortement croissante, et où l'on obligé de faire des raccords linéaires.) OK ?

Cordialement, et à +.

Commentaire de pseudo3 le 16/07/2010 12:22:46

Re-salut,

Complément à mon message précédent :

Tu dis "Si une boucle est grande, on verra les segments. Sauf si on augmente ton "nMax"" :
Non il y a confusion : "nMax" = nombre maxi de points de contrôle de la courbe qui sont tous à l'extérieur de la courbe sauf le 1er et le dernier.

C'est les 360 de Courbe : array [0..360] of tPoint qu'il faut augmenter le cas échéant.

Cordialement, et à +.

 Ajouter un commentaire


Discussions en rapport avec ce code source dans le forum

Ligne courbe [ par magicvinni ] Je cherche à tracer une ligne courbe entre deux points A et B et qui passe par C (en fait un morceau du cercle circonscrit au triangle ABC serait très Lissage de courbe en temps réel [ par roeugene ] BonjourJ'affiche en temps réel une courbe sur le graphique Tchart. La courbe est composée de droite et j'aimerais faire un lissage de courbe. Il faut accélération d'animations 2D [ par Fandril ] Je reprend un projet ou il y a des animations 2D faites avec le canva standard de delphi. Cependant, ces animations sont beaucopup trop lente (l'utili remplissage automatique de formulaire web [ par thone08 ] Bonjour j'aurai voulu savoir comment faire pour remplir des formulaire web de facon automatique soit par un webrowser ou par internet explorer ;) merc demande aide pour une representation graphique d'une courbe en miliseconde [ par ludolechinois ] je cherche un exemple de programme qui afficherait des donnees type temperature sous forme de courbe et dont l'axe X serait en miliseconde.Ensuite je Remplissage d'une stringgrid [ par Rankin ] Salut, je me posais seulement la question de savoir si dans une stringgrid le texte peut s'afficher sur plusieurs ligne, parce que je souhaite y affic Remplissage de champs autom sur une page Web [ par biloue ] Bonjour à tousJe sais que le sujet a déjà été traité mais je n'arrive pas à ouvrir le source.Je voudrais savoir si il est possible de remplir automati Temps réel [ par fredjn ] fred jnBonjour, Vopilà je souhaite réaliser un oscilloscope en temps réel, dont l'acquisition de point d'intersection d'une droite avec une courbe? [ par calajoue ] bonjour,soit une droite y:=ax+b; connuset une fonction polynominale y:=f(x), de degree n;je cherche le code source pour avoir le point d'intersection Courbe de tendance [ par jmp77 ] Hello, Voici mon souci. Je souhaiterais reproduire la fonction excel "courbe de tendance". Pour etre plus clair j'ai une courbe avec X points et dans


Nos sponsors


Sondage...

Comparez les prix

CalendriCode

Mai 2013
LMMJVSD
  12345
6789101112
13141516171819
20212223242526
2728293031  

Consulter la suite du CalendriCode

Photothèque

A découvrir



 
Développement réalisé par Nicolas SOREL (Nix) avec l'aide de : Cyril DURAND et Emmanuel (EBArtSoft), Merci à Vincent pour ses précieux conseils.
CodeS-SourceS.com© Toute reproduction même partielle est interdite sauf accord écrit du Webmaster
CodeS-SourceS.com© est une marque déposée tous droits réservés

Google Coop CodeS-SourceS Google Coop CodeS-SourceS
Temps d'éxécution de la page : 0,702 sec (4)

Nous contacter | Annoncer sur CodeS-SourceS | Mentions légales