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

Les interpolations avec Lazarus (3/3)

Les courbes de Bézier cubiques

L'auteur

Profil ProSite personnel

Liens sociaux

Viadeo Twitter Facebook Share on Google+   

I. Introduction

Les programmes de test sont présents dans le répertoire exemples accompagnant le tutoriel.

II. Les courbes de Bézier cubiques (cubic bezier)

II-A. Un exemple interactif

II-B. La production de listes de coordonnées

II-C. Les courbes de Bézier en action

III. Des classes pour les interpolations, fonctions d'easing et les courbes de Bézier cubiques

IV. Une unité pour les nostalgiques

[Exemple Interpolations 08]

Comme souvent en Pascal, il est possible de travailler avec des fonctions hors des classes. Nous fournissons donc une unité baptisée interpolationfunctions composée des fonctions étudiées, mais accessibles directement.

En voici l'interface :

 
Sélectionnez
unit interpolationfunctions;

{$mode objfpc}{$H+}

interface

uses
  Classes, SysUtils;

type
  TInterpolationFunction = function(AStart, AEnd, ADuration, AStep: Single):
   Single;

function InPower(AStart, AChange, ADuration, AStep: Single; APower: Integer): Single;
function OutPower(AStart, AChange, ADuration, AStep: Single; APower: Integer): Single;
function InOutPower(AStart, AChange, ADuration, AStep: Single; APower: Integer): Single;
function EaseNone(AStart, AEnd, ADuration, AStep: Single): Single;
function EaseInQuad(AStart, AEnd, ADuration, AStep: Single): Single;
function EaseOutQuad(AStart, AEnd, ADuration, AStep: Single): Single;
function EaseInOutQuad(AStart, AEnd, ADuration, AStep: Single): Single;
function EaseOutInQuad(AStart, AEnd, ADuration, AStep: Single): Single;
function EaseInCubic(AStart, AEnd, ADuration, AStep: Single): Single;
function EaseOutCubic(AStart, AEnd, ADuration, AStep: Single): Single;
function EaseInOutCubic(AStart, AEnd, ADuration, AStep: Single): Single;
function EaseOutInCubic(AStart, AEnd, ADuration, AStep: Single): Single;
function EaseInQuart(AStart, AEnd, ADuration, AStep: Single): Single;
function EaseOutQuart(AStart, AEnd, ADuration, AStep: Single): Single;
function EaseInOutQuart(AStart, AEnd, ADuration, AStep: Single): Single;
function EaseOutInQuart(AStart, AEnd, ADuration, AStep: Single): Single;
function EaseInQuint(AStart, AEnd, ADuration, AStep: Single): Single;
function EaseOutQuint(AStart, AEnd, ADuration, AStep: Single): Single;
function EaseInOutQuint(AStart, AEnd, ADuration, AStep: Single): Single;
function EaseOutInQuint(AStart, AEnd, ADuration, AStep: Single): Single;
function EaseInSine(AStart, AEnd, ADuration, AStep: Single): Single;
function EaseOutSine(AStart, AEnd, ADuration, AStep: Single): Single;
function EaseInOutSine(AStart, AEnd, ADuration, AStep: Single): Single;
function EaseOutInSine(AStart, AEnd, ADuration, AStep: Single): Single;
function EaseInExpo(AStart, AEnd, ADuration, AStep: Single): Single;
function EaseOutExpo(AStart, AEnd, ADuration, AStep: Single): Single;
function EaseInOutExpo(AStart, AEnd, ADuration, AStep: Single): Single;
function EaseOutInExpo(AStart, AEnd, ADuration, AStep: Single): Single;
function EaseInCirc(AStart, AEnd, ADuration, AStep: Single): Single;
function EaseOutCirc(AStart, AEnd, ADuration, AStep: Single): Single;
function EaseInOutCirc(AStart, AEnd, ADuration, AStep: Single): Single;
function EaseOutInCirc(AStart, AEnd, ADuration, AStep: Single): Single;
function EaseInElastic(AStart, AEnd, ADuration, AStep: Single): Single;
function EaseOutElastic(AStart, AEnd, ADuration, AStep: Single): Single;
function EaseInOutElastic(AStart, AEnd, ADuration, AStep: Single): Single;
function EaseOutInElastic(AStart, AEnd, ADuration, AStep: Single): Single;
function EaseInBack(AStart, AEnd, ADuration, AStep: Single): Single;
function EaseOutBack(AStart, AEnd, ADuration, AStep: Single): Single;
function EaseInOutBack(AStart, AEnd, ADuration, AStep: Single): Single;
function EaseOutInBack(AStart, AEnd, ADuration, AStep: Single): Single;
function EaseInBounce(AStart, AEnd, ADuration, AStep: Single): Single;
function EaseOutBounce(AStart, AEnd, ADuration, AStep: Single): Single;
function EaseInOutBounce(AStart, AEnd, ADuration, AStep: Single): Single;
function EaseOutInBounce(AStart, AEnd, ADuration, AStep: Single): Single;

Le type TInterpolationfunction permet d'utiliser ces fonctions comme paramètres de procédures ou d'autres fonctions.

Ainsi, l'entête de ComputeInterpolation pourra devenir :

 
Sélectionnez
function TMainForm.ComputeInterpolation(AInter: TInterpolationFunction; AStart,
  AEnd, AStep: Single; ABack: Boolean): Single;

L'appel de cette fonction se fera en précisant qu'il ne s'agit pas d'exécuter la fonction fournie comme premier paramètre, mais d'accéder à son adresse. Nous utiliserons alors un @ devant son identificateur :

 
Sélectionnez
btnEaseInQuad.Left := ComputeInterpolationInt(@EaseInQuad, 0, LWidth, Li, LBack);

Pour le reste, la modification essentielle tient au fait que la durée n'est plus accessible directement puisque nous nous situons hors de la classe : il faut par conséquent prévoir un paramètre supplémentaire à toutes nos fonctions (Aduration).

Si nous reprenons l'exemple 03 donné dans le premier tutoriel pour afficher les fonctions d'easing, quelques modifications sont à apporter à sa réalisation. Voici le code source de l'unité principale modifiée :

 
Sélectionnez
unit main;

{$mode objfpc}{$H+}

interface

uses
  Classes, SysUtils, FileUtil, Forms, Controls, Graphics, Dialogs, ExtCtrls,
  StdCtrls, ComCtrls,
  interpolationfunctions;

const
 C_DefaultDuration = 100;
 C_End = 200;

type

  { TMainForm }

  TMainForm = class(TForm)
    btnEaseOutInQuart: TButton;
    btnLinear2: TButton;
    btnEaseInQuad: TButton;
    btnEaseOutCubic: TButton;
    btnEaseInCubic: TButton;
    btnEaseOutQuad: TButton;
    btnEaseInOutCubic: TButton;
    btnEaseInOutQuart: TButton;
    btnEaseOutInCubic: TButton;
    btnEaseInQuart: TButton;
    btnEaseOutQuart: TButton;
    btnEaseInQuint: TButton;
    btnEaseOutQuint: TButton;
    btnEaseOutInQuint: TButton;
    btnEaseInOutQuint: TButton;
    btnEaseInSine: TButton;
    btnEaseOutSine: TButton;
    btnEaseInOutSine: TButton;
    btnEaseOutInSine: TButton;
    btnEaseInOutQuad: TButton;
    btnEaseOutInQuad: TButton;
    btnEaseInExpo: TButton;
    btnEaseInCirc: TButton;
    btnEaseInElastic: TButton;
    btnEaseInBack: TButton;
    btnEaseInBounce: TButton;
    btnEaseOutCirc: TButton;
    btnEaseOutElastic: TButton;
    btnEaseOutBack: TButton;
    btnEaseOutBounce: TButton;
    btnEaseOutExpo: TButton;
    btnLinear: TButton;
    btnEaseOutInCirc: TButton;
    btnEaseOutInElastic: TButton;
    btnEaseOutInBack: TButton;
    btnEaseOutInBounce: TButton;
    btnEaseInOutExpo: TButton;
    btnEaseInOutCirc: TButton;
    btnEaseInOutElastic: TButton;
    btnEaseInOutBack: TButton;
    btnEaseOutInExpo: TButton;
    btnEaseInOutBounce: TButton;
    pnlRight: TPanel;
    pnlLeft: TPanel;
    pnlBottom: TPanel;
    pnlMain: TPanel;
    Splitter1: TSplitter;
    tbarWait: TTrackBar;
    procedure btnEaseInOutQuadClick(Sender: TObject);
    procedure btnEaseInQuadClick(Sender: TObject);
    procedure btnEaseOutInQuadClick(Sender: TObject);
    procedure btnEaseOutQuadClick(Sender: TObject);
    procedure btnLinear2Click(Sender: TObject);
    procedure FormCreate(Sender: TObject);
    procedure tbarWaitChange(Sender: TObject);
  private
    fDuration: Cardinal;
    procedure SetDuration(AValue: Cardinal);
  public
    property Duration: Cardinal read fDuration write SetDuration default C_DefaultDuration;
    function ComputeInterpolation(AInter: TInterpolationFunction;
      AStart, AEnd, AStep: Single; ABack: Boolean = False):
      Single;
    function ComputeInterpolationInt(AInter: TInterpolationFunction; AStart, AEnd,
      AStep: Integer; ABack: Boolean = False): Integer;
  end;

var
  MainForm: TMainForm;

implementation

{$R *.lfm}

{ TMainForm }

procedure TMainForm.btnLinear2Click(Sender: TObject);
// *** lancement des animations ***
var
  Li, LWidth, LWidth2: Integer;
  LBack: Boolean;
begin
  tbarWait.Enabled := False;
  LWidth := pnlLeft.Width - btnLinear2.Width;
  LWidth2 := pnlRight.Width - btnLinear.Width;
  for LBack := False to True do
    for Li := 1 to Duration do
    begin
      btnLinear.Left := ComputeInterpolationInt(@EaseNone, 0, LWidth, Li, LBack);
      btnLinear2.Left := ComputeInterpolationInt(@EaseNone, 0, LWidth2, Li, LBack);

      btnEaseInQuad.Left := ComputeInterpolationInt(@EaseInQuad, 0, LWidth, Li, LBack);
      btnEaseOutQuad.Left := ComputeInterpolationInt(@EaseOutQuad, 0, LWidth, Li, LBack);
      btnEaseInOutQuad.Left := ComputeInterpolationInt(@EaseInOutQuad, 0, LWidth2, Li, LBack);
      btnEaseOutInQuad.Left := ComputeInterpolationInt(@EaseOutInQuad, 0, LWidth2, Li, LBack);

      btnEaseInCubic.Left := ComputeInterpolationInt(@EaseInCubic, 0, LWidth, Li, LBack);
      btnEaseOutCubic.Left := ComputeInterpolationInt(@EaseOutCubic, 0, LWidth, Li, LBack);
      btnEaseInOutCubic.Left := ComputeInterpolationInt(@EaseInOutCubic, 0, LWidth2, Li, LBack);
      btnEaseOutInCubic.Left := ComputeInterpolationInt(@EaseOutInCubic, 0, LWidth2, Li, LBack);

      btnEaseInQuart.Left := ComputeInterpolationInt(@EaseInQuart, 0, LWidth, Li, LBack);
      btnEaseOutQuart.Left := ComputeInterpolationInt(@EaseOutQuart, 0, LWidth, Li, LBack);
      btnEaseInOutQuart.Left := ComputeInterpolationInt(@EaseInOutQuart, 0, LWidth2, Li, LBack);
      btnEaseOutInQuart.Left := ComputeInterpolationInt(@EaseOutInQuart, 0, LWidth2, Li, LBack);

      btnEaseInQuint.Left := ComputeInterpolationInt(@EaseInQuint, 0, LWidth, Li, LBack);
      btnEaseOutQuint.Left := ComputeInterpolationInt(@EaseOutQuint, 0, LWidth, Li, LBack);
      btnEaseInOutQuint.Left := ComputeInterpolationInt(@EaseInOutQuint, 0, LWidth2, Li, LBack);
      btnEaseOutInQuint.Left := ComputeInterpolationInt(@EaseOutInQuint, 0, LWidth2, Li, LBack);

      btnEaseInSine.Left := ComputeInterpolationInt(@EaseInSine, 0, LWidth, Li, LBack);
      btnEaseOutSine.Left := ComputeInterpolationInt(@EaseOutSine, 0, LWidth, Li, LBack);
      btnEaseInOutSine.Left := ComputeInterpolationInt(@EaseInOutSine, 0, LWidth2, Li, LBack);
      btnEaseOutInSine.Left := ComputeInterpolationInt(@EaseOutInSine, 0, LWidth2, Li, LBack);

      btnEaseInExpo.Left := ComputeInterpolationInt(@EaseInExpo, 0, LWidth, Li, LBack);
      btnEaseOutExpo.Left := ComputeInterpolationInt(@EaseOutExpo, 0, LWidth, Li, LBack);
      btnEaseInOutExpo.Left := ComputeInterpolationInt(@EaseInOutExpo, 0, LWidth2, Li, LBack);
      btnEaseOutInExpo.Left := ComputeInterpolationInt(@EaseOutInExpo, 0, LWidth2, Li, LBack);

      btnEaseInCirc.Left := ComputeInterpolationInt(@EaseInCirc, 0, LWidth, Li, LBack);
      btnEaseOutCirc.Left := ComputeInterpolationInt(@EaseOutCirc, 0, LWidth, Li, LBack);
      btnEaseInOutCirc.Left := ComputeInterpolationInt(@EaseInOutCirc, 0, LWidth2, Li, LBack);
      btnEaseOutInCirc.Left := ComputeInterpolationInt(@EaseOutInCirc, 0, LWidth2, Li, LBack);

      btnEaseInElastic.Left := ComputeInterpolationInt(@EaseInElastic, 0, LWidth, Li, LBack);
      btnEaseOutElastic.Left := ComputeInterpolationInt(@EaseOutElastic, 0, LWidth, Li, LBack);
      btnEaseInOutElastic.Left := ComputeInterpolationInt(@EaseInOutElastic, 0, LWidth2, Li, LBack);
      btnEaseOutInElastic.Left := ComputeInterpolationInt(@EaseOutInElastic, 0, LWidth2, Li, LBack);

      btnEaseInBack.Left := ComputeInterpolationInt(@EaseInBack, 0, LWidth, Li, LBack);
      btnEaseOutBack.Left := ComputeInterpolationInt(@EaseOutBack, 0, LWidth, Li, LBack);
      btnEaseInOutBack.Left := ComputeInterpolationInt(@EaseInOutBack, 0, LWidth2, Li, LBack);
      btnEaseOutInBack.Left := ComputeInterpolationInt(@EaseOutInBack, 0, LWidth2, Li, LBack);

      btnEaseInBounce.Left := ComputeInterpolationInt(@EaseInBounce, 0, LWidth, Li, LBack);
      btnEaseOutBounce.Left := ComputeInterpolationInt(@EaseOutBounce, 0, LWidth, Li, LBack);
      btnEaseInOutBounce.Left := ComputeInterpolationInt(@EaseInOutBounce, 0, LWidth2, Li, LBack);
      btnEaseOutInBounce.Left := ComputeInterpolationInt(@EaseOutInBounce, 0, LWidth2, Li, LBack);

      sleep(10);
      Repaint;
      Application.ProcessMessages;
    end;
  tbarWait.Enabled := True;
end;

procedure TMainForm.btnEaseInQuadClick(Sender: TObject);
// *** fonctions IN ***
var
  Li, LWidth: Integer;
  LBack: Boolean;
begin
  tbarWait.Enabled := False;
  LWidth := pnlLeft.Width - btnLinear2.Width;
  for LBack := False to True do
    for Li := 1 to fDuration do
    begin
      btnLinear.Left := ComputeInterpolationInt(@EaseNone, 0, LWidth, Li, LBack);
      btnEaseInQuad.Left := ComputeInterpolationInt(@EaseInQuad, 0, LWidth, Li, LBack);
      btnEaseInCubic.Left := ComputeInterpolationInt(@EaseInCubic, 0, LWidth, Li, LBack);
      btnEaseInQuart.Left := ComputeInterpolationInt(@EaseInQuart, 0, LWidth, Li, LBack);
      btnEaseInQuint.Left := ComputeInterpolationInt(@EaseInQuint, 0, LWidth, Li, LBack);
      btnEaseInSine.Left := ComputeInterpolationInt(@EaseInSine, 0, LWidth, Li, LBack);
      btnEaseInExpo.Left := ComputeInterpolationInt(@EaseInExpo, 0, LWidth, Li, LBack);
      btnEaseInCirc.Left := ComputeInterpolationInt(@EaseInCirc, 0, LWidth, Li, LBack);
      btnEaseInElastic.Left := ComputeInterpolationInt(@EaseInElastic, 0, LWidth, Li, LBack);
      btnEaseInBack.Left := ComputeInterpolationInt(@EaseInBack, 0, LWidth, Li, LBack);
      btnEaseInBounce.Left := ComputeInterpolationInt(@EaseInBounce, 0, LWidth, Li, LBack);
      sleep(10);
      pnlLeft.Repaint;
      Application.ProcessMessages;
    end;
  tbarWait.Enabled := True;
end;

procedure TMainForm.btnEaseInOutQuadClick(Sender: TObject);
// *** fonctions INOUT ***
var
  Li, LWidth2: Integer;
  LBack: Boolean;
begin
  tbarWait.Enabled := False;
  LWidth2 := pnlRight.Width - btnLinear.Width;
  for LBack := False to True do
    for Li := 1 to fDuration do
    begin
      btnLinear2.Left := ComputeInterpolationInt(@EaseNone, 0, LWidth2, Li, LBack);
      btnEaseInOutQuad.Left := ComputeInterpolationInt(@EaseInOutQuad, 0, LWidth2, Li, LBack);
      btnEaseInOutCubic.Left := ComputeInterpolationInt(@EaseInOutCubic, 0, LWidth2, Li, LBack);
      btnEaseInOutQuart.Left := ComputeInterpolationInt(@EaseInOutQuart, 0, LWidth2, Li, LBack);
      btnEaseInOutQuint.Left := ComputeInterpolationInt(@EaseInOutQuint, 0, LWidth2, Li, LBack);
      btnEaseInOutSine.Left := ComputeInterpolationInt(@EaseInOutSine, 0, LWidth2, Li, LBack);
      btnEaseInOutExpo.Left := ComputeInterpolationInt(@EaseInOutExpo, 0, LWidth2, Li, LBack);
      btnEaseInOutCirc.Left := ComputeInterpolationInt(@EaseInOutCirc, 0, LWidth2, Li, LBack);
      btnEaseInOutElastic.Left := ComputeInterpolationInt(@EaseInOutElastic, 0, LWidth2, Li, LBack);
      btnEaseInOutBack.Left := ComputeInterpolationInt(@EaseInOutBack, 0, LWidth2, Li, LBack);
      btnEaseInOutBounce.Left := ComputeInterpolationInt(@EaseInOutBounce, 0, LWidth2, Li, LBack);
      sleep(10);
      pnlRight.Repaint;
      Application.ProcessMessages;
    end;
  tbarWait.Enabled := True;
end;

procedure TMainForm.btnEaseOutInQuadClick(Sender: TObject);
// *** fonctions OUTIN ***
var
  Li, LWidth2: Integer;
  LBack: Boolean;
begin
  tbarWait.Enabled := False;
  LWidth2 := pnlRight.Width - btnLinear.Width;
  for LBack := False to True do
    for Li := 1 to fDuration do
    begin
      btnLinear2.Left := ComputeInterpolationInt(@EaseNone, 0, LWidth2, Li, LBack);
      btnEaseOutInQuad.Left := ComputeInterpolationInt(@EaseOutInQuad, 0, LWidth2, Li, LBack);
      btnEaseOutInCubic.Left := ComputeInterpolationInt(@EaseOutInCubic, 0, LWidth2, Li, LBack);
      btnEaseOutInQuart.Left := ComputeInterpolationInt(@EaseOutInQuart, 0, LWidth2, Li, LBack);
      btnEaseOutInQuint.Left := ComputeInterpolationInt(@EaseOutInQuint, 0, LWidth2, Li, LBack);
      btnEaseOutInSine.Left := ComputeInterpolationInt(@EaseOutInSine, 0, LWidth2, Li, LBack);
      btnEaseOutInExpo.Left := ComputeInterpolationInt(@EaseOutInExpo, 0, LWidth2, Li, LBack);
      btnEaseOutInCirc.Left := ComputeInterpolationInt(@EaseOutInCirc, 0, LWidth2, Li, LBack);
      btnEaseOutInElastic.Left := ComputeInterpolationInt(@EaseOutInElastic, 0, LWidth2, Li, LBack);
      btnEaseOutInBack.Left := ComputeInterpolationInt(@EaseOutInBack, 0, LWidth2, Li, LBack);
      btnEaseOutInBounce.Left := ComputeInterpolationInt(@EaseOutInBounce, 0, LWidth2, Li, LBack);
      sleep(10);
      pnlRight.Repaint;
      Application.ProcessMessages;
    end;
  tbarWait.Enabled := True;
end;

procedure TMainForm.btnEaseOutQuadClick(Sender: TObject);
// *** fonctions OUT ***
var
  Li, LWidth: Integer;
  LBack: Boolean;
begin
  tbarWait.Enabled := False;
  LWidth := pnlLeft.Width - btnLinear2.Width;
  for LBack := False to True do
    for Li := 1 to fDuration do
    begin
      btnLinear.Left := ComputeInterpolationInt(@EaseNone, 0, LWidth, Li, LBack);

      btnEaseOutQuad.Left := ComputeInterpolationInt(@EaseOutQuad, 0, LWidth, Li, LBack);
      btnEaseOutCubic.Left := ComputeInterpolationInt(@EaseOutCubic, 0, LWidth, Li, LBack);
      btnEaseOutQuart.Left := ComputeInterpolationInt(@EaseOutQuart, 0, LWidth, Li, LBack);
      btnEaseOutQuint.Left := ComputeInterpolationInt(@EaseOutQuint, 0, LWidth, Li, LBack);
      btnEaseOutSine.Left := ComputeInterpolationInt(@EaseOutSine, 0, LWidth, Li, LBack);
      btnEaseOutExpo.Left := ComputeInterpolationInt(@EaseOutExpo, 0, LWidth, Li, LBack);
      btnEaseOutCirc.Left := ComputeInterpolationInt(@EaseOutCirc, 0, LWidth, Li, LBack);
      btnEaseOutElastic.Left := ComputeInterpolationInt(@EaseOutElastic, 0, LWidth, Li, LBack);
      btnEaseOutBack.Left := ComputeInterpolationInt(@EaseOutBack, 0, LWidth, Li, LBack);
      btnEaseOutBounce.Left := ComputeInterpolationInt(@EaseOutBounce, 0, LWidth, Li, LBack);
      sleep(10);
      pnlLeft.Repaint;
      Application.ProcessMessages;
    end;
  tbarWait.Enabled := True;
end;

procedure TMainForm.FormCreate(Sender: TObject);
// *** création de la fiche ***
begin
  Duration := C_DefaultDuration;
  tbarWait.Max := C_End;
  tbarWait.Position := fDuration;
end;

procedure TMainForm.tbarWaitChange(Sender: TObject);
// *** changement de la vitesse ***
begin
  Duration := tbarWait.Position;
end;

procedure TMainForm.SetDuration(AValue: Cardinal);
// *** détermination de la durée d'interpolation ***
begin
  if fDuration = AValue then
    Exit;
  fDuration := AValue;
end;

function TMainForm.ComputeInterpolation(AInter: TInterpolationFunction; AStart,
  AEnd, AStep: Single; ABack: Boolean): Single;
// *** calcul des interpolations ***
begin
  if AStep < 0 then
    Result := AStart
  else
  if AStep > Duration then
    Result := AEnd
  else
    Result := AInter(AStart, AEnd, fDuration, AStep);
  if ABack then
    Result := AEnd - Result;
end;

function TMainForm.ComputeInterpolationInt(AInter: TInterpolationFunction;
  AStart, AEnd, AStep: Integer; ABack: Boolean): Integer;
// *** interpolation entière ***
begin
  Result := Round(ComputeInterpolation(AInter, AStart, AEnd, AStep, ABack));
end;

end.

À l'exécution, le résultat est exactement le même que celui obtenu avec une inclusion dans la classe de la fiche principale du projet. Comme notre objectif était de créer des classes autonomes, nous n'irons pas plus loin dans l'exploration de cette voie qui privilégie la programmation structurée sans passer par des classes et des objets.

Si le titre de ce chapitre pouvait sembler ironique, la souplesse de Pascal qui accepte aussi bien une programmation séquentielle qu'une approche POO (Programmation Orientée Objet) permet à chacun de s'y retrouver et de ne pas forcément mettre en œuvre des outils lourds pour des résultats médiocres !

V. Conclusion

Vous avez aimé ce tutoriel ? Alors partagez-le en cliquant sur les boutons suivants : Viadeo Twitter Facebook Share on Google+   

  

Les sources présentées sur cette page sont libres de droits et vous pouvez les utiliser à votre convenance. Par contre, la page de présentation constitue une œuvre intellectuelle protégée par les droits d'auteur. Copyright © 2018 Gilles Vasseur. Aucune reproduction, même partielle, ne peut être faite de ce site ni de l'ensemble de son contenu : textes, documents, images, etc. sans l'autorisation expresse de l'auteur. Sinon vous encourez selon la loi jusqu'à trois ans de prison et jusqu'à 300 000 € de dommages et intérêts.