/*
 * This file is part of the Alliance CAD System
 * Copyright (C) Laboratoire LIP6 - Département ASIM
 * Universite Pierre et Marie Curie
 *
 * Home page          : http://www-asim.lip6.fr/alliance/
 * E-mail             : mailto:alliance-users@asim.lip6.fr
 *
 * This progam is  free software; you can redistribute it  and/or modify it
 * under the  terms of the GNU  General Public License as  published by the
 * Free Software Foundation;  either version 2 of the License,  or (at your
 * option) any later version.
 *
 * Alliance VLSI  CAD System  is distributed  in the hope  that it  will be
 * useful, but WITHOUT  ANY WARRANTY; without even the  implied warranty of
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General
 * Public License for more details.
 *
 * You should have received a copy  of the GNU General Public License along
 * with the GNU C Library; see the  file COPYING. If not, write to the Free
 * Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
 */

/****************************************************************************/
/*                                                                          */
/*                      ALLIANCE CAO & VLSI CAD                             */
/*                                                                          */
/*    Product : (S)ymbolic (2)to (R)eal translater                          */
/*    File    : postreat.c                                                  */
/*                                                                          */
/*    (c) copyright 1992 MASI laboratory CAO & VLSI team                    */
/*    All Right Reserved                                                    */
/*    Support : e-mail cao-vlsi@masi.ibp.fr                                 */
/*                                                                          */
/****************************************************************************/
/*                                                                          */
/*                     Post treatement functions                            */
/*                                                                          */
/****************************************************************************/
/* fonction void couron_layer ()                                            */
/* ATTENTION! dx et dy ne sont pas les longueurs mais les positions hautes  */
/*            et droites des couronnes dans couronne[]                      */
/****************************************************************************/

#include "generic.h"
#include  "mph.h"
#include  "mut.h"
#include  "rds.h"
#include  "rpr.h"
#include  "rtl.h"
#include  "rfm.h"
#include "rdsacces.h"
#include "postrat.h"
#include "merge.h"
#include "hash.h"
#include "math.h"

/*************************************************************************
 * resize_layer : extends the sides of all the rectangles in the specified
 *                layer in the specified model by the amount "qty" at each
 *                extreme.
 *************************************************************************/
static void resize_layer (model, layer_num)
     rdsfig_list *model;
     int layer_num;
{
   rdsrec_list *rectp;
   long qty;                    /* given in rds_unit */

   qty = GET_S2R_OVERSIZE (layer_num);

   for (rectp = model->LAYERTAB[layer_num]; rectp; rectp = rectp->NEXT)
   {
      rectp->X -= qty;
      rectp->Y -= qty;
      rectp->DX += 2 * qty;
      rectp->DY += 2 * qty;
   }
}

/*****************************************************************************
 * inv_resize_layer : minimizes the sides of all the rectangles in the specified
 *                    layer in the specified model by the amount "qty" at each
 *                    extreme.
 *****************************************************************************/
static void inv_resize_layer (model, layer_num)
     rdsfig_list *model;
     int layer_num;
{
   rdsrec_list *rectp;
   long qty;                    /* given in rds_unit */

   qty = GET_S2R_OVERSIZE (layer_num);

   for (rectp = model->LAYERTAB[layer_num]; rectp; rectp = rectp->NEXT)
   {
      rectp->X += qty;
      rectp->Y += qty;
      rectp->DX -= 2 * qty;
      rectp->DY -= 2 * qty;
   }
}

/******************************************************************************
 * adjust_rectangle: adjusts the data of the rectangle considering the symmetry
 *                   of the instance containning it.
 *                   The given symmetry might be different from the symmetry
 *                   of the instance in its father ( the case of several
 *                   hierarchical levels).
 *                   This function is used when copying the rectangle in higher
 *                   hierarchical level.
 *****************************************************************************/
static void adjust_rectangle (x, y, dx, dy, xins, yins, sym)
     long *x, *y, *dx, *dy;
     long xins, yins;
     char sym;
{
   long tx, ty, tdx, tdy;

   tx = *x;
   ty = *y;
   tdx = *dx;
   tdy = *dy;

   switch (sym)
   {
   case NOSYM:
      *x += xins;
      *y += yins;
      break;
   case SYM_X:
      *x = xins - tx - tdx;
      *y += yins;
      break;
   case SYM_Y:
      *x += xins;
      *y = yins - ty - tdy;
      break;
   case SYMXY:
      *x = xins - tx - tdx;
      *y = yins - ty - tdy;
      break;
   case ROT_P:
      *x = xins - ty - tdy;
      *y = yins + tx;
      *dx = tdy;
      *dy = tdx;
      break;
   case ROT_M:
      *x = xins + ty;
      *y = yins - tx - tdx;
      *dx = tdy;
      *dy = tdx;
      break;
   case SY_RP:
      *x = xins + ty;
      *y = yins + tx;
      *dx = tdy;
      *dy = tdx;
      break;
   case SY_RM:
      *x = xins - ty - tdy;
      *y = yins - tx - tdx;
      *dx = tdy;
      *dy = tdx;
      break;
   default:
      (void) fprintf (stderr, "**post_trat**adj_rect:unknown symetry number %d\n", sym);
      exit (1);
   }
}

/******************************************************************************
 * readjust_rectangle: adjusts the data of the rectangle considering the
 *                     symmetry of the instance that will contain it.
 *                     The given symmetry might be different from the symmetry
 *                     of the instance in its father ( the case of several
 *                     hierarchical levels).
 *                     This function is used when copying the rectangle in lower
 *                     hirerichal level.
 *****************************************************************************/
static void readjust_rectangle (x, y, dx, dy, xins, yins, sym)
     long *x, *y, *dx, *dy;
     long xins, yins;
     char sym;
{
   long tx, ty, tdx, tdy;

   tx = *x;
   ty = *y;
   tdx = *dx;
   tdy = *dy;
   switch (sym)
   {
   case NOSYM:
      *x -= xins;
      *y -= yins;
      break;
   case SYM_X:
      *x = xins - tx - tdx;
      *y -= yins;
      break;
   case SYM_Y:
      *x -= xins;
      *y = yins - ty - tdy;
      break;
   case SYMXY:
      *x = xins - tx - tdx;
      *y = yins - ty - tdy;
      break;
   case ROT_P:
      *x = ty - yins;
      *y = xins - tdx - tx;
      *dx = tdy;
      *dy = tdx;
      break;
   case ROT_M:
      *x = yins - tdy - ty;
      *y = tx - xins;
      *dx = tdy;
      *dy = tdx;
      break;
   case SY_RP:
      *x = ty - yins;
      *y = tx - xins;
      *dx = tdy;
      *dy = tdx;
      break;
   case SY_RM:
      *x = yins - tdy - ty;
      *y = xins - tdx - tx;
      *dx = tdy;
      *dy = tdx;
      break;
   default:
      (void) fprintf (stderr, "**post_trat**readj_rect:unknown symetry number %d\n", sym);
      exit (1);
   }
}

/******************************************************************************
 * result_sym: gives the result of 2 successive symmetry.
 *****************************************************************************/
static char result_sym (first_sym, second_sym)
     char first_sym, second_sym;
{
   switch (first_sym)
   {
   case NOSYM:
      switch (second_sym)
      {
      case NOSYM:
         return (NOSYM);
      case SYM_X:
         return (SYM_X);
      case SYM_Y:
         return (SYM_Y);
      case SYMXY:
         return (SYMXY);
      case ROT_P:
         return (ROT_P);
      case ROT_M:
         return (ROT_M);
      case SY_RP:
         return (SY_RP);
      case SY_RM:
         return (SY_RM);
      default:
         (void) fprintf (stderr, "**post_trat**result_sym:unknown symetry number %d\n", second_sym);
         exit (1);
      }
   case SYM_X:
      switch (second_sym)
      {
      case NOSYM:
         return (SYM_X);
      case SYM_X:
         return (NOSYM);
      case SYM_Y:
         return (SYMXY);
      case SYMXY:
         return (SYM_Y);
      case ROT_P:
         return (SY_RM);
      case ROT_M:
         return (SY_RP);
      case SY_RP:
         return (ROT_M);
      case SY_RM:
         return (ROT_P);
      default:
         (void) fprintf (stderr, "**post_trat**result_sym:unknown symetry number %d\n", second_sym);
         exit (1);
      }
   case SYM_Y:
      switch (second_sym)
      {
      case NOSYM:
         return (SYM_Y);
      case SYM_X:
         return (SYMXY);
      case SYM_Y:
         return (NOSYM);
      case SYMXY:
         return (SYM_X);
      case ROT_P:
         return (SY_RP);
      case ROT_M:
         return (SY_RM);
      case SY_RP:
         return (ROT_P);
      case SY_RM:
         return (ROT_M);
      default:
         (void) fprintf (stderr, "**post_trat**result_sym:unknown symetry number %d\n", second_sym);
         exit (1);
      }
   case SYMXY:
      switch (second_sym)
      {
      case NOSYM:
         return (SYMXY);
      case SYM_X:
         return (SYM_Y);
      case SYM_Y:
         return (SYM_X);
      case SYMXY:
         return (NOSYM);
      case ROT_P:
         return (ROT_M);
      case ROT_M:
         return (ROT_P);
      case SY_RP:
         return (SY_RM);
      case SY_RM:
         return (SY_RP);
      default:
         (void) fprintf (stderr, "**post_trat**result_sym:unknown symetry number %d\n", second_sym);
         exit (1);
      }
   case ROT_P:
      switch (second_sym)
      {
      case NOSYM:
         return (ROT_P);
      case SYM_X:
         return (SY_RP);
      case SYM_Y:
         return (SY_RM);
      case SYMXY:
         return (ROT_M);
      case ROT_P:
         return (SYMXY);
      case ROT_M:
         return (NOSYM);
      case SY_RP:
         return (SYM_Y);
      case SY_RM:
         return (SYM_X);
      default:
         (void) fprintf (stderr, "**post_trat**result_sym:unknown symetry number %d\n", second_sym);
         exit (1);
      }
   case ROT_M:
      switch (second_sym)
      {
      case NOSYM:
         return (ROT_M);
      case SYM_X:
         return (SY_RM);
      case SYM_Y:
         return (SY_RP);
      case SYMXY:
         return (ROT_P);
      case ROT_P:
         return (NOSYM);
      case ROT_M:
         return (SYMXY);
      case SY_RP:
         return (SYM_X);
      case SY_RM:
         return (SYM_Y);
      default:
         (void) fprintf (stderr, "**post_trat**result_sym:unknown symetry number %d\n", second_sym);
         exit (1);
      }
   case SY_RP:
      switch (second_sym)
      {
      case NOSYM:
         return (SY_RP);
      case SYM_X:
         return (ROT_P);
      case SYM_Y:
         return (ROT_M);
      case SYMXY:
         return (SY_RM);
      case ROT_P:
         return (SYM_X);
      case ROT_M:
         return (SYM_Y);
      case SY_RP:
         return (NOSYM);
      case SY_RM:
         return (SYMXY);
      default:
         (void) fprintf (stderr, "**post_trat**result_sym:unknown symetry number %d\n", second_sym);
         exit (1);
      }
   case SY_RM:
      switch (second_sym)
      {
      case NOSYM:
         return (SY_RM);
      case SYM_X:
         return (ROT_M);
      case SYM_Y:
         return (ROT_P);
      case SYMXY:
         return (SY_RP);
      case ROT_P:
         return (SYM_Y);
      case ROT_M:
         return (SYM_X);
      case SY_RP:
         return (SYMXY);
      case SY_RM:
         return (NOSYM);
      default:
         (void) fprintf (stderr, "**post_trat**result_sym:unknown symetry number %d\n", second_sym);
         exit (1);
      }
   default:
      (void) fprintf (stderr, "**post_trat**result_sym:unknown symetry number %d\n", first_sym);
      exit (1);
   }
   return (NOSYM);
}

/*****************************************************************************
 * flatten_instance_layer: copies to the given layer_tail, all the segments
 *                         in the given instance that intersect the couron of
 *                         the given ancetre, using the given father_sym
 *                         to compose the resulting symmetry of the instance
 *                         in the ancetre.
 *                         The segments of the sons instances are copied also
 *                         as it is a recursive function.
 ******************************************************************************/
static void flatten_instance_layer (instance, ancetre, comp_sym, origin_x, origin_y, layer_tail, layer_num)
     rdsins_list *instance;     /* instance where there is rectangles to flatten */
     rdsins_list *ancetre;      /* first instance where the ring is defined */
     char comp_sym;             /* symetry comp of instances without the first */
     long origin_x, origin_y;   /* origin comp of instances without the first */
     rds_rectanglep_typ *layer_tail;
     int layer_num;
{
   rdsfig_list *modelp;
   rdsins_list *instancef;
   long nx, ny, ndx, ndy;
   long dummy1, dummy2;
   long new_origin_x, new_origin_y;
   rdsrec_list *rectp;

   modelp = rds_model_out (instance->FIGNAME);
   if (incataloggds (instance->FIGNAME))
      return;

   dummy1 = 0l;
   dummy2 = 0l;
   new_origin_x = origin_x;
   new_origin_y = origin_y;
   origin_x = instance->X;
   origin_y = instance->Y;
   adjust_rectangle (&origin_x, &origin_y, &dummy1, &dummy2, new_origin_x, new_origin_y, comp_sym);
   comp_sym = result_sym (instance->TRANSF, comp_sym);

   for (instancef = modelp->INSTANCE; instancef; instancef = instancef->NEXT)
      flatten_instance_layer (instancef, ancetre, comp_sym, origin_x, origin_y, layer_tail, layer_num);

   for (rectp = modelp->LAYERTAB[layer_num]; rectp; rectp = rectp->NEXT)
   {
      if (IsRdsConExter (rectp))
         continue;
      if (IsRdsRefRef (rectp))
         continue;
      if (IsRdsRefCon (rectp))
         continue;

      nx = rectp->X;
      ny = rectp->Y;
      ndx = rectp->DX;
      ndy = rectp->DY;

      adjust_rectangle (&nx, &ny, &ndx, &ndy, origin_x, origin_y, comp_sym);
      if ((nx <= ancetre->COURONNE[layer_num]->X)
          || (ny <= ancetre->COURONNE[layer_num]->Y)
          || ((nx + ndx) >= ancetre->COURONNE[layer_num]->DX) || ((ny + ndy) >= ancetre->COURONNE[layer_num]->DY))
      {
         adjust_rectangle (&nx, &ny, &ndx, &ndy, ancetre->X, ancetre->Y, ancetre->TRANSF);

         *layer_tail = rds_rectangle_in (*layer_tail, nx, ny, ndx, ndy, layer_num, rectp->FLAGS, NULL);
         mark_flattenres (*layer_tail);
      }
   }
}

/******************************************************************************
 * flatten_layer: copies from: all the instances in the specified model in the
 *                             the specified layer any rectangle that intersects
 *                             the couron of the instance or even touches it.
 *                         to: the list of rectangles of the specified model in
 *                             th specified layer.
 *                A flattened rectangle is marked (flattened) so that if it is
 *                not used in the merging stage, it will be removed in the
 *                cleanning stage.
 *                remark: if there is more than 2 hierarchical levels, there
 *                will be a call to the flatten_instance_layer() function.
 *****************************************************************************/
static void flatten_layer (model, layer_num)
     rdsfig_list *model;
     int layer_num;
{
   rdsins_list *instance, *instancef;
   rdsrec_list *rectp;
   rds_rectanglep_typ *layer_tail;
   rdsfig_list *modelp;
   long nx, ny, ndx, ndy;

   /* get the tail of the list of segments of the model */
   for (rectp = model->LAYERTAB[layer_num]; (rectp && rectp->NEXT); rectp = rectp->NEXT)
      ;
   if (rectp)
      layer_tail = &(rectp->NEXT);
   else
      layer_tail = &(model->LAYERTAB[layer_num]);

   for (instance = model->INSTANCE; instance; instance = instance->NEXT)
   {
      modelp = rds_model_out (instance->FIGNAME);
      if (incataloggds (instance->FIGNAME))
         continue;
      /* flatten lower levels of the hierarchy */
      for (instancef = modelp->INSTANCE; instancef; instancef = instancef->NEXT)
      {
         flatten_instance_layer (instancef, instance, NOSYM, /* no symetry for the model */
                                 0l, 0l, layer_tail, layer_num);
      }
      /* flatten the instances of the model */
      for (rectp = modelp->LAYERTAB[layer_num]; rectp; rectp = rectp->NEXT)
      {
         nx = rectp->X;
         ny = rectp->Y;
         ndx = rectp->DX;
         ndy = rectp->DY;
         if ((nx <= instance->COURONNE[layer_num]->X)
             || (ny <= instance->COURONNE[layer_num]->Y)
             || ((nx + ndx) >= instance->COURONNE[layer_num]->DX) || ((ny + ndy) >= instance->COURONNE[layer_num]->DY))
         {
            adjust_rectangle (&nx, &ny, &ndx, &ndy, instance->X, instance->Y, instance->TRANSF);
            *layer_tail = rds_rectangle_in (*layer_tail, nx, ny, ndx, ndy, layer_num, rectp->FLAGS, NULL);
            mark_flattenres (*layer_tail);
         }
      }
   }
}

/*****************************************************************************
 * envelop_layer: defines the envelop of the specified model in the specified
 *                layer.
 *                i.e. the minimum rectangle that contains all the rectangles
 *                and all the envelops of all instances of the specified model
 *                in the specified layer.
 *                This function as it takes into consideration the envelops
 *                of the instances of the model it must be applied to the
 *                instances before the father model; what is done implicitly
 *                by the post_treat function.
 *                This function once applied on a model at a layer, marks that
 *                model enveloped at that layer.
 *                If the model at that layer does not contain any rectangles,
 *                it is marked empty at that layer.
 ****************************************************************************/
static void envelop_layer (model, layer_num)
     rdsfig_list *model;
     int layer_num;
{
   rdsfig_list *modelp;
   rdsins_list *instancep;
   long lx, ly, gx, gy;
   rdsrec_list *rectp;
   char init = 0;
   long nx, ny, ndx, ndy;

   /* printf("envelop %d\n",layer_num); */

   lx = ly = gx = gy = 0;

   /* segments of the model */
   if (model->LAYERTAB[layer_num])
   {
      lx = model->LAYERTAB[layer_num]->X;
      ly = model->LAYERTAB[layer_num]->Y;
      gx = model->LAYERTAB[layer_num]->X + model->LAYERTAB[layer_num]->DX;
      gy = model->LAYERTAB[layer_num]->Y + model->LAYERTAB[layer_num]->DY;
      init = 1;
      for (rectp = model->LAYERTAB[layer_num]; rectp; rectp = rectp->NEXT)
      {
         if (rectp->X < lx)
            lx = rectp->X;
         if (rectp->Y < ly)
            ly = rectp->Y;
         if ((rectp->X + rectp->DX) > gx)
            gx = rectp->X + rectp->DX;
         if ((rectp->Y + rectp->DY) > gy)
            gy = rectp->Y + rectp->DY;
      }
   }
   /* envelops of the instances of the model */
   for (instancep = model->INSTANCE; instancep; instancep = instancep->NEXT)
   {
      modelp = rds_model_out (instancep->FIGNAME);
      if (!(is_empty (modelp, layer_num)) && !(incataloggds (instancep->FIGNAME)))
      {
         rectp = modelp->BBOXTAB[layer_num];
         nx = rectp->X;
         ny = rectp->Y;
         ndx = rectp->DX;
         ndy = rectp->DY;
         adjust_rectangle (&nx, &ny, &ndx, &ndy, instancep->X, instancep->Y, instancep->TRANSF);
         if (init)
         {
            if (nx < lx)
               lx = nx;
            if (ny < ly)
               ly = ny;
            if ((nx + ndx) > gx)
               gx = nx + ndx;
            if ((ny + ndy) > gy)
               gy = ny + ndy;
         }
         else
         {
            lx = nx;
            ly = ny;
            gx = nx + ndx;
            gy = ny + ndy;
            init = 1;
         }
      }
   }
   if (init)
      model->BBOXTAB[layer_num] =
/* A VOIR 5 mai 1994
        rds_rectangle_in( model->BBOXTAB[ layer_num], lx,  ly,
                          gx - lx,  gy - ly, layer_num, rectp->FLAG, NULL );
 */
         rds_rectangle_in (model->BBOXTAB[layer_num], lx, ly, gx - lx, gy - ly, layer_num, NULL);
   else
      mark_empty (model, layer_num);
}

/*****************************************************************************
 * mod_ins_couron: given an instance, a layer and the rectangle of intersection
 *                 of this instance with another instance; it modifies the
 *                 couron of this instance in that layer if the rectangle of
 *                 intersection makes the couron wider at any side.
 *****************************************************************************/
static void mod_ins_couron (instance, layer_num, xi, yi, dxi, dyi)
     rdsins_list *instance;
     int layer_num;
     long xi, yi, dxi, dyi;
{
   rdsfig_list *model;
   long corn_width, xe, ye, dxe, dye;

   model = rds_model_out (instance->FIGNAME);

   corn_width = GET_S2R_RING_WIDTH (layer_num) + GET_S2R_LAYER_WIDTH (layer_num) / 2;
   xe = model->BBOXTAB[layer_num]->X;
   ye = model->BBOXTAB[layer_num]->Y;
   dxe = model->BBOXTAB[layer_num]->DX;
   dye = model->BBOXTAB[layer_num]->DY;

   readjust_rectangle (&xi, &yi, &dxi, &dyi, instance->X, instance->Y, instance->TRANSF);

   if ((xi - xe) > ((xe + dxe) - (xi + dxi)))
   {
      if ((xi - corn_width) < instance->COURONNE[layer_num]->DX)
         instance->COURONNE[layer_num]->DX = xi - corn_width;
   }
   else if ((xi + dxi + corn_width) > instance->COURONNE[layer_num]->X)
      instance->COURONNE[layer_num]->X = xi + dxi + corn_width;

   if ((yi - ye) > ((ye + dye) - (yi + dyi)))
   {
      if ((yi - corn_width) < instance->COURONNE[layer_num]->DY)
         instance->COURONNE[layer_num]->DY = yi - corn_width;
   }
   else if ((yi + dyi + corn_width) > instance->COURONNE[layer_num]->Y)
      instance->COURONNE[layer_num]->Y = yi + dyi + corn_width;
}

/*****************************************************************************
 * couron_layer: defines the courons of every instance in the specified model
 *               in the specified layer.
 *               The couron is determined by 4 limits: x, y, dx
 *               and dy beyond which is the couron area.
 * ATTENTION! dx et dy ne sont pas les longueurs mais les positions hautes
 *            et droites des couronnes dans couronne[]
 ****************************************************************************/
static void couron_layer (model, layer_num, verbose)
     rdsfig_list *model;
     int layer_num;
     int verbose;
{
   register rdsins_list *instance1, *instance2;
   long x1, x2, y1, y2, dx1, dx2, dy1, dy2, rx, rdx, ry, rdy;
   register rdsfig_list *model1, *model2;
   long corn_width;
   long dot = 0, nb_inst = 0, prc = 0, new_prc = 0, iteration, first = 1;

   corn_width = GET_S2R_RING_WIDTH (layer_num) + GET_S2R_LAYER_WIDTH (layer_num) / 2;

/*\
 * initial couron based on the abutment box and the envelop
\*/
   for (instance1 = model->INSTANCE, nb_inst = 0; instance1; instance1 = instance1->NEXT, nb_inst++)
   {
      model1 = rds_model_out (instance1->FIGNAME);
      if (incataloggds (instance1->FIGNAME))
         continue;
/*\
 * allocation d'une structure rectancle pour la couronne[layer_num]
\*/
      instance1->COURONNE[layer_num] = (rdsrec_list *) mbkalloc (sizeof (rdsrec_list));
      instance1->COURONNE[layer_num]->DY = model1->LAYERTAB[RDS_ABOX]->Y + model1->LAYERTAB[RDS_ABOX]->DY - corn_width;
      instance1->COURONNE[layer_num]->Y = model1->LAYERTAB[RDS_ABOX]->Y + corn_width;
      instance1->COURONNE[layer_num]->DX = model1->LAYERTAB[RDS_ABOX]->X + model1->LAYERTAB[RDS_ABOX]->DX - corn_width;
      instance1->COURONNE[layer_num]->X = model1->LAYERTAB[RDS_ABOX]->X + corn_width;

      if (!is_empty (model1, layer_num))
      {
         if (instance1->COURONNE[layer_num]->DY > (model1->BBOXTAB[layer_num]->Y + model1->BBOXTAB[layer_num]->DY - corn_width))
         {
            instance1->COURONNE[layer_num]->DY = model1->BBOXTAB[layer_num]->Y + model1->BBOXTAB[layer_num]->DY - corn_width;
         }
         if (instance1->COURONNE[layer_num]->Y < (model1->BBOXTAB[layer_num]->Y + corn_width))
         {
            instance1->COURONNE[layer_num]->Y = model1->BBOXTAB[layer_num]->Y + corn_width;
         }
         if (instance1->COURONNE[layer_num]->DX > (model1->BBOXTAB[layer_num]->X + model1->BBOXTAB[layer_num]->DX - corn_width))
         {
            instance1->COURONNE[layer_num]->DX = model1->BBOXTAB[layer_num]->X + model1->BBOXTAB[layer_num]->DX - corn_width;
         }
         if (instance1->COURONNE[layer_num]->X < (model1->BBOXTAB[layer_num]->X + corn_width))
         {
            instance1->COURONNE[layer_num]->X = model1->BBOXTAB[layer_num]->X + corn_width;
         }
      }
   }
/*\
 * final couron based on instance intersections
\*/
   for (instance1 = model->INSTANCE, iteration = 0; instance1; instance1 = instance1->NEXT, iteration++)
   {
      model1 = rds_model_out (instance1->FIGNAME);

      if (incataloggds (instance1->FIGNAME))
         continue;

      if (verbose)
      {
         if (first)
         {
            printf ("\t    . %s ", RDS_LAYER_NAME[layer_num]);
            first = 0;
         }
         new_prc = (iteration * 100 / nb_inst) / 3; /* one dot each 3% */
         if (new_prc > prc)
         {
            dot++;
            printf (".");
            fflush (stdout);
            prc = new_prc;
         }
      }

      if (!(is_empty (model1, layer_num)))
      {
         x1 = model1->BBOXTAB[layer_num]->X;
         y1 = model1->BBOXTAB[layer_num]->Y;
         dx1 = model1->BBOXTAB[layer_num]->DX;
         dy1 = model1->BBOXTAB[layer_num]->DY;

         adjust_rectangle (&x1, &y1, &dx1, &dy1, instance1->X, instance1->Y, instance1->TRANSF);

         for (instance2 = instance1->NEXT; instance2; instance2 = instance2->NEXT)
         {
            model2 = rds_model_out (instance2->FIGNAME);

            if (incataloggds (instance2->FIGNAME))
            {
               continue;
            }

            if (!(is_empty (model2, layer_num)))
            {
               x2 = model2->BBOXTAB[layer_num]->X;
               y2 = model2->BBOXTAB[layer_num]->Y;
               dx2 = model2->BBOXTAB[layer_num]->DX;
               dy2 = model2->BBOXTAB[layer_num]->DY;

               adjust_rectangle (&x2, &y2, &dx2, &dy2, instance2->X, instance2->Y, instance2->TRANSF);

               if (rect_intersec (x1, x2, dx1, dx2, y1, y2, dy1, dy2, &rx, &rdx, &ry, &rdy))
               {
                  mod_ins_couron (instance1, layer_num, rx, ry, rdx, rdy);
                  mod_ins_couron (instance2, layer_num, rx, ry, rdx, rdy);
               }
            }
         }
      }
   }
   if (verbose && !first)
   {
      for (; dot < 33; dot++)
         printf (".");
      printf ("\n");
      fflush (stdout);
   }
}

/******************************************************************************
 * cutcut : cut off layer shape from layer board in model
 *****************************************************************************/

void cutcut (model, board, shape)
     rdsfig_list *model;
     int board;                 /* layer number to cut */
     int shape;                 /* layer number of shapes to cut */
{
  rdsrec_list *rshp, *rbrd, *rbrd_end;
  int f = MBK_SEGMENT_MASK | RDS_FIG_REC_MASK;
  ht_t *dejavu;
  char buffer[1000];

  for (rbrd_end=model->LAYERTAB[board]; rbrd_end->NEXT; rbrd_end=rbrd_end->NEXT);

  dejavu = htinit (63179);
  for (rbrd = model->LAYERTAB[board]; rbrd; rbrd = rbrd->NEXT)
  {
    for (rshp = model->LAYERTAB[shape]; rshp; rshp = rshp->NEXT)
    {
      int rx, rdx, ry, rdy;
      if (rect_intersec (rshp->X, rbrd->X, rshp->DX, rbrd->DX, rshp->Y, rbrd->Y, rshp->DY, rbrd->DY, &rx, &rdx, &ry, &rdy))
      {
        if ((rdx > 0) && (rdy > 0))
        {
          mark_remove (rbrd);
          if (rx > (rbrd->X))  /* need right rectangle */
          {
            int nx = rbrd->X, ny = rbrd->Y, ndx = rx - (rbrd->X), ndy = rbrd->DY;
            sprintf (buffer, "%d %d %d %d", nx, ny, ndx, ndy);
            if (!htget (dejavu, buffer))
            {
              htset (dejavu, buffer);
              rbrd_end->NEXT = rds_rectangle_in (NULL, nx, ny, ndx, ndy, board, f, NULL);
              rbrd_end = rbrd_end->NEXT;
            }
          }
          if (ry > (rbrd->Y))  /* need bottom rectangle */
          {
            int nx = rbrd->X, ny = rbrd->Y, ndx = rbrd->DX, ndy = ry - (rbrd->Y);
            sprintf (buffer, "%d %d %d %d", nx, ny, ndx, ndy);
            if (!htget (dejavu, buffer))
            {
              htset (dejavu, buffer);
              rbrd_end->NEXT = rds_rectangle_in (NULL, nx, ny, ndx, ndy, board, f, NULL);
              rbrd_end = rbrd_end->NEXT;
            }
          }
          if (ry + rdy < (rbrd->Y + rbrd->DY)) /* need top rectangle */
          {
            int nx = rbrd->X, ny = ry + rdy, ndx = rbrd->DX, ndy = (rbrd->Y + rbrd->DY) - (ry + rdy);
            sprintf (buffer, "%d %d %d %d", nx, ny, ndx, ndy);
            if (!htget (dejavu, buffer))
            {
              htset (dejavu, buffer);
              rbrd_end->NEXT = rds_rectangle_in (NULL, nx, ny, ndx, ndy, board, f, NULL);
              rbrd_end = rbrd_end->NEXT;
            }
          }
          if (rx + rdx < (rbrd->X + rbrd->DX)) /* need left rectangle */
          {
            int nx = rx + rdx, ny = rbrd->Y, ndx = (rbrd->X + rbrd->DX) - (rx + rdx), ndy = rbrd->DY;
            sprintf (buffer, "%d %d %d %d", nx, ny, ndx, ndy);
            if (!htget (dejavu, buffer))
            {
              htset (dejavu, buffer);
              rbrd_end->NEXT = rds_rectangle_in (NULL, nx, ny, ndx, ndy, board, f, NULL);
              rbrd_end = rbrd_end->NEXT;
            }
          }
        }
      }
    }
  }
  rds_remove_rectangle (&(model->LAYERTAB[board]));
  htremove (dejavu);
}

/******************************************************************************
 * addpwell: define RDS_PWELL <- RDS_ABOX - RDS_NWELL
 *        only on terminal cells (without instance) having NWELL rectangle
 *****************************************************************************/
static void addpwell (model, verbose)
     rdsfig_list *model;
     int verbose;
{
  if (model->INSTANCE == NULL)
  {
    if ((model->LAYERTAB[RDS_ABOX]) == NULL)
    {
      (void) fprintf (stderr, "**post_trat**addpwell:cell %s has none ABOX\n", model->NAME);
      exit (1);
    }
    if (((model->LAYERTAB[RDS_ABOX])->NEXT) != NULL)
    {
      (void) fprintf (stderr, "**post_trat**addpwell:cell %s has more than one ABOX\n", model->NAME);
      exit (1);
    }
    if (model->LAYERTAB[RDS_NWELL] != NULL)
    {
      rdsrec_list *rectab = model->LAYERTAB[RDS_ABOX];
      int f = MBK_SEGMENT_MASK | RDS_FIG_REC_MASK;
      long qty = GET_S2R_OVERSIZE (RDS_NIMP);

      // ajout d'un rectangle de PWELL avec la taille de l'ABOX + OVERSIZE(RDS_NIMP)
      // puis on on elimine le PWELL qui intersecte le NWELL
      model->LAYERTAB[RDS_PWELL] = rds_rectangle_in (NULL, rectab->X-qty, rectab->Y-qty, rectab->DX+2*qty, rectab->DY+2*qty, RDS_PWELL,f,NULL);
      cutcut (model, RDS_PWELL, RDS_NWELL);

      // on recalcule de NWELL a partir du PWELL
      model->LAYERTAB[RDS_NWELL] = rds_rectangle_in (NULL, rectab->X-qty, rectab->Y-qty, rectab->DX+2*qty, rectab->DY+2*qty, RDS_PWELL,f,NULL);
      cutcut (model, RDS_NWELL, RDS_PWELL);
    }
  }
}

/******************************************************************************
 * addpimp: define on NWELL RDS_PIMP <- RDS_WELL - RDS_NIMP
 *        only on terminal cells (without instance) having NWELL rectangle
 * put RDS_PIMP  all over NWELL 
 * put RDS_NIMP  all over PWELL 
 *****************************************************************************/
static void addimp (model, verbose)
     rdsfig_list *model;
     int verbose;
{
  rdsrec_list *r;
  int f = MBK_SEGMENT_MASK | RDS_FIG_REC_MASK;

  if (model->INSTANCE == NULL && model->LAYERTAB[RDS_NWELL] != NULL)
  {
    model->LAYERTAB[RDS_PIMP] = NULL;
    model->LAYERTAB[RDS_NIMP] = NULL;
    
    for (r = model->LAYERTAB[RDS_NWELL]; r; r = r->NEXT)
      model->LAYERTAB[RDS_PIMP] = rds_rectangle_in (model->LAYERTAB[RDS_PIMP], r->X, r->Y, r->DX, r->DY, RDS_PIMP, f, NULL);
    for (r = model->LAYERTAB[RDS_PWELL]; r; r = r->NEXT)
      model->LAYERTAB[RDS_NIMP] = rds_rectangle_in (model->LAYERTAB[RDS_NIMP], r->X, r->Y, r->DX, r->DY, RDS_NIMP, f, NULL);

    if (model->LAYERTAB[RDS_NIMP] != NULL)
       cutcut (model, RDS_NIMP, RDS_PTIE);
    if (model->LAYERTAB[RDS_PIMP] != NULL) 
       cutcut (model, RDS_PIMP, RDS_NTIE);
  }
}

/******************************************************************************
 * envelop: envelops the post_treatable layers of the given model.
 *****************************************************************************/
static void envelop (model)
     rdsfig_list *model;
{
   int layer_num;

   for (layer_num = 0; layer_num < RDS_MAX_LAYER; layer_num++)
   {
      if (GET_S2R_POST_Y_OR_N (layer_num) == S2R_TREAT)
      {
         envelop_layer (model, layer_num);
      }
   }
}

/******************************************************************************
 * couron: courons the post_treatable layers of the given model.
 *****************************************************************************/
static void couron (model, verbose)
     rdsfig_list *model;
     int verbose;
{
   int layer_num;

   for (layer_num = 0; layer_num < RDS_MAX_LAYER; layer_num++)
   {
      if ((GET_S2R_POST_Y_OR_N (layer_num) == S2R_TREAT) && (GET_S2R_RING_WIDTH (layer_num) != 0))
      {
         couron_layer (model, layer_num, verbose);
      }
   }
}

/******************************************************************************
 * flatten: flattens the post_treatable layers of the model.
 *****************************************************************************/
static void flatten (model)
     rdsfig_list *model;
{
   int layer_num;

   for (layer_num = 0; layer_num < RDS_MAX_LAYER; layer_num++)
   {
      if ((GET_S2R_POST_Y_OR_N (layer_num) == S2R_TREAT) && (GET_S2R_RING_WIDTH (layer_num) != 0))
      {
         flatten_layer (model, layer_num);
      }
   }
}

/******************************************************************************
 * resize: oversize all post_treatable layers of the model
 *****************************************************************************/
static void resize (model)
     rdsfig_list *model;
{
   int layer_num;

   for (layer_num = 0; layer_num < RDS_MAX_LAYER; layer_num++)
   {
      if (GET_S2R_POST_Y_OR_N (layer_num) == S2R_TREAT)
      {
         resize_layer (model, layer_num);
      }
   }
}

/******************************************************************************
 * merge: merges all post_treatable layers of the model.
 *        If the layer to be merged is of the type that needs scotchs
 *        ( indicated by having a complementary layer in its postreat table),
 *        merge_layer_2() will be called instead of merge_layer().
 *****************************************************************************/
static void merge (model, scotch_on_flag, verbose)
     rdsfig_list *model;
     int scotch_on_flag, verbose;
{
   int layer_num;

   for (layer_num = 0; layer_num < RDS_MAX_LAYER; layer_num++)
   {
      if (GET_S2R_POST_Y_OR_N (layer_num) == S2R_TREAT)
      {
         if ((GET_S2R_POST_COMPLEMENTARY (layer_num) != RDS_S2R_POST_TREAT_EMPTY) && scotch_on_flag)
         {
            merge_layer_2 (model, layer_num, verbose);
         }
         else
         {
            merge_layer (model, layer_num, verbose);
         }
      }
   }
}

/******************************************************************************
 * clean: cleans all post_treatable layers.
 *****************************************************************************/
static void clean (model)
     rdsfig_list *model;
{
   int layer_num;

   for (layer_num = 0; layer_num < RDS_MAX_LAYER; layer_num++)
   {
      if (GET_S2R_POST_Y_OR_N (layer_num) == S2R_TREAT)
      {
         rds_clean_layer (&(model->LAYERTAB[layer_num]));
      }
   }
}

/******************************************************************************
 * inv_resize: undersizes all post_treatable layers.
 *****************************************************************************/
static void inv_resize (model)
     rdsfig_list *model;
{
   int layer_num;

   for (layer_num = 0; layer_num < RDS_MAX_LAYER; layer_num++)
   {
      if (GET_S2R_POST_Y_OR_N (layer_num) == S2R_TREAT)
      {
         inv_resize_layer (model, layer_num);
      }
   }
}

/*****************************************************************************
 * post_treat: post_treats the specified model.
 *             After completion it marks this model at this layer post_treated.
 *             This is a recursive function: if an instance of this model
 *             has its model not yet post treated at this layer, it is
 *             post treated first.
 ****************************************************************************/
void post_treat (model, scotch_on_flag, verbose, autoimp)
     rdsfig_list *model;
     int scotch_on_flag;
     int verbose;
     int autoimp;
{
   rdsins_list *instance;
   rdsfig_list *modelp;

   for (instance = model->INSTANCE; instance; instance = instance->NEXT)
   {
      modelp = rds_model_out (instance->FIGNAME);

      if (!modelp->FLAGS && !incataloggds (modelp->NAME))
      {
         post_treat (modelp, scotch_on_flag, verbose, autoimp);
      }
   }
   if (verbose)
      printf ("\t--> post-treating model %s\n", model->NAME);
   if (verbose && model->INSTANCE)
   {
      printf ("\t    ring flattenning  : \n");
      fflush (stdout);
   }
   if (!incataloggds (model->NAME))
   {
      envelop (model);
      couron (model, verbose);
      flatten (model);
      resize (model);
      if (verbose)
      {
         printf ("\t    rectangle merging : \n");
         fflush (stdout);
      }
      merge (model, scotch_on_flag, verbose);
      clean (model);
      inv_resize (model);
      if (autoimp)
      {
         addpwell (model, verbose);
         addimp (model, verbose);
      }
      mark_treat (model);
   }
}

/*******************************************************************************
 * replace_cells: traverses the list of models and replaces the models that are
 *                found in the gds catalog by the corresponding models parsed
 *                from this catalog.
 *                remarks:
 ******************************************************************************/
void replace_cells (verbose)
     int verbose;
{
   rdsfig_list *model, *model_next;
   static int not_print_yet = 1;
   char *model_name;

   for (model = HEAD_RDSFIG; model;)
   {
      model_next = model->NEXT;
      if (incataloggds (model->NAME))
      {
         if (not_print_yet)
         {
            printf ("\to replacing black boxes\n");
            not_print_yet = 0;
         }
         if (verbose)
            printf ("\t--> replace cell %s \n", model->NAME);
         model_name = model->NAME;
         delrdsfig (model_name);
         (void) getrdsfig (model_name, 'A', 0);
      }
      model = model_next;
   }
}
