GDI+B: Move et Zoom avec la souris

Description

Bonjour,

Comme annoncé, voici le deuxième article de la série "GDI±?: …" basée sur Microsoft Windows GDI.

Activé par la roulette de la souris, le zoom présenté ici est dit "intelligent", c'est-à-dire que l'endroit montré par le curseur reste fixe (centre du zoom).

Dans "GDI+A: Move avec la souris", j'ai utilisé "WorldTransform" (qui est en fait une transformation 2D affine complète).
Sauf avec une translation pure, cet outil semble également agir sur d'autres paramètres tels que hauteur d'un texte, épaisseur des lignes, etc.
Et cela n'est pas toujours désiré.

Utilisons donc une transformation explicite avec Xtrl,Ytrl pour la translation, et Dil pour la dilatation:
int Xtrl=0,Ytrl=0;
float Dil=1.0F; // x' = x*Dil + Xtrl; y' = y*Dil + Ytrl;
#define Tr2X(x) ((int)((x)*Dil) + Xtrl)
#define Tr2Y(y) ((int)((y)*Dil) + Ytrl)

Zoom "intelligent"

Condition: Avant et après (') le zoom, le point désigné par le curseur de la souris (xCur,yCur) ne bouge pas.

x*Dil + Xtrl = xCur = x*Dil' + Xtrl'; y*Dil + Ytrl = yCur = y*Dil' + Ytrl'
Le nouveau facteur de dilatation Dil' est facile à calculer:
Dil'=f*Dil
Extrayons x et y des premières équations:
x = (xCur-Xtrl)/Dil; y = (yCur-Ytrl)/Dil
Remplaçons x et y dans les secondes:
xCur = (xCur-Xtrl)*f + Xtrl'; yCur = (yCur-Ytrl)*f + Ytrl'
On peut en tirer Xtrl' et Ytrl':
Xtrl' = xCur - (xCur-Xtrl)*f; Ytrl' = yCur - (yCur-Ytrl)*f

Ce qui peut donner le code suivant:
LRESULT CALLBACK Wpro(HWND h,UINT m,WPARAM wP,LPARAM lP) {
  const float mulZoom=1.189207115F; // mulZoom = √√2 = 2^(1/4)
  static HDC hdc;
  static bool move=false;
  static int xCur=0,yCur=0;
  PAINTSTRUCT ps;

  switch(m) {
  case WM_LBUTTONDOWN: move=true; return 0;
  case WM_MOUSEMOVE:
    if (move) {
      Xtrl+=LOWORD(lP)-xCur; Ytrl+=HIWORD(lP)-yCur;
      InvalidateRect(h,0,TRUE); // force à redessiner
    }
    xCur=LOWORD(lP); yCur=HIWORD(lP); return 0;
  case WM_MOUSEWHEEL: {
    float f=((short)HIWORD(wP)<=0)?mulZoom:1.0F/mulZoom;
    Dil*=f; Xtrl=xCur-(int)((xCur-Xtrl)*f); Ytrl=yCur-(int)((yCur-Ytrl)*f);
    InvalidateRect(h,0,TRUE); // force à redessiner
  } return 0;
  case WM_LBUTTONUP: move=false; return 0;
  case WM_PAINT: hdc=BeginPaint(h,&ps); Paint(hdc); EndPaint(h,&ps); return 0;
  case WM_CLOSE: DestroyWindow(h); return 0;
  case WM_DESTROY: PostQuitMessage(0); return 0;
  }
  return DefWindowProc(h,m,wP,lP);
}
Pour inverser le "sens" du zoom, remplacez dans case WM_MOUSEWHEEL le <= par >.

Remarque:
Pour un texte, l'endroit qui obéit correctement au zoom est le point initial: deuxième et troisième paramètre de TextOut(hdc,x,y,...).
Par contre, ce n'est en général pas le cas pour la fin du texte.

Lien GDI±?:
GDI+A: Déplacement avec la souris

Autres liens:
CodeS-SourceS: Photos plein écran (full screen picture viewer)
CodeS-SourceS: Canvas: Move et Zoom avec la Souris

Bonne lecture ...

Codes Sources

A voir également

Vous n'êtes pas encore membre ?

inscrivez-vous, c'est gratuit et ça prend moins d'une minute !

Les membres obtiennent plus de réponses que les utilisateurs anonymes.

Le fait d'être membre vous permet d'avoir un suivi détaillé de vos demandes et codes sources.

Le fait d'être membre vous permet d'avoir des options supplémentaires.