
#ifndef lint
static char rcsid[] __attribute__ ((unused)) = "$Header: /usr/cvsroot/magic-8.0/resis/ResMakeRes.c,v 1.3 2010/06/24 12:37:56 tim Exp $";
#endif  /* not lint */

#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <ctype.h>
#include <math.h>

#include "utils/magic.h"
#include "utils/geometry.h"
#include "utils/geofast.h"
#include "tiles/tile.h"
#include "utils/hash.h"
#include "database/database.h"
#include "utils/malloc.h"
#include "textio/textio.h"
#include "extract/extract.h"
#include "extract/extractInt.h"
#include "windows/windows.h"
#include "dbwind/dbwind.h"
#include "utils/tech.h"
#include "textio/txcommands.h"
#include "resis/resis.h"
#include "cif/CIFint.h"

/* Forward declarations */
bool ResCalcNearDevice();
bool ResCalcNorthSouth();
bool ResCalcEastWest();


/*
 *--------------------------------------------------------------------------
 *
 * ResCalcTileResistance-- Given a set of partitions for a tile, the tile can
 *	be converted into resistors. To do this, nodes are sorted in the 
 *	direction of current flow. Resistors are created by counting squares
 *	between successive breakpoints. Breakpoints with the same coordinate
 *	are combined.
 *
 *   Results: returns TRUE if the startnode was involved in a merge.
 *
 *   Side Effects:  Resistor structures are produced.  Some nodes may be
 *		    eliminated.
 *--------------------------------------------------------------------------
 *
 */

bool 
ResCalcTileResistance(tile, junk, pendingList, doneList)
    Tile 	*tile;
    tileJunk 	*junk;
    resNode	**pendingList, **doneList;

{
    int 	MaxX = MINFINITY, MinX = INFINITY;
    int		MaxY = MINFINITY, MinY = INFINITY;
    int		device;
    bool	merged;
    Breakpoint 	*p1;
     
    merged = FALSE;
    device = FALSE;
     
    if ((p1 = junk->breakList) == NULL) return FALSE;
    for (; p1; p1 = p1->br_next)
    {
	int	x = p1->br_loc.p_x;
	int	y = p1->br_loc.p_y;
	if (x > MaxX) MaxX = x;
	if (x < MinX) MinX = x;
	if (y > MaxY) MaxY = y;
	if (y < MinY) MinY = y;
	if (p1->br_this->rn_why == RES_NODE_DEVICE)
	{
	    device = TRUE;
	}
    }
     
    /* Finally, produce resistors for partition. Keep track of	*/
    /* whether or not the node was involved in a merge.		*/
     
    if (device)
    {
	merged |= ResCalcNearDevice(tile, pendingList, doneList, &ResResList);
    }
    else if (MaxY-MinY > MaxX-MinX)
    {
	merged |= ResCalcNorthSouth(tile, pendingList, doneList, &ResResList);
    }
    else
    {
	merged |= ResCalcEastWest(tile, pendingList, doneList, &ResResList);
    }

    /* 
     * For all the new resistors, propagate the resistance from the origin
     * to the new nodes.
     */

    return(merged);
}


/*
 *-------------------------------------------------------------------------
 *
 * ResCalcEastWest-- Makes resistors from an EastWest partition.
 *
 * Results: Returns TRUE if the sacredNode was involved in a merge.
 *
 * Side Effects: Makes resistors. Frees breakpoints.
 *
 *-------------------------------------------------------------------------
 */

bool
ResCalcEastWest(tile, pendingList, doneList, resList)
    Tile	*tile;
    resNode	**pendingList, **doneList;
    resResistor	**resList;
{
    int 	height;
    bool	merged;
    Breakpoint	*p1, *p2, *p3;
    resResistor	*resistor;
    resElement	*element;
    resNode	*currNode;
    float	rArea;
    tileJunk	*junk = (tileJunk *)tile->ti_client;
     
    merged = FALSE;
    height = TOP(tile) - BOTTOM(tile);

    /* 
     * One Breakpoint? No resistors need to be made. Free up the first
     * breakpoint, then return.
     */

    p1 = junk->breakList;
    if   (p1->br_next == NULL) 
    {
	p1->br_this->rn_float.rn_area += height * (LEFT(tile) - RIGHT(tile));
	freeMagic((char *)p1);
	junk->breakList = NULL;
	return(merged);
    }

    /* re-sort nodes left to right. */

    ResSortBreaks(&junk->breakList, TRUE);
     
    /* 
     * Eliminate breakpoints with the same X coordinate and merge 
     * their nodes.
     */

    p2= junk->breakList;

    /* add extra left area to leftmost node */

    p2->br_this->rn_float.rn_area += 	height*(p2->br_loc.p_x-LEFT(tile));
    while (p2->br_next != NULL)
    {
	p1 = p2;
	p2 = p2->br_next;
	if (p2->br_loc.p_x == p1->br_loc.p_x)
	{
	    if (p2->br_this == p1->br_this)
	    {
		 currNode = NULL;
		 p1->br_next = p2->br_next;
		 freeMagic((char *)p2);
		 p2 = p1;
	    }
	    else if (p2->br_this == resCurrentNode)
	    {
		 currNode = p1->br_this;
	    	 ResMergeNodes(p2->br_this,p1->br_this,pendingList,doneList);
		 merged = TRUE;
		 freeMagic((char *)p1);
	    }
	    else if (p1->br_this == resCurrentNode)
	    {
		 currNode = p2->br_this;
		 p1->br_next = p2->br_next;
	    	 ResMergeNodes(p1->br_this,p2->br_this,pendingList,doneList);
		 merged = TRUE;
		 freeMagic((char *)p2);
		 p2 = p1;
	    }
	    else
	    {
		 currNode = p1->br_this;
	    	 ResMergeNodes(p2->br_this,p1->br_this,pendingList,doneList);
		 freeMagic((char *)p1);
	    }

	    /* 
	     * Was the node used in another junk or breakpoint?
	     * If so, replace the old node with the new one.
	     */
	    p3  = p2->br_next;
	    while (p3 != NULL)
	    {
		if (p3->br_this == currNode)
		{
		     p3->br_this = p2->br_this;
		}
		p3 = p3->br_next;
	    }
       }

       /* 
        * If the X coordinates don't match, make a resistor between
        * the breakpoints.
        */

       else
       {
            resistor = (resResistor *) mallocMagic((unsigned) (sizeof(resResistor)));
            resistor->rr_nextResistor = (*resList);
            resistor->rr_lastResistor = NULL;
            if ((*resList) != NULL) (*resList)->rr_lastResistor = resistor;
            (*resList) = resistor;
            resistor->rr_connection1 = p1->br_this;
            resistor->rr_connection2 = p2->br_this;
            element = (resElement *) mallocMagic((unsigned) (sizeof(resElement)));
            element->re_nextEl = p1->br_this->rn_re;
            element->re_thisEl = resistor;
            p1->br_this->rn_re = element;
            element = (resElement *) mallocMagic((unsigned) (sizeof(resElement)));
            element->re_nextEl = p2->br_this->rn_re;
            element->re_thisEl = resistor;
            p2->br_this->rn_re = element;
	    resistor->rr_cl = (TOP(tile) + BOTTOM(tile)) >> 1;
	    resistor->rr_width = height;

	    if (IsSplit(tile))
	    {
		resistor->rr_tt = (SplitSide(tile)) ? SplitRightType(tile)
			: SplitLeftType(tile);
		resistor->rr_status = RES_DIAGONAL;
		resistor->rr_status |= (SplitDirection(tile)) ? RES_NS
			: RES_EW;
			
	    }
	    else
	    {
		resistor->rr_status = RES_EW;
		resistor->rr_tt = TiGetTypeExact(tile);
	    }
#ifdef ARIEL
	    resistor->rr_csArea = height *
				ExtCurStyle->exts_thick[resistor->rr_tt];
#endif
	    resistor->rr_value =
		    	  (ExtCurStyle->exts_sheetResist[resistor->rr_tt]
		          * (p2->br_loc.p_x-p1->br_loc.p_x)) / height;
	    rArea = ((p2->br_loc.p_x-p1->br_loc.p_x) * height) / 2;
	    resistor->rr_connection1->rn_float.rn_area += rArea;
	    resistor->rr_connection2->rn_float.rn_area += rArea;
	    resistor->rr_float.rr_area = 0;
		    
	    freeMagic((char *)p1);
	}
    }
    p2->br_this->rn_float.rn_area += height * (RIGHT(tile) - p2->br_loc.p_x);
    freeMagic((char *)p2);
    junk->breakList = NULL;
    return(merged);
}


/*
 *-------------------------------------------------------------------------
 *
 * ResCalcNorthSouth-- Makes resistors from a NorthSouth partition
 *
 * Results: Returns TRUE if the resCurrentNode was involved in a merge.
 *
 * Side Effects: Makes resistors. Frees breakpoints
 *
 *-------------------------------------------------------------------------
 */

bool
ResCalcNorthSouth(tile, pendingList, doneList, resList)
    Tile	*tile;
    resNode	**pendingList, **doneList;
    resResistor	**resList;
{
    int 	width;
    bool	merged;
    Breakpoint	*p1, *p2, *p3;
    resResistor	*resistor;
    resElement	*element;
    resNode	*currNode;
    float	rArea;
    tileJunk	*junk = (tileJunk *)tile->ti_client;
     
    merged = FALSE;
    width = RIGHT(tile)-LEFT(tile);

    /* 
     * One Breakpoint? No resistors need to be made. Free up the first
     * breakpoint, then return.
     */

    p1 = junk->breakList;
    if   (p1->br_next == NULL) 
    {
	p1->br_this->rn_float.rn_area += width * (TOP(tile) - BOTTOM(tile));
     	freeMagic((char *)p1);
	junk->breakList = NULL;
	return(merged);
    }

    /* re-sort nodes south to north. */
    ResSortBreaks(&junk->breakList, FALSE);

    /* 
     * Eliminate breakpoints with the same Y coordinate and merge 
     * their nodes.
     */

    p2 = junk->breakList;

    /* add extra left area to leftmost node */

    p2->br_this->rn_float.rn_area += width * (p2->br_loc.p_y - BOTTOM(tile));
    while (p2->br_next != NULL)
    {
	p1 = p2;
	p2 = p2->br_next;
	if (p1->br_loc.p_y == p2->br_loc.p_y)
	{
	    if (p2->br_this == p1->br_this)
	    {
		 currNode = NULL;
		 p1->br_next = p2->br_next;
		 freeMagic((char *)p2);
		 p2 = p1;
	    }
	    else if (p2->br_this == resCurrentNode)
	    {
		 currNode = p1->br_this;
	    	 ResMergeNodes(p2->br_this,p1->br_this,pendingList,doneList);
		 freeMagic((char *)p1);
		 merged = TRUE;
	    }
	    else if (p1->br_this == resCurrentNode)
	    {
		 currNode = p2->br_this;
		 p1->br_next = p2->br_next;
	    	 ResMergeNodes(p1->br_this,p2->br_this,pendingList,doneList);
		 merged = TRUE;
		 freeMagic((char *)p2);
		 p2 = p1;
	    }
	    else
	    {
		 currNode = p1->br_this;
	    	 ResMergeNodes(p2->br_this,p1->br_this,pendingList,doneList);
		 freeMagic((char *)p1);
	    }
		    
	    /* 
	     * Was the node used in another junk or breakpoint?
	     * If so, replace the old node with the new one.
	     */
	    p3  = p2->br_next;
	    while (p3 != NULL)
	    {
		if (p3->br_this == currNode)
		{
		     p3->br_this = p2->br_this;
		}
		p3 = p3->br_next;
	    }
	}

	/* 
	 * If the Y coordinates don't match, make a resistor between
	 * the breakpoints.
	 */

	else
	{
	    resistor = (resResistor *) mallocMagic((unsigned) (sizeof(resResistor)));
	    resistor->rr_nextResistor = (*resList);
	    resistor->rr_lastResistor = NULL;
	    if ((*resList) != NULL) (*resList)->rr_lastResistor = resistor;
	    (*resList) = resistor;
	    resistor->rr_connection1 = p1->br_this;
	    resistor->rr_connection2 = p2->br_this;
	    element = (resElement *) mallocMagic((unsigned) (sizeof(resElement)));
	    element->re_nextEl = p1->br_this->rn_re;
	    element->re_thisEl = resistor;
	    p1->br_this->rn_re = element;
	    element = (resElement *) mallocMagic((unsigned) (sizeof(resElement)));
	    element->re_nextEl = p2->br_this->rn_re;
	    element->re_thisEl = resistor;
	    p2->br_this->rn_re = element;
	    resistor->rr_cl = (LEFT(tile) + RIGHT(tile)) >> 1;
	    resistor->rr_width = width;
	    if (IsSplit(tile))
	    {
		resistor->rr_tt = (SplitSide(tile)) ? SplitRightType(tile)
			: SplitLeftType(tile);
		resistor->rr_status = RES_DIAGONAL;
		resistor->rr_status |= (SplitDirection(tile)) ? RES_NS
			: RES_EW;
	    }
	    else
	    {
		resistor->rr_status = RES_NS;
		resistor->rr_tt = TiGetTypeExact(tile);
	    }
#ifdef ARIEL
	    resistor->rr_csArea = width
			* ExtCurStyle->exts_thick[resistor->rr_tt];
#endif
	    resistor->rr_value =
		    	  (ExtCurStyle->exts_sheetResist[resistor->rr_tt]
		          * (p2->br_loc.p_y-p1->br_loc.p_y)) / width;
	    rArea = ((p2->br_loc.p_y-p1->br_loc.p_y) * width) / 2;
	    resistor->rr_connection1->rn_float.rn_area += rArea;
	    resistor->rr_connection2->rn_float.rn_area += rArea;
	    resistor->rr_float.rr_area = 0;
	    freeMagic((char *)p1);
	}
    }
    p2->br_this->rn_float.rn_area += width * (TOP(tile) - p2->br_loc.p_y);
    freeMagic((char *)p2);
    junk->breakList = NULL;
    return(merged);
}


/*
 *-------------------------------------------------------------------------
 *
 * ResCalcNearDevice-- Calculating the direction of current flow near
 *	devices is tricky because there are two adjoining regions with
 *	vastly different sheet resistances.  ResCalcNearDevice is called
 *	whenever a diffusion tile adjoining a real tile is found.  It makes
 *	a guess at the correct direction of current flow, removes extra 
 *	breakpoints, and call either ResCalcEastWest or ResCalcNorthSouth
 *
 * Results:
 *	TRUE if merging occurred, FALSE if not.
 *
 * Side Effects: Makes resistors. Frees breakpoints
 *
 *-------------------------------------------------------------------------
 */

bool
ResCalcNearDevice(tile, pendingList, doneList, resList)
    Tile	*tile;
    resNode	**pendingList, **doneList;
    resResistor	**resList;

{
     bool 		merged;
     int		devcount,devedge,deltax,deltay;
     Breakpoint		*p1,*p2,*p3;
     tileJunk		*junk = (tileJunk *)tile->ti_client;
     
     
     merged = FALSE;

     /* 
        One Breakpoint? No resistors need to be made. Free up the first
     	breakpoint, then return.
     */
     
     if   (junk->breakList->br_next == NULL) 
     {
     	  freeMagic((char *)junk->breakList);
	  junk->breakList = NULL;
	  return(merged);
     }
     /* count the number of device breakpoints  */
     /* mark which edge they connect to		    */
     devcount = 0;
     devedge = 0;
     for (p1=junk->breakList; p1 != NULL;p1 = p1->br_next)
     {
	  if (p1->br_this->rn_why == RES_NODE_DEVICE)
	  {
	       devcount++;
	       if (p1->br_loc.p_x == LEFT(tile)) devedge |= LEFTEDGE;
	       else if (p1->br_loc.p_x == RIGHT(tile)) devedge |= RIGHTEDGE;
	       else if (p1->br_loc.p_y == TOP(tile)) devedge |= TOPEDGE;
	       else if (p1->br_loc.p_y == BOTTOM(tile)) devedge |= BOTTOMEDGE;
	  }
     }
     /* use distance from device to next breakpoint as determinant     */
     /* if there is only one device or if all the devices are along */
     /* the same edge.							   */
     if (devcount == 1 		|| 
        (devedge & LEFTEDGE) == devedge	||
        (devedge & RIGHTEDGE) == devedge 	||
        (devedge & TOPEDGE) == devedge 	||
        (devedge & BOTTOMEDGE) == devedge)
     {
	  ResSortBreaks(&junk->breakList,TRUE);
          p2 = NULL;
          for (p1=junk->breakList; p1 != NULL;p1 = p1->br_next)
          {
	       if (p1->br_this->rn_why == RES_NODE_DEVICE)
	       {
	            break;
	       }
	       if (p1->br_next != NULL && 
	       	     (p1->br_loc.p_x != p1->br_next->br_loc.p_x ||
	       	      p1->br_loc.p_y != p1->br_next->br_loc.p_y))
	       
	       {
	       	    p2 = p1;
	       }
          }
	  deltax=INFINITY;
	  for (p3 = p1->br_next; 
	       p3 != NULL && 
	       p3->br_loc.p_x == p1->br_loc.p_x && 
	       p3->br_loc.p_y == p1->br_loc.p_y; p3 = p3->br_next);
	  if (p3 != NULL)
	  {
	       if (p3->br_crect)
	       {
	       	    if (p3->br_crect->r_ll.p_x > p1->br_loc.p_x)
		    {
		         deltax = p3->br_crect->r_ll.p_x-p1->br_loc.p_x;
		    }
	       	    else if (p3->br_crect->r_ur.p_x < p1->br_loc.p_x)
		    {
		         deltax = p1->br_loc.p_x-p3->br_crect->r_ur.p_x;
		    }
		    else
		    {
		    	 deltax=0;
		    }
	       }
	       else
	       {
	       deltax = abs(p1->br_loc.p_x-p3->br_loc.p_x);
	       }
	  }
	  if (p2 != NULL)
	  {
	       if (p2->br_crect)
	       {
	       	    if (p2->br_crect->r_ll.p_x > p1->br_loc.p_x)
		    {
		         deltax = MIN(deltax,p2->br_crect->r_ll.p_x-p1->br_loc.p_x);
		    }
	       	    else if (p2->br_crect->r_ur.p_x < p1->br_loc.p_x)
		    {
		         deltax = MIN(deltax,p1->br_loc.p_x-p2->br_crect->r_ur.p_x);
		    }
		    else
		    {
		    	 deltax=0;
		    }
	       }
	       else
	       {
	            deltax = MIN(deltax,abs(p1->br_loc.p_x-p2->br_loc.p_x));
	       }
	  }

          /* re-sort nodes south to north. */
	  ResSortBreaks(&junk->breakList,FALSE);
          p2 = NULL;
          for (p1=junk->breakList; p1 != NULL;p1 = p1->br_next)
          {
	       if (p1->br_this->rn_why == RES_NODE_DEVICE)
	       {
	            break;
	       }
	       if (p1->br_next != NULL && 
	       	     (p1->br_loc.p_x != p1->br_next->br_loc.p_x ||
	       	      p1->br_loc.p_y != p1->br_next->br_loc.p_y))
	       
	       {
	       	    p2 = p1;
	       }
          }
	  deltay=INFINITY;
	  for (p3 = p1->br_next; 
	       p3 != NULL && 
	       p3->br_loc.p_x == p1->br_loc.p_x && 
	       p3->br_loc.p_y == p1->br_loc.p_y; p3 = p3->br_next);
	  if (p3 != NULL)
	  {
	       if (p3->br_crect)
	       {
	       	    if (p3->br_crect->r_ll.p_y > p1->br_loc.p_y)
		    {
		         deltay = p3->br_crect->r_ll.p_y-p1->br_loc.p_y;
		    }
	       	    else if (p3->br_crect->r_ur.p_y < p1->br_loc.p_y)
		    {
		         deltay = p1->br_loc.p_y-p3->br_crect->r_ur.p_y;
		    }
		    else
		    {
		    	 deltay=0;
		    }
	       }
	       else
	       {
	       deltay = abs(p1->br_loc.p_y-p3->br_loc.p_y);
	       }
	  }
	  if (p2!= NULL)
	  {
	       if (p2->br_crect)
	       {
	       	    if (p2->br_crect->r_ll.p_y > p1->br_loc.p_y)
		    {
		         deltay = MIN(deltay,p2->br_crect->r_ll.p_y-p1->br_loc.p_y);
		    }
	       	    else if (p2->br_crect->r_ur.p_y < p1->br_loc.p_y)
		    {
		         deltay = MIN(deltay,p1->br_loc.p_y-p2->br_crect->r_ur.p_y);
		    }
		    else
		    {
		    	 deltay=0;
		    }
	       }
	       else
	       {
	            deltay = MIN(deltay,abs(p1->br_loc.p_y-p2->br_loc.p_y));
	       }
	  }
	  if (deltay > deltax)
	  {
	       return(ResCalcNorthSouth(tile,pendingList,doneList,resList));
	  }
	  else
	  {
	       return(ResCalcEastWest(tile,pendingList,doneList,resList));
	  }

     }
     /* multiple devices connected to the partition */
     else  
     {
     	  if (devedge == 0)
	  {
	       TxError("Error in device current direction routine\n");
	       return(merged);
	  }
	  /* check to see if the current flow is north-south		*/
	  /* possible north-south conditions:				*/
	  /* 1. there are devices along the top and bottom edges    */
	  /*    but not along the left or right			        */
	  /* 2. there are devices along two sides at right angles,  */
	  /*    and the tile is wider than it is tall.			*/
	  
	  if ((devedge & TOPEDGE)     && 
	      (devedge & BOTTOMEDGE)  &&
	      !(devedge & LEFTEDGE)   &&
	      !(devedge & RIGHTEDGE)  			||
	      (devedge & TOPEDGE || devedge & BOTTOMEDGE) &&
	      (devedge & LEFTEDGE || devedge & RIGHTEDGE) &&
	      RIGHT(tile)-LEFT(tile) > TOP(tile)-BOTTOM(tile))
	 {
               /* re-sort nodes south to north. */
	       ResSortBreaks(&junk->breakList,FALSE);

	      /* eliminate duplicate S/D pointers */
	      for (p1 = junk->breakList; p1 != NULL; p1 = p1->br_next)
	      {
	      	   if  (p1->br_this->rn_why == RES_NODE_DEVICE &&
		       (p1->br_loc.p_y == BOTTOM(tile) ||
		        p1->br_loc.p_y == TOP(tile)))
		   {
	      		p3 = NULL;
			p2 = junk->breakList;
			while ( p2 != NULL)
			{
			     if (p2->br_this == p1->br_this	&& 
			         p2 != p1			&&
				 p2->br_loc.p_y != BOTTOM(tile) &&
				 p2->br_loc.p_y != TOP(tile))
			     {
			     	  if (p3 == NULL)
				  {
				       junk->breakList = p2->br_next;
				       freeMagic((char *) p2);
				       p2 = junk->breakList;
				  }
				  else
				  {
				       p3->br_next = p2->br_next;
				       freeMagic((char *) p2);
				       p2 = p3->br_next;
				  }
			     }
			     else
			     {
			          p3 = p2;
				  p2 = p2->br_next;
			     }
			}
		   }
	      }
	      return(ResCalcNorthSouth(tile,pendingList,doneList,resList));
	 }
	 else
	 {
	      /* eliminate duplicate S/D pointers */
	      for (p1 = junk->breakList; p1 != NULL; p1 = p1->br_next)
	      {
	      	   if (p1->br_this->rn_why == RES_NODE_DEVICE &&
		       (p1->br_loc.p_x == LEFT(tile) ||
		        p1->br_loc.p_x == RIGHT(tile)))
		   {
	      		p3 = NULL;
			p2 = junk->breakList;
			while ( p2 != NULL)
			{
			     if (p2->br_this == p1->br_this	&& 
			         p2 != p1			&&
				 p2->br_loc.p_x != LEFT(tile) &&
				 p2->br_loc.p_x != RIGHT(tile))
			     {
			     	  if (p3 == NULL)
				  {
				       junk->breakList = p2->br_next;
				       freeMagic((char *) p2);
				       p2 = junk->breakList;
				  }
				  else
				  {
				       p3->br_next = p2->br_next;
				       freeMagic((char *) p2);
				       p2 = p3->br_next;
				  }
			     }
			     else
			     {
			          p3 = p2;
				  p2 = p2->br_next;
			     }
			}
		   }
	      }
	      return(ResCalcEastWest(tile,pendingList,doneList,resList));
	 }
     }
}


/*
 *-------------------------------------------------------------------------
 *
 * ResDoContacts-- Add node (or nodes) for a contact.  If there are contact
 *	resistances, also add a resistor.
 *
 * Results: 
 *	None.
 *
 * Side Effects: Creates nodes and resistors
 *
 *-------------------------------------------------------------------------
 */

void
ResDoContacts(contact, nodes, resList)
    ResContactPoint	*contact;
    resNode		**nodes;
    resResistor	**resList;
{
    resNode	 *resptr;
    cElement	 *ccell;
    int		 tilenum, squaresx, squaresy, viawidth;
    int 	 minside, spacing, border, cscale;
    float	 squaresf;
    resResistor	 *resistor;
    resElement	 *element;
    static int	 too_small = 1;
     
    minside = CIFGetContactSize(contact->cp_type, &viawidth, &spacing, &border);
    cscale = CIFCurStyle->cs_scaleFactor;

    if ((ExtCurStyle->exts_viaResist[contact->cp_type] == 0) || (viawidth == 0))
    {
	int x = contact->cp_center.p_x;
	int y = contact->cp_center.p_y;

	resptr = (resNode *) mallocMagic((unsigned) (sizeof(resNode)));
	InitializeNode(resptr,x,y,RES_NODE_CONTACT);
	ResAddToQueue(resptr,nodes);

 	ccell = (cElement *) mallocMagic((unsigned) (sizeof(cElement)));
	ccell->ce_nextc = resptr->rn_ce;
	resptr->rn_ce = ccell;
	ccell->ce_thisc = contact;

	/* add 1 celement for each layer of contact  */

	for (tilenum=0; tilenum < contact->cp_currentcontact; tilenum++)
	{
	    Tile	*tile = contact->cp_tile[tilenum];

	    contact->cp_cnode[tilenum] = resptr;
	    NEWBREAK(resptr, tile, contact->cp_center.p_x,
			contact->cp_center.p_y, &contact->cp_rect);
        }
    }
    else
    {
	if (((contact->cp_width * cscale) < minside) ||
		    ((contact->cp_height * cscale) < minside))
	{
	    if (too_small)
	    {
		TxError("Warning: %s at %d %d smaller than extract section allows\n",
	            DBTypeLongNameTbl[contact->cp_type],
	            contact->cp_center.p_x, contact->cp_center.p_y);
	        too_small = 0;
	    }
	    squaresx = squaresy = 1;
	}
	else
	{
	    viawidth += spacing;
	    squaresf = (float)((contact->cp_width * cscale) - minside) / (float)viawidth;
	    squaresf *= ExtCurStyle->exts_unitsPerLambda;
	    squaresf /= (float)viawidth;
	    squaresx = (int)squaresf;
	    squaresx++;

	    squaresf = (float)((contact->cp_height * cscale) - minside) / (float)viawidth;
	    squaresf *= ExtCurStyle->exts_unitsPerLambda;
	    squaresf /= (float)viawidth;
	    squaresy = (int)squaresf;
	    squaresy++;
	}
        for (tilenum=0; tilenum < contact->cp_currentcontact; tilenum++)
	{
      	    int  x = contact->cp_center.p_x;
      	    int  y = contact->cp_center.p_y;
	    Tile *tile = contact->cp_tile[tilenum];

	    resptr = (resNode *) mallocMagic((unsigned) (sizeof(resNode)));
	    InitializeNode(resptr,x,y,RES_NODE_CONTACT);
	    ResAddToQueue(resptr,nodes);
	  
 	    /* add contact pointer to node  */

	    ccell = (cElement *) mallocMagic((unsigned) (sizeof(cElement)));
	    ccell->ce_nextc = resptr->rn_ce;
	    resptr->rn_ce = ccell;
	    ccell->ce_thisc = contact;
	       
	    contact->cp_cnode[tilenum] = resptr;
	    NEWBREAK(resptr, tile, contact->cp_center.p_x,
			contact->cp_center.p_y, &contact->cp_rect);

	    /* add resistors here */

	    if (tilenum > 0)
	    {
	        resistor = (resResistor *) mallocMagic((unsigned) (sizeof(resResistor)));
	        resistor->rr_nextResistor = (*resList);
	        resistor->rr_lastResistor = NULL;
	        if ((*resList) != NULL) (*resList)->rr_lastResistor = resistor;
	        (*resList) = resistor;
	        resistor->rr_connection1 = contact->cp_cnode[tilenum-1];
	        resistor->rr_connection2 = contact->cp_cnode[tilenum];
		    
	        element = (resElement *) mallocMagic((unsigned) (sizeof(resElement)));
	        element->re_nextEl = contact->cp_cnode[tilenum-1]->rn_re;
	        element->re_thisEl = resistor;
	        contact->cp_cnode[tilenum-1]->rn_re = element;
	        element = (resElement *) mallocMagic((unsigned)(sizeof(resElement)));
	        element->re_nextEl = contact->cp_cnode[tilenum]->rn_re;
	        element->re_thisEl = resistor;
	        contact->cp_cnode[tilenum]->rn_re = element;

		/* Need to figure out how to handle the multiple nodes	*/	
		/* and multiple resistors necessary to determine the 	*/
		/* correct geometry for the geometry extractor.  For	*/
		/* now, extract as one big glob.			*/
	
		/* rr_cl doesn't need to represent centerline; use for	*/
		/* # squares in y direction instead; use rr_width for	*/
		/* # squares in x direction.				*/

		resistor->rr_cl = squaresy;
		resistor->rr_width = squaresx;
		resistor->rr_value =
		    	ExtCurStyle->exts_viaResist[contact->cp_type] /
			(squaresx * squaresy);
#ifdef ARIEL
		resistor->rr_csArea =
		    	ExtCurStyle->exts_thick[contact->cp_type] /
			(squaresx * squaresy);
#endif
		resistor->rr_tt = contact->cp_type;
		resistor->rr_float.rr_area= 0;
		resistor->rr_status = 0;
	    }
	}
    }
}

/*
 *-------------------------------------------------------------------------
 *
 *-------------------------------------------------------------------------
 */

void
ResSortBreaks(masterlist, xsort)
    Breakpoint	**masterlist;
    int		xsort;
{
    Breakpoint	*p1, *p2, *p3, *p4;
    bool		changed;

    changed = TRUE;
    while (changed == TRUE)
    {
	changed = FALSE;
	p1 = NULL;
	p2 = *masterlist;
	p3 = p2->br_next;
	while (p3 != NULL)
	{
	    if (xsort == TRUE  && p2->br_loc.p_x > p3->br_loc.p_x ||
	           xsort == FALSE && p2->br_loc.p_y > p3->br_loc.p_y)
	    {
		changed = TRUE;
		if (p1 == NULL)
		{
		    *masterlist = p3;
		}
		else
		{
		    p1->br_next = p3;
		}
		p2->br_next = p3->br_next;
		p3->br_next = p2;
		p4 = p2;
		p2 = p3;
		p3 = p4;
	    }
	    else
	    {
	        p1 = p2;
	        p2 = p3;
	       	p3 = p3->br_next;
	    }
	}
    }
}
	
