par , 14/01/2019 à 12h00 (3841 Affichages)
Pour les besoins du composant TGVTransition qui traite les transitions d'image à image, nous avons déjà présenté des éléments afin de créer des interpolations. Nous reprenons ci-après les formules empiriques qui ont accompagné ce projet dans sa forme initiale.
L'objectif d'une première fonction appelée Exponant était de renvoyer une valeur entre AStart et AEnd modifiée par la puissance AExp utilisée. Quelle que soit la valeur de AExp, nous obtenions une valeur comprise entre 0 et (AEnd - AStart).
Par exemple, si la puissance valait 1, nous étions en présence d'une progression linéaire : en effet, la différence entre AStart et AEnd était alors multipliée par le pas à la puissance 1 (elle était donc inchangée) puis divisée par 100 à la même puissance (donc par 100 inchangé encore une fois). Vous aurez reconnu la formule qui permet de calculer le simple pourcentage d'une valeur ! Pour des puissances supérieures à 1, nous nous retrouvions dans les cas étudiés dans le billet précédent.
Pseudo-code :
1 2 3 4 5 6 7 8 9
| AStart entier (valeur initiale de l'interpolation)
AEnd entier (valeur finale de l'interpolation)
AStep entier (pas/étape en cours)
fonction Exponant
paramètre en entrée : AExp entier
sortie : Result entier
Result = Valeur arrondie de (AStart - AEnd) multipliée par (AStep à la puissance AExp) divisée par (100 à la puissance AExp) |
En Pascal, nous avions :
1 2 3 4
| function Exponant(AExp: Byte): Integer;
begin
Result := Round((AEnd - AStart) * Power(AStep, AExp) / Power(100, AExp));
end; |
Une autre fonction nommée DownExponant permettait de donner l'illusion d'un ralentissement. Pour cela, il suffisait d'inverser les calculs de l'accélération positive par deux soustractions. En partant de (AEnd - AStart), nous arrivions progressivement à 0 :
1 2 3 4
| function DownExponant(AExp: Byte): Integer;
begin
Result := AEnd - AStart - Round((AEnd - AStart) * Power(100 - AStep, AExp) / Power(100, AExp));
end; |
Ces deux fonctions formaient la base des fonctions d'interpolation utilisées dont l'écriture se trouvait grandement simplifiée.
Les fonctions d'interpolation étaient elles-mêmes définies dans une énumération :
1 2 3 4 5
| type
TInterpolation = (intLinear, intQuadratic, intCubic, intQuartic, intQuintic,
intSinus, intSpring, intExpo, intSqrt, intSlowDownQuadratic, intSlowDownCubic,
intSlowDownQuartic, intSlowDownQuintic, intBounceCos, intStepsCos); |
Enfin, elles étaient traitées dans une méthode dont la structure comportait essentiellement un case of (choix...parmi) :
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19
| function ComputeInterpolation(AStart, AEnd: Integer; AStep: Integer;
AInter: TInterpolation; ABack: Boolean): Integer;
// *** calcul des interpolations ***
begin
case AInter of
intLinear: Result := Exponant(1);
intQuadratic: Result := Exponant(2);
intCubic: Result := Exponant(3);
intQuartic: Result := Exponant(4);
intQuintic: Result := Exponant(5);
// [...]
intSlowDownQuadratic: Result := DownExponant(2);
intSlowDownCubic: Result := DownExponant(3);
intSlowDownQuartic: Result := DownExponant(4);
intSlowDownQuintic: Result := DownExponant(5);
// [...]
end;
// [...]
end; |
Simplement, pour permettre un retour de AEnd vers AStart, un paramètre de type booléen ABack était utilisé à la toute fin de la même méthode :
1 2 3 4 5 6 7
|
intSlowDownQuintic: Result := DownExponant(5);
// [...]
end;
if ABack then
Result := AEnd - Result;
end; |
D'autres fonctions ont ensuite été ajoutées pour obtenir des effets variés.
Comme nous pouvions nous y attendre, la racine carrée ou les puissances de 2 produisaient des effets proches des puissances déjà vues. Elles les modulaient seulement avec leur propre progression.
Leur emploi dans le case of s'appuyait aussi sur la fonction Exponant :
1 2
| intExpo: Result := Round(Exponant(1) * (Power(2, AStep / 100) - 1));
intSqrt: Result := Round(Exponant(1) * (Sqrt(AStep) / 10)); |
Nous avions aussi adjoint des formules à base de fonctions trigonométriques. Leurs cycles permettaient en particulier d'envisager des effets de rebonds :
1 2 3 4 5 6 7 8 9 10 11 12
| case AInter of
// [...]
intSinus: Result := Round(Exponant(1) * sin(pi * AStep / 200));
intSpring: Result := Round(Exponant(1) * (Power(cos(pi * AStep / 100), 2)));
// [...]
intBounceCos: Result := Exponant(1) + Round((cos(AStep * pi / 100) + 1) * Exponant(1));
intStepsCos: Result := Exponant(1) + Round(Power((cos(AStep * pi / 100) + 1), 2) * 100);
intCos: Result := Round(Exponant(1) * (1 - cos(AStep / 100 * pi)) / 2);
intHalfCos: Result := Round(Exponant(1) * ((1 - cos(AStep /100 * Pi)) / 4 + AStep / 200));
end;
// [...]
end; |
Pour le moment, contentons-nous d'avoir un aperçu de ce que produisaient ces interpolations appliquées à de simples boutons :
Ce billet n'a fait que rappeler les outils créés de manière empirique pour l'écriture d'un composant particulier. Cependant, il montre qu'avec peu de moyens, nous pouvons créer des animations déjà sympathiques et variées.
Par la suite, il s'agira de formaliser cette approche en la rendant compatible avec celle qu'offrent CSS ou JavaScript par exemple (souvent via des bibliothèques complémentaires). A très bientôt !