
#include "zones.h"


/******************************************************************************/
/* LECTURE DES PARAMETRES DU MOTIF                                            */
/*                                                                            */
/* Allocation memoire et remplissage de la structure forme_t pour un polygone */
/* ou une courbe spline fermee.                                               */
/******************************************************************************/

void parametres_formes(motif_t motif,angle_t angle,forme_t *forme) {
  if (motif==m_polygone)
    forme->intervalles.aretes=(arete_t *)malloc(forme->nb*sizeof(arete_t));
  else {
    forme->intervalles.spline.x=(polynome_t *)malloc((forme->nb-1)*sizeof(polynome_t));
    forme->intervalles.spline.y=(polynome_t *)malloc((forme->nb-1)*sizeof(polynome_t));
  }
  if (angle==fixe) {
    forme->x_rotation=NULL;
    forme->y_rotation=NULL;
    if (motif==m_polygone) calcul_aretes(forme,forme->intervalles.aretes);
    else {
      coeffs_spline(forme->x,forme->intervalles.spline.x,forme->nb);
      coeffs_spline(forme->y,forme->intervalles.spline.y,forme->nb);
    }
  } else {
    forme->x_rotation=(double *)malloc(forme->nb*sizeof(double));
    forme->y_rotation=(double *)malloc(forme->nb*sizeof(double));
  }
}


/******************************************************************************/
/* LECTURE DE LA LISTE DES ZONES                                              */
/******************************************************************************/

long lire_liste_zones(en_tete_t *en_tete,zone_t **zones,forme_t **formes,
                      ellipse_t **ellipses,shaper_t **shapers) {

  /* variables locales */
  
  long nb_zones=(long)en_tete->nb_zones,nb_formes=(long)en_tete->nb_formes,
       nb_ellipses=(long)en_tete->nb_ellipses,
       nb_shapers_quelconques=(long)en_tete->nb_shapers_quelconques,
       nb,cpt_formes=0,cpt_ellipses=0,cpt_shapers=0,i;
  info_zone_t *info_zone=(info_zone_t *)en_tete+1;
  info_motif_t *info_motif;
  motif_t motif;
  angle_t angle;
  double *info_loi;


  /* allocation memoire */
  
  if (nb_zones   ) *zones   =(zone_t *)   malloc(nb_zones   *sizeof(zone_t)   );
  else             *zones   =NULL;
  if (nb_formes  ) *formes  =(forme_t *)  malloc(nb_formes  *sizeof(forme_t)  );
  else             *formes  =NULL;
  if (nb_ellipses) *ellipses=(ellipse_t *)malloc(nb_ellipses*sizeof(ellipse_t));
  else             *ellipses=NULL;
  if (nb_shapers_quelconques) *shapers=(shaper_t *)malloc(nb_shapers_quelconques*sizeof(shaper_t));
  else             *shapers =NULL;

  
  for (i=0;i<nb_zones;i++) {
  
    /* informations relatives a la zone */

    (*zones)[i].masque=info_zone->masque;
    (*zones)[i].mort  =info_zone->mort;
    (*zones)[i].nb_points_controle=nb=(long)info_zone->nb_points_controle;
    (*zones)[i].points_x=(double *)info_zone+1;
    (*zones)[i].points_y=(double *)info_zone+1+nb;


    /* informations relatives au motif */

    info_motif=(info_motif_t *)info_zone+1+2*nb;
    (*zones)[i].motif=motif=              (motif_t)info_motif->motif;
    (*zones)[i].angle=angle=              (angle_t)info_motif->angle;
    (*zones)[i].numero_fonction=(numero_fonction_t)info_motif->numero_fonction;
    nb=info_motif->nb_parametres;
    if (motif==m_polygone || motif==m_spline) {
      (*formes)[cpt_formes].nb=nb/2;
      (*formes)[cpt_formes].x=(double *)info_motif+1;
      (*formes)[cpt_formes].y=(double *)info_motif+1+nb/2;
      parametres_formes(motif,angle,*formes+cpt_formes);
      (*zones)[i].numero_motif=cpt_formes++;
    } else if (motif==m_ellipse) {
      memcpy((ellipse_t *)(*ellipses+cpt_ellipses),(double *)info_motif+1,
             sizeof(ellipse_t));
      (*zones)[i].numero_motif=cpt_ellipses++;
    } else if (motif==m_shaper_quelconque) {
      (*shapers)[cpt_shapers].nb=nb;
      (*shapers)[cpt_shapers].points=(double *)info_motif+1;
      (*zones)[i].numero_motif=cpt_shapers++;
    }


    /* informations relatives a la loi */

    info_loi=(double *)info_motif+1+nb;
    (*zones)[i].loi.type=(type_loi_t)*info_loi;
    memcpy(&((*zones)[i].loi.parametres),info_loi+1,sizeof(parametres_t)+sizeof(double));


    info_zone+=info_zone->nb_cases_zone;
  }

  return nb_zones;
}


/******************************************************************************/
/* CONSTRUCTION DE LA LISTE DES ZONES                                         */
/******************************************************************************/

void construire_liste_zones(long nb_zones,long nb_formes,long nb_ellipses,long nb_shapers_quelconques,
                            long indice_debut_non_shaper,zone_t *zones,forme_t *formes,
                            ellipse_t *ellipses,shaper_t *shapers,mxArray **sortie,en_tete_t **en_tete) {

  /* variables locales */

  long nb_cases,cpt_formes=0,cpt_ellipses=0,cpt_shapers=0,nb,i;
  motif_t motif;
  info_zone_t *info_zone;
  info_motif_t *info_motif;
  double *info_loi;


  /* allocation memoire */

  nb_cases=1+nb_zones*6+nb_ellipses*(sizeof(ellipse_t)/sizeof(double));
  for (i=0;i<nb_zones ;i++)              nb_cases+=2*zones[i].nb_points_controle;
  for (i=0;i<nb_formes;i++)              nb_cases+=2*formes[i].nb;
  for (i=0;i<nb_shapers_quelconques;i++) nb_cases+=shapers[i].nb;
  *sortie=mxCreateDoubleMatrix(1,nb_cases,mxREAL);
  *en_tete=(en_tete_t *)mxGetPr(*sortie);


  /* en-tete de la liste */

  (*en_tete)->nb_zones               =(unsigned char)nb_zones;
  (*en_tete)->nb_formes              =(unsigned char)nb_formes;
  (*en_tete)->nb_ellipses            =(unsigned char)nb_ellipses;
  (*en_tete)->nb_shapers_quelconques =(unsigned char)nb_shapers_quelconques;
  (*en_tete)->indice_debut_non_shaper=indice_debut_non_shaper;
  info_zone=(info_zone_t *)*en_tete+1;
  

  for (i=0;i<nb_zones;i++) {

    /* parametres de la zone */

    info_zone->masque=zones[i].masque;
    info_zone->mort  =zones[i].mort;
    info_zone->nb_points_controle=nb=zones[i].nb_points_controle;
    info_zone->nb_cases_zone=6+2*nb; /* le nombre de parametres de la forme est ajoute apres */
    if (nb) {
      memcpy((double *)info_zone+1   ,zones[i].points_x,nb*sizeof(double));
      memcpy((double *)info_zone+1+nb,zones[i].points_y,nb*sizeof(double));
    }
    

    /* parametres du motif */
    
    info_motif=(info_motif_t *)info_zone+1+2*nb;
    info_motif->motif=motif     =(unsigned char)zones[i].motif;
    info_motif->angle           =(unsigned char)zones[i].angle;
    info_motif->numero_fonction =(unsigned short)zones[i].numero_fonction;
    if (motif==m_polygone || motif==m_spline) {
      info_motif->nb_parametres=nb=2*formes[cpt_formes].nb;
      memcpy((double *)info_motif+1     ,formes[cpt_formes].x,nb/2*sizeof(double));
      memcpy((double *)info_motif+1+nb/2,formes[cpt_formes].y,nb/2*sizeof(double));
      cpt_formes++;
    } else if (motif==m_ellipse) {
      info_motif->nb_parametres=nb=sizeof(ellipse_t)/sizeof(double);
      memcpy((double *)info_motif+1,(ellipse_t *)(ellipses+cpt_ellipses),
             sizeof(ellipse_t));
      cpt_ellipses++;
    } else if (motif==m_shaper_quelconque) {
      info_motif->nb_parametres=nb=shapers[cpt_shapers].nb;
      memcpy((double *)info_motif+1,shapers[cpt_shapers].points,nb*sizeof(double));
      cpt_shapers++;
    } else info_motif->nb_parametres=nb=0;
    info_zone->nb_cases_zone+=nb;


    /* parametres de la loi */
    
    info_loi=(double *)info_motif+1+nb;
    *info_loi=(double)zones[i].loi.type;
    memcpy(info_loi+1,&(zones[i].loi.parametres),sizeof(parametres_t)+sizeof(double));


    info_zone+=info_zone->nb_cases_zone;
  }
}


/******************************************************************************/
/* LIBERATION DE LA MEMOIRE D'UNE FORME                                       */
/******************************************************************************/

void liberer_forme(forme_t forme,motif_t motif) {
  if (forme.x_rotation) {
    free(forme.x_rotation);
    free(forme.y_rotation);
  }
  if (motif==m_polygone)
    free(forme.intervalles.aretes);
  else {
    free(forme.intervalles.spline.x);
    free(forme.intervalles.spline.y);
  }
}


/******************************************************************************/
/* LIBERATION DE LA MEMOIRE DES ZONES                                         */
/******************************************************************************/

void liberer_memoire_zones(en_tete_t *en_tete,zone_t *zones,forme_t *formes,
                           ellipse_t *ellipses,shaper_t *shapers,char f_scid2d) {

  /* variables locales */
  
  long nb_formes=en_tete->nb_formes,nb,i=0;
  info_zone_t *info_zone=(info_zone_t *)en_tete+1;
  info_motif_t *info_motif;


  /* forme des motifs */

  while (i<nb_formes) {
    nb=info_zone->nb_points_controle;
    info_motif=(info_motif_t *)info_zone+1+2*nb;
    if ((motif_t)info_motif->motif==m_polygone ||
        (motif_t)info_motif->motif==m_spline) {
      liberer_forme(formes[i],(motif_t)info_motif->motif);
      i++;
    }
    info_zone+=info_zone->nb_cases_zone;
  }


  /* liste des zones, des formes et des ellipses */

  if (zones              ) free(zones);
  if (formes && !f_scid2d) free(formes);
  if (ellipses           ) free(ellipses);
  if (shapers            ) free(shapers);
}


/******************************************************************************/
/* SUPPRIMER UNE ZONE                                                         */
/*                                                                            */
/* On decale vers la gauche les zones, les formes, les ellipses et les fonc-  */
/* tions lissantes situees apres celle qu'on suprime dans leurs listes respec-*/
/* tives. On met a jour la liste des tirages en mettant a jour les indices en */
/* consequence. On gère aussi la suppression d'une zone masque d'autres zones.*/
/* -> masque : une zone j constitue un masque pour une zone k si tous les mul-*/
/*             tiplieurs de k doivent etre situes dans la zone j              */
/******************************************************************************/

void supprimer_zone(zone_t *zones,long *nb_zones,long i,forme_t *formes,long *nb_formes,
                    ellipse_t *ellipses,long *nb_ellipses,shaper_t *shapers,
                    long *nb_shapers_quelconques,tirage_t *tirages,long nb_tirages,char cadre) {

  /* variables locales */

  long j;
  char suppression;
  

  /* traitement des zones dont celle-ci est le masque */

  for (j=i+1;j<*nb_zones;j++) {
    if (zones[j].masque==i) {
      if (cadre) {
      
        /* si on supprime une zone parcequ'elle a un cadre disjoint avec celui du zoom */

        supprimer_zone(zones,nb_zones,j,formes,nb_formes,ellipses,nb_ellipses,
                       shapers,nb_shapers_quelconques,tirages,nb_tirages,cadre);

      } else {
      
        /* si on supprime une zone parcequ'elle n'a plus de représentants */

        zones[j].masque=zones[i].masque;

      }
    }
  }


  /* mise a jour de formes, ellipses et shapers */

  if (zones[i].motif==m_polygone || zones[i].motif==m_spline) {
    suppression=1;
    liberer_forme(formes[zones[i].numero_motif],zones[i].motif);
    for (j=zones[i].numero_motif+1;j<*nb_formes;j++) formes[j-1]=formes[j];
    (*nb_formes)--;
  } else if (zones[i].motif==m_ellipse) {
    suppression=2;
    for (j=zones[i].numero_motif+1;j<*nb_ellipses;j++) ellipses[j-1]=ellipses[j];
    (*nb_ellipses)--;
  } else if (zones[i].motif==m_shaper_quelconque) {
    suppression=3;
    for (j=zones[i].numero_motif+1;j<*nb_shapers_quelconques;j++) shapers[j-1]=shapers[j];
    (*nb_shapers_quelconques)--;
  } else suppression==0;


  /* mise a jour de zones */

  for (j=i+1;j<*nb_zones;j++) {
    if ((suppression==1 && (zones[j].motif==m_polygone || zones[j].motif==m_spline)) ||
        (suppression==2 &&  zones[j].motif==m_ellipse) ||
        (suppression==3 &&  zones[j].motif==m_shaper_quelconque)) zones[j].numero_motif--;
    if (zones[j].masque>i) zones[j].masque--;
    if (zones[j].masque==0) zones[j].masque=-1;
    zones[j-1]=zones[j];
  }


  /* mise a jour de tirages */

  for (j=0;j<nb_tirages;j++) {
    if (tirages[j].numero_zone>i) {
      tirages[j].numero_zone--;
      if ((suppression==1 && (tirages[j].type_motif==m_polygone || tirages[j].type_motif==m_spline)) ||
          (suppression==2 &&  tirages[j].type_motif==m_ellipse) ||
          (suppression==3 &&  tirages[j].type_motif==m_shaper_quelconque))
        tirages[j].numero_motif--;
    }
  }


  (*nb_zones)--;
}


/******************************************************************************/
/* CADRE DES ZONES (BORNES SUP ET INF SELON X ET Y)                           */
/*                                                                            */
/* Si on constate que le cadre d'une zone est en dehors du cadre du zoom, on  */
/* supprime cette zone. En outre les cadres permettront de limiter les tests  */
/* d'appartenance d'un point a une zone donnee.                               */
/******************************************************************************/

void cadre_zones(zone_t *zones,long *nb_zones,double x_min,double y_min,
                 double delta_x,double delta_y,forme_t *formes,long *nb_formes,
                 ellipse_t *ellipses,long *nb_ellipses,shaper_t *shapers,
                 long *nb_shapers_quelconques,tirage_t *tirages,long nb_tirages) {

  /* variables locales */
  
  long nb_points,i=1,j;
  zone_t *zone=zones;


  /* la premiere zone a comme cadre le cadre du zoom */

  zone->inf_x=zone->inf_y=0.;
  zone->sup_x=delta_x;
  zone->sup_y=delta_y;
  zone->spline.x=NULL;
  zone->spline.y=NULL;


  while (i<*nb_zones) {

    /* translation des points de controle */

    zone=zones+i;
    nb_points=zone->nb_points_controle;
    for (j=0;j<nb_points;j++) {
      zone->points_x[j]-=x_min;
      zone->points_y[j]-=y_min;
    }
    
    
    /* equation des polynomes */

    zone->spline.x=(polynome_t *)malloc((nb_points-1)*sizeof(polynome_t));
    zone->spline.y=(polynome_t *)malloc((nb_points-1)*sizeof(polynome_t));
    coeffs_spline(zone->points_x,zone->spline.x,nb_points);
    coeffs_spline(zone->points_y,zone->spline.y,nb_points);
    
    
    /* extremaux des polynomes dans le cadre du zoom */

    zone->sup_x=zone->sup_y=0.;
    zone->inf_x=delta_x;
    zone->inf_y=delta_y;
    for (j=0;j<nb_points-1;j++) {
      bornes(zone->spline.x[j],zone->points_x[j],&(zone->inf_x),&(zone->sup_x));
      bornes(zone->spline.y[j],zone->points_y[j],&(zone->inf_y),&(zone->sup_y));
    }
    if (zone->inf_x<0.) zone->inf_x=0.;
    if (zone->inf_y<0.) zone->inf_y=0.;
    if (zone->sup_x>delta_x) zone->sup_x=delta_x;
    if (zone->sup_y>delta_y) zone->sup_y=delta_y;

    
    /* suppression de la zone si elle est hors du cadre */

    if (zone->inf_x>=zone->sup_x || zone->inf_y>=zone->sup_y) {
      free(zone->spline.x);
      free(zone->spline.y);
      supprimer_zone(zones,nb_zones,i,formes,nb_formes,ellipses,nb_ellipses,
                     shapers,nb_shapers_quelconques,tirages,nb_tirages,1);
    } else i++;

  }
}

