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 ;
208 i1 = np->posi ; j1 = np->posj ;
209 i2 = npp1->posi ; j2 = npp1->posj ;
211 nb_pixel_segment = calcul_liste_pixel_segment(i1,j1,i2,j2, liste_pixel_segment, 0) ;
212 for (n=1; n<nb_pixel_segment-1; n++)
213 image[liste_pixel_segment[2*n]][liste_pixel_segment[2*n+1]] = valseg ;
216 npp1 = np->noeud_suiv ;
218 while (np != snake) ;
220 /* les deux noeuds */
222 npp1 = snake->noeud_suiv ;
225 i1 = np->posi ; j1 = np->posj ;
226 i2 = npp1->posi ; j2 = npp1->posj ;
228 image[i1][j1] = valnoeud ;
229 image[i2][j2] = valnoeud ;
232 npp1 = np->noeud_suiv ;
234 while (np != snake) ;
237 /* ========== DEBUG ================= */
238 /* fonction d'affichage pour le debug */
239 /* affiche les deux premiers segments avec valseg-1 */
240 /* et incremenent les valeurs des noeuds */
241 void affiche_snake_couleur(int **image, struct snake_node *snake, int valseg, int valnoeud,
242 uint32 *liste_pixel_segment)
244 uint32 i1, j1, i2, j2 ;
245 uint32 n, nb_pixel_segment ;
246 struct snake_node *np, *npp1 ;
248 snake = snake->noeud_prec ;
252 npp1 = np->noeud_suiv ;
255 i1 = np->posi ; j1 = np->posj ;
256 i2 = npp1->posi ; j2 = npp1->posj ;
258 nb_pixel_segment = calcul_liste_pixel_segment(i1,j1,i2,j2, liste_pixel_segment, 0) ;
260 for (n=1; n<nb_pixel_segment-1; n++)
261 image[liste_pixel_segment[2*n]][liste_pixel_segment[2*n+1]] = valseg-1 ;
263 for (n=1; n<nb_pixel_segment-1; n++)
264 image[liste_pixel_segment[2*n]][liste_pixel_segment[2*n+1]] = valseg ;
268 npp1 = np->noeud_suiv ;
270 while (np != snake) ;
272 /* les deux noeuds */
275 npp1 = snake->noeud_suiv ;
278 i1 = np->posi ; j1 = np->posj ;
279 i2 = npp1->posi ; j2 = npp1->posj ;
281 image[i1][j1] = valnoeud+cpt ;
282 image[i2][j2] = valnoeud+cpt++ ;
285 npp1 = np->noeud_suiv ;
287 while (np != snake) ;
290 /* ========= DEBUG ===================== */
291 /* copie l'image du snake avec un numero */
292 /* de fichier incremente a chaque appel */
293 void debug_aff_snake(struct snake_node *snake)
295 const int idim=256, jdim=256 ;
297 int **image = new_matrix_int(idim, jdim) ;
298 uint32 *liste_pixel = malloc(sizeof(int)*2*(idim+jdim)) ;
303 for (n=0; n<idim*jdim; n++)
306 affiche_snake_couleur(image, snake, 255, 0, liste_pixel) ;
307 sprintf(output, "debug_im%.4d.pgm", iter++) ;
308 write_int2pgm(image, idim, idim, output, 0) ;
310 del_matrix_int(image, idim);
318 * \fn int ajout_noeud_snake(struct snake_node *node, int *nb_noeud)
319 * \brief ajout un noeud au snake
322 * \param[in] node adresse du noeud
323 * \param[out] nb_noeud nombre de noeuds du snake
325 * \return le pointeur du nouveau noeud si ajout reussi, NULL sinon
327 * Ajout d'un noeud au millieu du segment.
328 * !!! Pour algo rapide, cette fonction doit etre suivie
329 * d'une mise a jour des contrib des noeuds qui conviennent !!!
332 struct snake_node* ajout_noeud_snake(struct snake_node *node, uint32 *nb_noeud)
334 struct snake_node *najout ;
336 najout = malloc(sizeof(struct snake_node)) ;
338 najout->posi = node->centre_i ;
339 najout->posj = node->centre_j ;
341 najout->noeud_prec = node ;
342 najout->noeud_suiv = node->noeud_suiv ;
343 node->noeud_suiv->noeud_prec = najout ;
344 node->noeud_suiv = najout ;
354 * \fn inline int test_croisement_segment_large(int Ai, int Aj, int Bi, int Bj,
355 * int Ui, int Uj, int Vi, int Vj)
357 * \brief Test qui determine si deux segments croisent
369 * \return 1 si croisement, 0 sinon
371 * Version large : autorise les triangles nulles
372 * Test de croisement des segments :
373 * si deux segments AB et UV croisent, alors
374 * les triangles ABU et ABV change d'ordre de rotation
376 * les triangles UVA et UVB change aussi d'ordre de rotation
379 inline int test_croisement_segment_large(uint32 Ai, uint32 Aj, uint32 Bi, uint32 Bj,
380 uint32 Ui, uint32 Uj, uint32 Vi, uint32 Vj)
382 if (sign_diff_strict(sinus_triangle(Ai, Aj, Bi, Bj, Ui, Uj), // Bi-Ai, Uj-Aj, Ui-Ai, Bj-Aj
383 sinus_triangle(Ai, Aj, Bi, Bj, Vi, Vj))) // Bi-Ai, Vj-Aj, Vi-Ai, Bj-Aj
384 if (sign_diff_strict(sinus_triangle(Ui, Uj, Vi, Vj, Ai, Aj), // Vi-Ui, Aj-Uj, Ai-Ui, Vj-Uj
385 sinus_triangle(Ui, Uj, Vi, Vj, Bi, Bj))) // Vi-Ui, Bj-Uj, Bi-Ui, Vj-Uj
392 * \fn inline int test_croisement_segment_strict(int Ai, int Aj, int Bi, int Bj,
393 * int Ui, int Uj, int Vi, int Vj)
395 * \brief Test qui determine si deux segments croisent
407 * \return 1 si croisement, 0 sinon
409 * Version strict : n'autorise pas les triangles nulles
410 * Test de croisement des segments :
411 * si deux segments AB et UV croisent, alors
412 * les triangles ABU et ABV change d'ordre de rotation
414 * les triangles UVA et UVB change aussi d'ordre de rotation
417 inline int test_croisement_segment_strict(uint32 Ai, uint32 Aj, uint32 Bi, uint32 Bj,
418 uint32 Ui, uint32 Uj, uint32 Vi, uint32 Vj)
420 if (sign_diff_ou_egal_zero(sinus_triangle(Ai, Aj, Bi, Bj, Ui, Uj),
421 sinus_triangle(Ai, Aj, Bi, Bj, Vi, Vj)))
422 if (sign_diff_ou_egal_zero(sinus_triangle(Ui, Uj, Vi, Vj, Ai, Aj),
423 sinus_triangle(Ui, Uj, Vi, Vj, Bi, Bj)))
433 * \fn int test_croisement_add_noeud_large(struct snake_node *N, int Nxi, int Nxj, int seg)
435 * \brief test si il y a croisement de segments lors de l'ajout d'un noeud
438 * \param[in] N le noeud ou l'on veut ajouter un noeud Nx au milieu de son segment
439 * \param[in] Nxi coordonnee i du nouveau node Nx
440 * \param[in] Nxj coordonnee j du nouveau node Nx
441 * \param[in] seg booleen pour definir quel segment on test:
442 * Nx --> Nsuiv si seg==1
445 * \return 1 si croisement, 0 sinon
447 * Version large : autorise les triangles nulles
450 int test_croisement_add_noeud_large(struct snake_node *N, uint32 Nxi, uint32 Nxj, int seg)
452 uint32 Nrefi=0, Nrefj=0 ; /* reference avec Nxi et Nxj */
453 uint32 posi, posj, suivi, suivj ; /* segment courant de test */
454 struct snake_node *node, *end ;
458 Nrefi = N->noeud_suiv->posi ;
459 Nrefj = N->noeud_suiv->posj ;
467 node = N->noeud_suiv ;
476 node = node->noeud_suiv ;
479 if (test_croisement_segment_large(Nxi,Nxj,Nrefi,Nrefj, posi,posj,suivi,suivj))
488 * \fn int test_croisement_add_noeud_strict(struct snake_node *N, int Nxi, int Nxj, int seg)
490 * \brief test si il y a croisement de segments lors de l'ajout d'un noeud
493 * \param[in] N le noeud ou l'on veut ajouter un noeud Nx au milieu de son segment
494 * \param[in] Nxi coordonnee i du nouveau node Nx
495 * \param[in] Nxj coordonnee j du nouveau node Nx
496 * \param[in] seg booleen pour definir quel segment on test:
497 * Nx --> Nsuiv si seg==1
500 * \return 1 si croisement, 0 sinon
502 * Version strict : n'autorise pas les triangles nulles
505 int test_croisement_add_noeud_strict(struct snake_node *N, uint32 Nxi, uint32 Nxj, int seg)
507 uint32 Nrefi=0, Nrefj=0 ; /* reference avec Nxi et Nxj */
508 uint32 posi, posj, suivi, suivj ; /* segment courant de test */
509 struct snake_node *node, *end ;
511 /* segment de reference */
514 Nrefi = N->noeud_suiv->posi ;
515 Nrefj = N->noeud_suiv->posj ;
523 /* segments de tests */
524 node = N->noeud_suiv ;
530 /* premier segment : il touche le segment de ref */
531 /* pour Nx --> Nsuiv(ref) */
534 node = node->noeud_suiv ;
537 if (test_croisement_segment_large(Nxi,Nxj,Nrefi,Nrefj,posi,posj,suivi,suivj))
539 end = N ; /* pour boucle while */
543 end = N->noeud_prec ; /* pour boucle while */
545 /* boucle sur les segments */
550 node = node->noeud_suiv ;
553 if (test_croisement_segment_strict(posi,posj,suivi,suivj,Nxi,Nxj,Nrefi,Nrefj))
557 /* dernier segment */
563 node = node->noeud_suiv ;
566 if (test_croisement_segment_large(Nxi,Nxj,Nrefi,Nrefj, posi,posj,suivi,suivj))
578 * \fn int test_croisement_move_seg_large(struct snake_node *Nx, int Nxi, int Nxj, int seg)
580 * \brief test si il y a croisement de segments lors du deplacement d'un noeud
583 * \param[in] Nx le noeud que l'on veut deplacer
584 * \param[in] Nxi coordonnee i du nouveau node Nx
585 * \param[in] Nxj coordonnee j du nouveau node Nx
586 * \param[in] seg booleen pour definir quel segment on test:
587 * Nx --> Nsuiv si seg==1
588 * Nprec --> Nx si seg==0
590 * \return 1 si croisement, 0 sinon
592 * Version large : autorise les triangles nulles
593 * Version non optimisee car elle test systematiquement tout les segments du snake !
596 int test_croisement_move_seg_large(struct snake_node *Nx, uint32 Nxi, uint32 Nxj, int seg)
598 uint32 Nrefi=0, Nrefj=0 ; /* reference avec Nxi et Nxj */
599 uint32 posi, posj, suivi, suivj ; /* segment courant de test */
600 struct snake_node *node, *end ;
604 Nrefi = Nx->noeud_suiv->posi ;
605 Nrefj = Nx->noeud_suiv->posj ;
609 Nrefi = Nx->noeud_prec->posi ;
610 Nrefj = Nx->noeud_prec->posj ;
613 node = Nx->noeud_suiv ;
617 end = Nx->noeud_prec ;
622 node = node->noeud_suiv ;
625 if (test_croisement_segment_large(Nxi,Nxj,Nrefi,Nrefj, posi,posj,suivi,suivj))
634 * \fn int test_croisement_move_seg_strict(struct snake_node *Nx, int Nxi, int Nxj, int seg)
636 * \brief test si il y a croisement de segments lors du deplacement d'un noeud
639 * \param[in] Nx le noeud que l'on veut deplacer
640 * \param[in] Nxi coordonnee i du nouveau node Nx
641 * \param[in] Nxj coordonnee j du nouveau node Nx
642 * \param[in] seg booleen pour definir quel segment on test:
643 * Nx --> Nsuiv si seg==1
644 * Nprec --> Nx si seg==0
646 * \return 1 si croisement, 0 sinon
648 * Version strict : n'autorise pas les triangles nulles
649 * Version non optimisee car elle test systematiquement tout les segments du snake !
651 int test_croisement_move_seg_strict(struct snake_node *Nx, uint32 Nxi, uint32 Nxj, int seg)
653 uint32 Nrefi=0, Nrefj=0 ; /* reference avec Nxi et Nxj */
654 uint32 posi, posj, suivi, suivj ; /* segment courant de test */
655 struct snake_node *node, *end ;
657 /* segment de reference */
660 Nrefi = Nx->noeud_suiv->posi ;
661 Nrefj = Nx->noeud_suiv->posj ;
665 Nrefi = Nx->noeud_prec->posi ;
666 Nrefj = Nx->noeud_prec->posj ;
669 /* segments de tests */
670 node = Nx->noeud_suiv ;
676 /* premier segment : il touche le segment de ref */
677 /* pour Nx --> Nsuiv(ref) */
680 node = node->noeud_suiv ;
683 if (test_croisement_segment_large(Nxi,Nxj,Nrefi,Nrefj,posi,posj,suivi,suivj))
686 end = Nx->noeud_prec ; /* pour boucle while */
689 /* pour Nprec --> Nx */
690 end = Nx->noeud_prec->noeud_prec ; /* pour boucle while */
692 /* boucle sur les segments */
697 node = node->noeud_suiv ;
700 if (test_croisement_segment_strict(posi,posj,suivi,suivj,Nxi,Nxj,Nrefi,Nrefj))
704 /* dernier segment */
705 /* cas Nprec --> Nx */
710 node = node->noeud_suiv ;
713 if (test_croisement_segment_large(Nxi,Nxj,Nrefi,Nrefj, posi,posj,suivi,suivj))