[Cairo] Remplissage de polygones (perspective cavalière)
par , 12/03/2017 à 12h12 (1197 Affichages)
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 c : 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; }
Mis à jour 29/07/2018 à 19h09 par LittleWhite (Coloration du code)
- Catégories
- Programmation , C
« [GTK+ v3.0] Comment avoir un GtkGrid ressemblant à un tableur ?
Liste des billets
[Gtk+] Accéder à un pointeur d'un widget en tout point d'un programme »