Voir le flux RSS

gerald3d

[Cairo] Remplissage de polygones (perspective cavalière)

Noter ce billet
par , 12/03/2017 à 11h12 (223 Affichages)
Citation Envoyé par gerald3d Voir le message
Je vous livre en pâture la fonction qui permet de mapper un parallélogramme. Elle a quelques contraintes mais elle répond exactement à mes besoins.

Code : Sélectionner tout - Visualiser dans une fenêtre à part
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
/* Fonction de mapping d'un parallélogramme.
 *
 * Les points A, B, C, D doivent être disposés de la sorte :
 *
 *                                 B                    A        
 *                   A                                                B
 *                                            ou
 *                                 C                    D
 *                   D                                                C
 *
 * Vous pouvez aussi utiliser cette fonction pour mapper un
 * rectangle.
 *
 * Cette fonction renvoie NULL si src est NULL, si le parallélogramme
 * représente une simple ligne verticale ou si les points AD
 * ou les points BC ne sont pas alignés verticalement.
 *
 * src : GdkPixbuf original utilisé comme texture à mapper
 * A, B, C, D : sommets du parallelogramme
 *
 * Renvoie un GdkPixbuf nouvellement créé.
 */
GdkPixbuf*
gdk_pixbuf_perspective_new (const GdkPixbuf *src, GdkPoint A, GdkPoint B, GdkPoint C, GdkPoint D)
{
  if (!src)
    {
      g_printerr ("Error in gdk_pixbuf_perspective_new (); !\n src must be not NULL !\n");
      return NULL;
    }

  if (A.x-B.x==0)
    {
      g_printerr ("Error in gdk_pixbuf_perspective_new (); !\n A and B points are vertical aligned !\n");
      return NULL;
    }

  if (A.x!=D.x || B.x!=C.x)
    {
      g_printerr ("Error in gdk_pixbuf_perspective_new (); !\n A and D or B and C points are not vertical aligned !\n");
      return NULL;
    }

  // Les points AB et CD sont inversés
  if (A.x>B.x)
    {
      GdkPoint tmp;

      tmp.x = A.x; tmp.y = A.y;
      A.x = B.x; A.y = B.y;
      B.x = tmp.x; B.y = tmp.y;

      tmp.x = C.x; tmp.y = C.y;
      C.x = D.x; C.y = D.y;
      D.x = tmp.x; D.y = tmp.y;
    }
  
  guchar *pixels = gdk_pixbuf_get_pixels (src);
  gint rowstride = gdk_pixbuf_get_rowstride (src);
  guchar channels = gdk_pixbuf_get_n_channels (src);
  gint width = gdk_pixbuf_get_width (src);
  gint height = gdk_pixbuf_get_height (src);
  gdouble scalex, scaley;
  gint x, y;
  gint targety;
  GdkPoint Orig; // Coordonnées dans l'image originale
  GdkPixbuf *TargetPixbuf;
  gint xmax, ymax;  // Limites du boundingbox 2D
  gdouble a, b; // coefficient de droite entre les points A et B

  // Calcul des coefficients
  a = (A.y - B.y) / (gdouble)(A.x - B.x);
  b = ((B.y*A.x) - (B.x*A.y)) / (gdouble)(A.x - B.x);

  // Calcul du boundingbox
  xmax = A.x;
  if (B.x>xmax) xmax = B.x;
  if (C.x>xmax) xmax = C.x;
  if (D.x>xmax) xmax = D.x;

  ymax = A.y;
  if (B.y>ymax) ymax = B.y;
  if (C.y>ymax) ymax = C.y;
  if (D.y>ymax) ymax = D.y;
  
  TargetPixbuf = gdk_pixbuf_new (GDK_COLORSPACE_RGB, TRUE, 8, xmax, ymax);
  guchar *TargetPixels = gdk_pixbuf_get_pixels (TargetPixbuf);
  gint TargetRowstride = gdk_pixbuf_get_rowstride (TargetPixbuf);
  gint TargetChannels = gdk_pixbuf_get_n_channels (TargetPixbuf);

  // Effacement complet du nouveau pixbuf créé
  memset(TargetPixels, 0, TargetRowstride * (D.y - A.y));
  
  Orig.x = 0; Orig.y = 0; // Coordonnées dans l'image originale
  scalex = (B.x-A.x) / (gdouble)width; // Rapport d'échelle sur l'axe des x entre l'image source et l'image cible
  scaley = (D.y - A.y) / (gdouble)height; // Rapport d'échelle sur l'axe des y entre l'image source et l'image cible

  // Création du pixbuf cible
  for (y=0; y<(D.y-A.y); y++)
    {
      Orig.y = (gint)(y / scaley);

      for (x=0; x<(B.x-A.x); x++)
	{
	  Orig.x = (gint)(x / scalex);
	  targety = y + a*x + b;

	  TargetPixels[(x * TargetChannels) + (targety * TargetRowstride)] = pixels [(Orig.x * channels) + (Orig.y * rowstride)];
	  TargetPixels[(x * TargetChannels) + (targety * TargetRowstride) + 1] = pixels [(Orig.x * channels) + (Orig.y * rowstride) + 1];
	  TargetPixels[(x * TargetChannels) + (targety * TargetRowstride) + 2] = pixels [(Orig.x * channels) + (Orig.y * rowstride) + 2];
	  if (gdk_pixbuf_get_has_alpha (src))
	    TargetPixels[(x * TargetChannels) + (targety * TargetRowstride) + 3] = pixels [(Orig.x * channels) + (Orig.y * rowstride) + 3];
	  else
	    TargetPixels[(x * TargetChannels) + (targety * TargetRowstride) + 3] = 255;
	}
    }

  return TargetPixbuf;
}

Envoyer le billet « [Cairo] Remplissage de polygones (perspective cavalière) » dans le blog Viadeo Envoyer le billet « [Cairo] Remplissage de polygones (perspective cavalière) » dans le blog Twitter Envoyer le billet « [Cairo] Remplissage de polygones (perspective cavalière) » dans le blog Google Envoyer le billet « [Cairo] Remplissage de polygones (perspective cavalière) » dans le blog Facebook Envoyer le billet « [Cairo] Remplissage de polygones (perspective cavalière) » dans le blog Digg Envoyer le billet « [Cairo] Remplissage de polygones (perspective cavalière) » dans le blog Delicious Envoyer le billet « [Cairo] Remplissage de polygones (perspective cavalière) » dans le blog MySpace Envoyer le billet « [Cairo] Remplissage de polygones (perspective cavalière) » dans le blog Yahoo

Mis à jour 12/03/2017 à 11h25 par gerald3d

Catégories
Sans catégorie

Commentaires