2 * \file lib_snake_common.c
3 * \brief routines de bases pour la gestion du snake
6 * \date 25 decembre 2009
12 #include "lib_snake_common.h"
13 #include "lib_contour.h"
19 #include "lib_images.h"
20 #include "lib_alloc.h"
24 * \fn struct snake_node* genere_snake_rectangle_bords(int *nb_noeud, int distance_bords,
25 * int i_dim, int j_dim)
27 * \brief Initialise un snake rectangulaire par rapport au bords de l'image
30 * \param[out] nb_noeud renvoie le nombre de node du snake
31 * \param[in] distance_bords distance du rectangle par rapport au bords
32 * \param[in] i_dim dimension verticale de l'image
33 * \param[in] j_dim dimension horizontale de l'image
35 * \return le pointeur du premier noeud du snake
37 * note : les calculs sse necessite l'alignement memoire des snake_node
39 struct snake_node* genere_snake_rectangle_bords(uint32 *nb_noeud, uint32 distance_bords,
40 uint32 i_dim, uint32 j_dim)
42 struct snake_node *n1, *n2, *n3 ; /* noeuds courant */
43 struct snake_node *n0 = malloc(sizeof(struct snake_node)) ;
47 n0->posi = distance_bords ;
48 n0->posj = distance_bords ;
49 n0->noeud_suiv = malloc(sizeof(struct snake_node)) ;
53 n1->posi = i_dim - distance_bords ;
54 n1->posj = distance_bords ;
56 n1->noeud_suiv = malloc(sizeof(struct snake_node)) ;
60 n2->posi = i_dim - distance_bords ;
61 n2->posj = j_dim - distance_bords ;
63 n2->noeud_suiv = malloc(sizeof(struct snake_node)) ;
67 n3->posi = distance_bords ;
68 n3->posj = j_dim - distance_bords ;
70 n3->noeud_suiv = n0 ; /* on ferme le snake */
71 /* n0, on ferme le snake */
78 * \fn struct snake_node* genere_snake_rectangle(int *nb_noeud,int i1,int j1,int i2,int j2,
79 * int i_dim, int j_dim)
81 * \brief Initialise un snake rectangulaire definie par deux noeuds
84 * \param[out] nb_noeud renvoie le nombre de node du snake
85 * \param[in] i1 coordonnee du coin haut-gauche
86 * \param[in] j1 coordonnee du coin haut-gauche
87 * \param[in] i2 coordonnee du coin bas-droit
88 * \param[in] j2 coordonnee du coin bas-droit
89 * \param[in] i_dim dimension verticale de l'image
90 * \param[in] j_dim dimension horizontale de l'image
92 * \return le pointeur du premier noeud du snake
94 * note : les calculs sse necessite l'alignement memoire des snake_node
96 struct snake_node* genere_snake_rectangle(int *nb_noeud, uint32 i1, uint32 j1, uint32 i2, uint32 j2,
97 uint32 i_dim, uint32 j_dim)
99 struct snake_node *n1, *n2, *n3 ; /* noeuds courant */
100 struct snake_node *n0 = malloc(sizeof(struct snake_node)) ;
106 n0->noeud_suiv = malloc(sizeof(struct snake_node)) ;
109 n1 = n0->noeud_suiv ;
112 n1->noeud_prec = n0 ;
113 n1->noeud_suiv = malloc(sizeof(struct snake_node)) ;
116 n2 = n1->noeud_suiv ;
119 n2->noeud_prec = n1 ;
120 n2->noeud_suiv = malloc(sizeof(struct snake_node)) ;
123 n3 = n2->noeud_suiv ;
126 n3->noeud_prec = n2 ;
127 n3->noeud_suiv = n0 ; /* on ferme le snake */
128 /* n0, on ferme le snake */
129 n0->noeud_prec = n3 ;
140 * \fn int affiche_snake(int **image, struct snake_node *snake,
141 * int valseg, int valnoeud, int *liste_pixel_segment)
143 * \brief Affiche le snake sur une image N&B
146 * \param[out] image image ou le snake doit etre affiche
147 * \param[in] snake premier noeud du snake
148 * \param[in] valseg valeur de niveau de gris des segments
149 * \param[in] valnoeud valeur de niveau de gris des noeuds
150 * \param[out] liste_pixel_segment pour caluls temporaire
152 * \return nb_noeud le nombre de noeuds du snake
155 void affiche_snake(int **image, struct snake_node *snake, int valseg, int valnoeud,
156 uint32 *liste_pixel_segment)
158 uint32 i1, j1, i2, j2 ;
159 uint32 n, nb_pixel_segment ;
160 struct snake_node *np, *npp1 ;
164 npp1 = snake->noeud_suiv ;
167 i1 = np->posi ; j1 = np->posj ;
168 i2 = npp1->posi ; j2 = npp1->posj ;
170 nb_pixel_segment = calcul_liste_pixel_segment(i1,j1,i2,j2, liste_pixel_segment, 0) ;
171 for (n=1; n<nb_pixel_segment-1; n++)
172 image[liste_pixel_segment[2*n]][liste_pixel_segment[2*n+1]] = valseg ;
175 npp1 = np->noeud_suiv ;
177 while (np != snake) ;
179 /* les deux noeuds */
181 npp1 = snake->noeud_suiv ;
184 i1 = np->posi ; j1 = np->posj ;
185 i2 = npp1->posi ; j2 = npp1->posj ;
187 image[i1][j1] = valnoeud ;
188 image[i2][j2] = valnoeud ;
191 npp1 = np->noeud_suiv ;
193 while (np != snake) ;
196 void affiche_snake_ushort(unsigned short **image, struct snake_node *snake, int valseg, unsigned short valnoeud,
197 uint32 *liste_pixel_segment)
199 uint32 i1, j1, i2, j2 ;
200 uint32 n, nb_pixel_segment ;
201 struct snake_node *np, *npp1 ;
205 npp1 = snake->noeud_suiv ;
209 i1 = np->posi ; j1 = np->posj ;
210 i2 = npp1->posi ; j2 = npp1->posj ;
212 nb_pixel_segment = calcul_liste_pixel_segment(i1,j1,i2,j2, liste_pixel_segment, 0) ;
214 for (n=1; n<nb_pixel_segment-1; n++)
215 image[liste_pixel_segment[2*n]][liste_pixel_segment[2*n+1]] = valseg ;
218 npp1 = np->noeud_suiv ;
221 while (np != snake) ;
223 /* les deux noeuds */
225 npp1 = snake->noeud_suiv ;
229 i1 = np->posi ; j1 = np->posj ;
230 i2 = npp1->posi ; j2 = npp1->posj ;
232 image[i1][j1] = valnoeud ;
233 image[i2][j2] = valnoeud ;
236 npp1 = np->noeud_suiv ;
238 while (np != snake) ;
242 /* ========== DEBUG ================= */
243 /* fonction d'affichage pour le debug */
244 /* affiche les deux premiers segments avec valseg-1 */
245 /* et incremenent les valeurs des noeuds */
246 void affiche_snake_couleur(int **image, struct snake_node *snake, int valseg, int valnoeud,
247 uint32 *liste_pixel_segment)
249 uint32 i1, j1, i2, j2 ;
250 uint32 n, nb_pixel_segment ;
251 struct snake_node *np, *npp1 ;
253 snake = snake->noeud_prec ;
257 npp1 = np->noeud_suiv ;
260 i1 = np->posi ; j1 = np->posj ;
261 i2 = npp1->posi ; j2 = npp1->posj ;
263 nb_pixel_segment = calcul_liste_pixel_segment(i1,j1,i2,j2, liste_pixel_segment, 0) ;
265 for (n=1; n<nb_pixel_segment-1; n++)
266 image[liste_pixel_segment[2*n]][liste_pixel_segment[2*n+1]] = valseg-1 ;
268 for (n=1; n<nb_pixel_segment-1; n++)
269 image[liste_pixel_segment[2*n]][liste_pixel_segment[2*n+1]] = valseg ;
273 npp1 = np->noeud_suiv ;
275 while (np != snake) ;
277 /* les deux noeuds */
280 npp1 = snake->noeud_suiv ;
283 i1 = np->posi ; j1 = np->posj ;
284 i2 = npp1->posi ; j2 = npp1->posj ;
286 image[i1][j1] = valnoeud+cpt ;
287 image[i2][j2] = valnoeud+cpt++ ;
290 npp1 = np->noeud_suiv ;
292 while (np != snake) ;
295 /* ========= DEBUG ===================== */
296 /* copie l'image du snake avec un numero */
297 /* de fichier incremente a chaque appel */
298 void debug_aff_snake(struct snake_node *snake)
300 const int idim=256, jdim=256 ;
302 int **image = new_matrix_int(idim, jdim) ;
303 uint32 *liste_pixel = malloc(sizeof(int)*2*(idim+jdim)) ;
308 for (n=0; n<idim*jdim; n++)
311 affiche_snake_couleur(image, snake, 255, 0, liste_pixel) ;
312 sprintf(output, "debug_im%.4d.pgm", iter++) ;
313 write_int2pgm(image, idim, idim, output, 0) ;
315 del_matrix_int(image, idim);
323 * \fn int ajout_noeud_snake(struct snake_node *node, int *nb_noeud)
324 * \brief ajout un noeud au snake
327 * \param[in] node adresse du noeud
328 * \param[out] nb_noeud nombre de noeuds du snake
330 * \return le pointeur du nouveau noeud si ajout reussi, NULL sinon
332 * Ajout d'un noeud au millieu du segment.
333 * !!! Pour algo rapide, cette fonction doit etre suivie
334 * d'une mise a jour des contrib des noeuds qui conviennent !!!
337 struct snake_node* ajout_noeud_snake(struct snake_node *node, uint32 *nb_noeud)
339 struct snake_node *najout ;
341 najout = malloc(sizeof(struct snake_node)) ;
343 najout->posi = node->centre_i ;
344 najout->posj = node->centre_j ;
346 najout->noeud_prec = node ;
347 najout->noeud_suiv = node->noeud_suiv ;
348 node->noeud_suiv->noeud_prec = najout ;
349 node->noeud_suiv = najout ;
359 * \fn inline int test_croisement_segment_large(int Ai, int Aj, int Bi, int Bj,
360 * int Ui, int Uj, int Vi, int Vj)
362 * \brief Test qui determine si deux segments croisent
374 * \return 1 si croisement, 0 sinon
376 * Version large : autorise les triangles nulles
377 * Test de croisement des segments :
378 * si deux segments AB et UV croisent, alors
379 * les triangles ABU et ABV change d'ordre de rotation
381 * les triangles UVA et UVB change aussi d'ordre de rotation
384 inline int test_croisement_segment_large(uint32 Ai, uint32 Aj, uint32 Bi, uint32 Bj,
385 uint32 Ui, uint32 Uj, uint32 Vi, uint32 Vj)
387 if (sign_diff_strict(sinus_triangle(Ai, Aj, Bi, Bj, Ui, Uj), // Bi-Ai, Uj-Aj, Ui-Ai, Bj-Aj
388 sinus_triangle(Ai, Aj, Bi, Bj, Vi, Vj))) // Bi-Ai, Vj-Aj, Vi-Ai, Bj-Aj
389 if (sign_diff_strict(sinus_triangle(Ui, Uj, Vi, Vj, Ai, Aj), // Vi-Ui, Aj-Uj, Ai-Ui, Vj-Uj
390 sinus_triangle(Ui, Uj, Vi, Vj, Bi, Bj))) // Vi-Ui, Bj-Uj, Bi-Ui, Vj-Uj
397 * \fn inline int test_croisement_segment_strict(int Ai, int Aj, int Bi, int Bj,
398 * int Ui, int Uj, int Vi, int Vj)
400 * \brief Test qui determine si deux segments croisent
412 * \return 1 si croisement, 0 sinon
414 * Version strict : n'autorise pas les triangles nulles
415 * Test de croisement des segments :
416 * si deux segments AB et UV croisent, alors
417 * les triangles ABU et ABV change d'ordre de rotation
419 * les triangles UVA et UVB change aussi d'ordre de rotation
422 inline int test_croisement_segment_strict(uint32 Ai, uint32 Aj, uint32 Bi, uint32 Bj,
423 uint32 Ui, uint32 Uj, uint32 Vi, uint32 Vj)
425 if (sign_diff_ou_egal_zero(sinus_triangle(Ai, Aj, Bi, Bj, Ui, Uj),
426 sinus_triangle(Ai, Aj, Bi, Bj, Vi, Vj)))
427 if (sign_diff_ou_egal_zero(sinus_triangle(Ui, Uj, Vi, Vj, Ai, Aj),
428 sinus_triangle(Ui, Uj, Vi, Vj, Bi, Bj)))
438 * \fn int test_croisement_add_noeud_large(struct snake_node *N, int Nxi, int Nxj, int seg)
440 * \brief test si il y a croisement de segments lors de l'ajout d'un noeud
443 * \param[in] N le noeud ou l'on veut ajouter un noeud Nx au milieu de son segment
444 * \param[in] Nxi coordonnee i du nouveau node Nx
445 * \param[in] Nxj coordonnee j du nouveau node Nx
446 * \param[in] seg booleen pour definir quel segment on test:
447 * Nx --> Nsuiv si seg==1
450 * \return 1 si croisement, 0 sinon
452 * Version large : autorise les triangles nulles
455 int test_croisement_add_noeud_large(struct snake_node *N, uint32 Nxi, uint32 Nxj, int seg)
457 uint32 Nrefi=0, Nrefj=0 ; /* reference avec Nxi et Nxj */
458 uint32 posi, posj, suivi, suivj ; /* segment courant de test */
459 struct snake_node *node, *end ;
463 Nrefi = N->noeud_suiv->posi ;
464 Nrefj = N->noeud_suiv->posj ;
472 node = N->noeud_suiv ;
481 node = node->noeud_suiv ;
484 if (test_croisement_segment_large(Nxi,Nxj,Nrefi,Nrefj, posi,posj,suivi,suivj))
493 * \fn int test_croisement_add_noeud_strict(struct snake_node *N, int Nxi, int Nxj, int seg)
495 * \brief test si il y a croisement de segments lors de l'ajout d'un noeud
498 * \param[in] N le noeud ou l'on veut ajouter un noeud Nx au milieu de son segment
499 * \param[in] Nxi coordonnee i du nouveau node Nx
500 * \param[in] Nxj coordonnee j du nouveau node Nx
501 * \param[in] seg booleen pour definir quel segment on test:
502 * Nx --> Nsuiv si seg==1
505 * \return 1 si croisement, 0 sinon
507 * Version strict : n'autorise pas les triangles nulles
510 int test_croisement_add_noeud_strict(struct snake_node *N, uint32 Nxi, uint32 Nxj, int seg)
512 uint32 Nrefi=0, Nrefj=0 ; /* reference avec Nxi et Nxj */
513 uint32 posi, posj, suivi, suivj ; /* segment courant de test */
514 struct snake_node *node, *end ;
516 /* segment de reference */
519 Nrefi = N->noeud_suiv->posi ;
520 Nrefj = N->noeud_suiv->posj ;
528 /* segments de tests */
529 node = N->noeud_suiv ;
535 /* premier segment : il touche le segment de ref */
536 /* pour Nx --> Nsuiv(ref) */
539 node = node->noeud_suiv ;
542 if (test_croisement_segment_large(Nxi,Nxj,Nrefi,Nrefj,posi,posj,suivi,suivj))
544 end = N ; /* pour boucle while */
548 end = N->noeud_prec ; /* pour boucle while */
550 /* boucle sur les segments */
555 node = node->noeud_suiv ;
558 if (test_croisement_segment_strict(posi,posj,suivi,suivj,Nxi,Nxj,Nrefi,Nrefj))
562 /* dernier segment */
568 node = node->noeud_suiv ;
571 if (test_croisement_segment_large(Nxi,Nxj,Nrefi,Nrefj, posi,posj,suivi,suivj))
583 * \fn int test_croisement_move_seg_large(struct snake_node *Nx, int Nxi, int Nxj, int seg)
585 * \brief test si il y a croisement de segments lors du deplacement d'un noeud
588 * \param[in] Nx le noeud que l'on veut deplacer
589 * \param[in] Nxi coordonnee i du nouveau node Nx
590 * \param[in] Nxj coordonnee j du nouveau node Nx
591 * \param[in] seg booleen pour definir quel segment on test:
592 * Nx --> Nsuiv si seg==1
593 * Nprec --> Nx si seg==0
595 * \return 1 si croisement, 0 sinon
597 * Version large : autorise les triangles nulles
598 * Version non optimisee car elle test systematiquement tout les segments du snake !
601 int test_croisement_move_seg_large(struct snake_node *Nx, uint32 Nxi, uint32 Nxj, int seg)
603 uint32 Nrefi=0, Nrefj=0 ; /* reference avec Nxi et Nxj */
604 uint32 posi, posj, suivi, suivj ; /* segment courant de test */
605 struct snake_node *node, *end ;
609 Nrefi = Nx->noeud_suiv->posi ;
610 Nrefj = Nx->noeud_suiv->posj ;
614 Nrefi = Nx->noeud_prec->posi ;
615 Nrefj = Nx->noeud_prec->posj ;
618 node = Nx->noeud_suiv ;
622 end = Nx->noeud_prec ;
627 node = node->noeud_suiv ;
630 if (test_croisement_segment_large(Nxi,Nxj,Nrefi,Nrefj, posi,posj,suivi,suivj))
639 * \fn int test_croisement_move_seg_strict(struct snake_node *Nx, int Nxi, int Nxj, int seg)
641 * \brief test si il y a croisement de segments lors du deplacement d'un noeud
644 * \param[in] Nx le noeud que l'on veut deplacer
645 * \param[in] Nxi coordonnee i du nouveau node Nx
646 * \param[in] Nxj coordonnee j du nouveau node Nx
647 * \param[in] seg booleen pour definir quel segment on test:
648 * Nx --> Nsuiv si seg==1
649 * Nprec --> Nx si seg==0
651 * \return 1 si croisement, 0 sinon
653 * Version strict : n'autorise pas les triangles nulles
654 * Version non optimisee car elle test systematiquement tout les segments du snake !
656 int test_croisement_move_seg_strict(struct snake_node *Nx, uint32 Nxi, uint32 Nxj, int seg)
658 uint32 Nrefi=0, Nrefj=0 ; /* reference avec Nxi et Nxj */
659 uint32 posi, posj, suivi, suivj ; /* segment courant de test */
660 struct snake_node *node, *end ;
662 /* segment de reference */
665 Nrefi = Nx->noeud_suiv->posi ;
666 Nrefj = Nx->noeud_suiv->posj ;
670 Nrefi = Nx->noeud_prec->posi ;
671 Nrefj = Nx->noeud_prec->posj ;
674 /* segments de tests */
675 node = Nx->noeud_suiv ;
681 /* premier segment : il touche le segment de ref */
682 /* pour Nx --> Nsuiv(ref) */
685 node = node->noeud_suiv ;
688 if (test_croisement_segment_large(Nxi,Nxj,Nrefi,Nrefj,posi,posj,suivi,suivj))
691 end = Nx->noeud_prec ; /* pour boucle while */
694 /* pour Nprec --> Nx */
695 end = Nx->noeud_prec->noeud_prec ; /* pour boucle while */
697 /* boucle sur les segments */
702 node = node->noeud_suiv ;
705 if (test_croisement_segment_strict(posi,posj,suivi,suivj,Nxi,Nxj,Nrefi,Nrefj))
709 /* dernier segment */
710 /* cas Nprec --> Nx */
715 node = node->noeud_suiv ;
718 if (test_croisement_segment_large(Nxi,Nxj,Nrefi,Nrefj, posi,posj,suivi,suivj))