COMPOSANT THORLOGE

Bacterius Messages postés 3792 Date d'inscription samedi 22 décembre 2007 Statut Membre Dernière intervention 3 juin 2016 - 4 mars 2010 à 12:40
f0xi Messages postés 4205 Date d'inscription samedi 16 octobre 2004 Statut Modérateur Dernière intervention 12 mars 2022 - 8 mars 2010 à 23:45
Cette discussion concerne un article du site. Pour la consulter dans son contexte d'origine, cliquez sur le lien ci-dessous.

https://codes-sources.commentcamarche.net/source/51381-composant-thorloge

f0xi Messages postés 4205 Date d'inscription samedi 16 octobre 2004 Statut Modérateur Dernière intervention 12 mars 2022 35
8 mars 2010 à 23:45
conclusions :

au final, dans la méthode Paint, seul reste, à part la convertion du temps en degré que l'on aurait également pus mettre en cache aussi (puisque ce sont des valeurs connues d'avance dans un interval connus lui aussi), les positions sont reduite à de simple additions!
au final on à supprimer de nombreux appels a Sinus et Cosinus et de nombreuses multiplications qui ralentissent les boucles et les méthodes.
f0xi Messages postés 4205 Date d'inscription samedi 16 octobre 2004 Statut Modérateur Dernière intervention 12 mars 2022 35
8 mars 2010 à 23:34
tout a fait, un exemple :

unit UDrawTime;

interface

uses
Windows, Messages, SysUtils, Variants, Classes, Graphics, Controls, Forms,
Dialogs, ExtCtrls;

type
TForm31 = class(TForm)
Timer1: TTimer;
PaintBox1: TPaintBox;
procedure Timer1Timer(Sender: TObject);
procedure PaintBox1Paint(Sender: TObject);
procedure FormCreate(Sender: TObject);
private
{ Déclarations privées }
public
{ Déclarations publiques }
end;

var
Form31: TForm31;

implementation

{$R *.dfm}

const
DTR = PI/180; // Degre to radian
iSin = 0; // sin index
iCos = 1; // cos index

var
// Sin cos cache ( 2 880 octets)
SinCos : array[iSin..iCos, 0..359] of single;

// Positions cache (4 * 2 880 octets (11 520 octets))
PointsOfRayBig, // Aiguille secondes
PointsOfRayBigIv, // Aiguille secondes (arrière)
PointsOfRayMedium, // Aiguille minutes
PointsOfRaySmall : array[0..359] of TPoint; // Aiguille heures

// les caches prennent un peu de mémoire, cela est necessaire pour gagner les
// cycles dans l'animation. au total 14.4Ko seront necessaire (ridicule) pour
// un gains de performance non négligeable.

// pré-calculs
procedure Precalculus;
var A : integer;
begin
// les Sinus et cosinus, on pourrait aussi utiliser la fonction
// Math.SinCos qui est un chouille plus rapide, mais comme il s'agit
// ici de pré-calculs éfféctués au démarrage de l'application,
// le gains des quelques cycles n'est pas trés important.
for A := 0 to 359 do
begin
SinCos[iSin, A] := Sin(DTR * (A-90)); // A-90 pour corriger l'angle de
SinCos[iCos, A] := Cos(DTR * (A-90)); // départ des aiguilles.
end;

// Les points, on calcul les positions avec nos rayons
// prédéfinit. Dans un objet, on mettrait à jours ces
// calculs uniquement quand l'utilisateur/développeur
// modifierai un des rayons, bien entendus, il faudrait
// 3 méthode (PCBig, PCMedium, PCSmall) en changeant
// réspectivement les rayons Heure, Minute, Seconde,
// et également la taille (Resize) du composant.
// ici les rayons pourrait être un % de la taille :
// round(Width * 0.48 * SinCos[...]) = rayon de 48% de
// la taille du composant.
for A := 0 to 359 do
begin
PointsOfRayBig[A].X := round(80 * SinCos[iCos, A]);
PointsOfRayBig[A].Y := round(80 * SinCos[iSin, A]);

// -180° = position inverse, mod 360 pour ne pas dépasser l'interval
// 0..359.
PointsOfRayBigIv[(A - 180) mod 360].X := round(10 * SinCos[iCos, A]);
PointsOfRayBigIv[(A - 180) mod 360].Y := round(10 * SinCos[iSin, A]);

PointsOfRayMedium[A].X := round(60 * SinCos[iCos, A]);
PointsOfRayMedium[A].Y := round(60 * SinCos[iSin, A]);

PointsOfRaySmall[A].X := round(40 * SinCos[iCos, A]);
PointsOfRaySmall[A].Y := round(40 * SinCos[iSin, A]);

end;
end;

{ Procedure de dessin de l'horloge

parametres :
Canvas : le canvas de destination pour le dessin de l'horloge
H, M, S : heure (0..11 ou 0..23), minute et seconde (0..59) de l'heure à afficher.
CX, CY : position centrale X et Y de l'horloge sur le canvas
}
procedure DrawTime(Canvas: TCanvas; const H, M, S: byte; const CX, CY: integer);
var
vH, vM, vS : integer;
vBuffer : TBitmap;
begin
// on transforme le Temps en Degrés! BWAHAHAHA!
vH := trunc(360 * (((H mod 12)*60+M)/720)); // on transforme les heures en minutes
vM := trunc(360 * (M/60));
vS := trunc(360 * (S/60));

// back buffer ...
// what that bidule ?
// le back buffer permet de dessiner "hors affichage", ce qui est plus performant
// avec la GDI. on transmet le back buffer uniquement à la fin, on parlera ici de
// rendu software, ce que la carte graphique fait en hardware de façon naturelle.
// mais la GDI n'etant pas supportée en hardware, appliquer ce principe en mode
// software permet de grapiller encore de la fluidité.
vBuffer := TBitmap.Create;
try
vBuffer.Width := 160;
vBuffer.Height:= 160;
vBuffer.PixelFormat := pf32bit;

vBuffer.Canvas.Brush.Color := clBtnFace;
vBuffer.Canvas.FillRect(vBuffer.Canvas.ClipRect);

// le cadre
vBuffer.Canvas.Pen.Color := clBlack;
vBuffer.Canvas.Ellipse(0, 0, 159, 159);

// les minutes
vBuffer.Canvas.Pen.Width := 3;
vBuffer.Canvas.MoveTo(80, 80);
vBuffer.Canvas.LineTo(80+PointsOfRayMedium[vM].X, 80+PointsOfRayMedium[vM].Y);

// les heures
vBuffer.Canvas.Pen.Width := 2;
vBuffer.Canvas.MoveTo(80, 80);
vBuffer.Canvas.LineTo(80+PointsOfRaySmall[vH].X, 80+PointsOfRaySmall[vH].Y);

// les secondes
vBuffer.Canvas.Pen.Width := 1;
vBuffer.Canvas.Pen.Color := clRed;
vBuffer.Canvas.MoveTo(80, 80);
vBuffer.Canvas.LineTo(80+PointsOfRayBig[vS].X, 80+PointsOfRayBig[vS].Y);
vBuffer.Canvas.MoveTo(80, 80);
vBuffer.Canvas.LineTo(80+PointsOfRayBigIv[vS].X, 80+PointsOfRayBigIv[vS].Y);

// dessin sur le canvas transmit
Canvas.Draw(CX-80, CY-80, vBuffer);
finally
vBuffer.Free;
end;
end;

procedure TForm31.FormCreate(Sender: TObject);
begin
// 250ms, largement suffisant ici
Timer1.Interval := 250;
end;

procedure TForm31.PaintBox1Paint(Sender: TObject);
var H, M, S, Z: word;
begin
// on decode l'heure courrante
DecodeTime(Now, H, M, S, Z);
// on appel la methode de dessin
DrawTime(PaintBox1.Canvas, H, M, S, PaintBox1.Width div 2, PaintBox1.Height div 2);
end;

procedure TForm31.Timer1Timer(Sender: TObject);
begin
// timer 1 sert uniquement à rafraichir le dessin
PaintBox1.Invalidate;
end;

// éxécuté au l'initialisation de l'unité
initialization
// les précalculs.
Precalculus;

end.
cs_Michel34 Messages postés 79 Date d'inscription samedi 28 décembre 2002 Statut Membre Dernière intervention 27 juin 2011
8 mars 2010 à 22:06
Salut Bacterius , d'accord pour apprendre et comprendre , pouvez vous mettre les grosses lignes pour que je puisse etudier laformule.
Merci et bonne soirée .
Bacterius Messages postés 3792 Date d'inscription samedi 22 décembre 2007 Statut Membre Dernière intervention 3 juin 2016 10
8 mars 2010 à 19:49
Calculer un sinus et un cosinus, ça fait mal à l'ordinateur (ça coute cher). C'est pourquoi en général on les calcule une bonne fois pour toute et on les lit dans une table. Ca fait gagner des performances :)

Cordialement, Bacterius !
cs_Michel34 Messages postés 79 Date d'inscription samedi 28 décembre 2002 Statut Membre Dernière intervention 27 juin 2011
8 mars 2010 à 19:07
Salut a tous ,j'ai demandé des infos a Thierry William sur ce sujet , et je m'y suis mis , pour ce qui est des optimisations , je ne comprend pas ce que tu me demande Foxi ,pourquoi mettre en cache les sinus et cosinus ?, j'aurais plutot essayé de trouver mieux pour ma grille de TPoints pour avoir plus de choix de polygones sans avoir une usine a gaz.
si quelqu'un a un code simple pour faire un degrade , je suis preneur.

A + ,sur le site.
Bacterius Messages postés 3792 Date d'inscription samedi 22 décembre 2007 Statut Membre Dernière intervention 3 juin 2016 10
8 mars 2010 à 11:27
Salut,
ca ne devrait pas être trop difficile à implémenter, Edisson :)
Si Christophe a du temps, il pourra certainement t'arranger ça en mettant à jour la source.

Cordialement, Bacterius !
edisson81 Messages postés 5 Date d'inscription mercredi 12 janvier 2005 Statut Membre Dernière intervention 22 juillet 2010
8 mars 2010 à 11:19
Très bon code. Est-il possible de mettre une image au fond de l'horloge ?
f0xi Messages postés 4205 Date d'inscription samedi 16 octobre 2004 Statut Modérateur Dernière intervention 12 mars 2022 35
4 mars 2010 à 22:12
pas mal, on vas pouvoir passer à l'optimisation :

précalcul et Sin et Cos en cache, amélioration des conventions de code, et d'autres trucs par ci par la.
cs_Michel34 Messages postés 79 Date d'inscription samedi 28 décembre 2002 Statut Membre Dernière intervention 27 juin 2011
4 mars 2010 à 18:09
@ Bacterius

Salut et merci pour tes encouragements ,
Pour l'histoire des F , j'avais mapropre conception V pour variable , F Pour Fiche , U pour Unite Etc ...
mais je vais m'ameliorer et faire ce qui ressemble a du Bon sens , c'est a dire uniformiser pour etre mieux compris.
Pour la suite tu comprend maintenant ma question sur le forum pour le TLabel (dans mon compos c'est TTexte), je n'arrive pas
a ecrire les textes dansla fonte que je veut, pour l'anti-Aliesing je me penche dessus , et d'ailleur j'ai regarde le compo
TZSimage , et ca m'a donné une idée d'habiller le Fond de l'horloge avec l'image de son choix.
Merci encore.
Bacterius Messages postés 3792 Date d'inscription samedi 22 décembre 2007 Statut Membre Dernière intervention 3 juin 2016 10
4 mars 2010 à 12:40
J'aime bien le rendu. Pour un encore meilleur rendu, tu peux considérer d'anti-aliaser (lisser) les bords des aiguilles, ça fera moins saccadé quand l'aiguille des minutes bouge.

En revanche, dans MDClock.pas, :/
Bon j'ai déjà mentionné la convention en F dans le forum, ensuite, un rapide truc :
- quand tu modifies des champs objet à l'aide des Set, par convention on vérifie que la propriété a effectivement changé pour éviter que le composant ne se redessine pour rien.

Pour le reste, je n'ai pas encore regardé en détail. Je pense qu'il y a moyen d'optimiser, mais ça part d'une bonne idée est le rendu est là (en général, quand on a le rendu, on est plus enclin à refaire le code mieux que si l'on avait pas le résultat).

Cordialement, Bacterius !
Rejoignez-nous