/** ~/c/overprop/overpropf.c
Time-stamp: </home/wrf/git/all/c/overprop/overpropf.c, Tue, 20 Nov 2018, 19:03:15 EST, w540, wrf, W. Randolph Franklin, http://wrfranklin.org/>
Time-stamp: </b1/wrf/c/upto2006/overprop/overlay.c, Wed,  6 Jan 2010, 12:26:57 EST
Time-stamp: </wrf/c/overprop/overlay.c, Thu, 11 Jul 2002, 12:17:54 EDT, 
Last modified: by Wm Randolph Franklin (wrf) on mab.ecse.rpi.edu at Wed Nov 20 17:56:29 1991
*/

#include <stdio.h>
#include <stdlib.h>
#include  <math.h>
#include <sys/types.h>
#include <sys/times.h>

/* Contents:
    includes,
    constants,
    macros,
    types,
    structs,
    variables,
    routines.
 */


/* ================ Constants ================ */
#define OK	0
#define IN	1
#define OUT	0
#define MYINFINITY 32767
#define DONTKNOW (-1)

/* I compile in a lot of max array sizes, rather than allocating at run time.  It probably doesn't help, but doesn't hurt. */
#define MAX_CHAINS	20000   
#define MAX_VERTS 5000000
#define MAX_EDGES 5000000
#define MAX_PTS_PER_CHAIN 26000
#define MAX_MAP_NAME_LEN 50
#define MAX_XSECTS 50000		/* Max number of intersections */
#define MAX_GRID_HISTOGRAM 1000	/* Size of histogram table for # edges per cell */

#define CELL_HEADER_LEN 3	/* Number of header elements in each grid cell. */

#define HASH_TABLE_DISP 2	/* displacement from start of table to 1st data */

#define POLYGON_ID_MIN 0
#define POLYGON_ID_MAX 32767

#define INTERNAL_MIN (-16383)	/* legal internal coords after scaling */
#define INTERNAL_MAX  16383
#define INTERNAL_RANGE (INTERNAL_MAX-INTERNAL_MIN)



/* ================ Macros ================ */

/*
 * Scaling the input coords to (-16383,16383) means that the edge eqn can be stored
 * in long ints w/o division
 */

#define SCALEX(x) ((VERT_COORD_T) ((x)*rx+deltax))
#define SCALEY(y) ((VERT_COORD_T) ((y)*ry+deltay))

#define UNSCALEX(x) ((float)(x)*rrx+ddeltax)
#define UNSCALEY(y) ((float)(y)*rry+ddeltay)

#define GET_EDGE_COORDS(i) \
	v1 = e[i].v1; \
	v2 = e[i].v2; \
	pl = e[i].pl; \
	pr = e[i].pr; \
	x1 = v[v1].x; \
	y1 = v[v1].y; \
	x2 = v[v2].x; \
	y2 = v[v2].y

/* Find the cell number from the internal coordinate */
#define CELL(xy)  (int) ((float)((xy)-INTERNAL_MIN)*cell_scale)

#define SWAP(i,j) {temp=i;i=j;j=temp;}

#define MAX3(i,j,k) ( ((i)<(j)) ? \
		     ( ((j)<(k)) ? (k) : (j) ) : \
		     ( ((i)<(k)) ? (k) : (i) ) )

#define MAX(a,b) ((a)>(b)?(a):(b))
#define MIN(a,b) ((a)<(b)?(a):(b))

/* MAX4 Calls MAX(a,b) too many times, but don't worry now. */
#define MAX4(a,b,c,d) (MAX(MAX(a,b),MAX(c,d)))
#define MIN4(a,b,c,d) (MIN(MIN(a,b),MIN(c,d)))

/* Compute output (intersection) polygon id as a function of the
 * 2 input polygon ids.  Note that + binds tighter than <<. */
#define OUTPUT_POLYGON(a,b) ( ((a)<<16) + (b) )

/* Compute input polygon ids as a function of the output polygon id. */
#define INPUT_POLYGON_1(a) ((a)>>16)
#define INPUT_POLYGON_2(a) ((a)&65535)

/* Loop for each map */
#define FOR2 for(im=0;im<2;im++)

/* Square */
#define SQ(x) ((x)*(x))


/* ================ Types ================ */
/* When I wrote this, minimizing memory was more important.  Hence the short ints. */

#define VERT_COORD_T  short int
#define VERT_NO_T long int
#define EDGE_NO_T  int		/* too big for unsigned short. Oh well. */
#define HASH_KEY_T long int
#define POLYGON_ID_T short int
#define RANGE_T float		/* of xmin etc */
#define INTERMED_COORD_T long int	/* intermediate type for coordinate
					 * calculations.  If long int is
					 * insufficient, make VERT_COORD_T and this
					 * double. */


/* ================ Structs ================ */

typedef struct VERTEX_T {
    VERT_COORD_T x, y;
    short int p;		/* Which polygon on the other map this vert is in.
				 * -1: dont know.  */
}       VERTEX_T;

typedef struct FLOAT_VERTEX_T {
    float   x, y;
}       FLOAT_VERTEX_T;		/* Vertices before scaling */

typedef struct EDGE_T {
    VERT_NO_T v1, v2;		/* id numbers of verts at ends */
    POLYGON_ID_T pl, pr;	/* id numbers of the polygons to left and right */
    INTERMED_COORD_T a, b, c;	/* Eqn: a*x+b*y+c=0 */
    INTERMED_COORD_T dx, dy;	/* Direction of edge: v2-v1. Stored for efficiency.
				 * Calced in accumulate_vertex_areas and used in
				 * accumulate_xsect_areas. */
}       EDGE_T;

typedef struct HASH_RECORD_T {	/* hash table entry */
    HASH_KEY_T k;
    float   v;
}       HASH_RECORD_T;

typedef struct XSECT_T {    /* Intersection of two edges */
    EDGE_NO_T e1, e2;
    VERT_COORD_T x, y;
}       XSECT_T;


typedef struct SLAB {
    EDGE_NO_T edge;
    struct SLAB *next;
}       SLAB;

typedef struct CHAIN {  /* aka polyline or common border between two polygons */
    int     base;		/* loc, in fverts and vertices, of 1st vert of this
				 * chain */
    int     num_vert;
    POLYGON_ID_T lpol, rpol;
}       CHAIN;


/* ======================= Copies of constants for debugging convenience ==== */

int     Max_Chains, Max_Verts, Max_Edges, Max_Pts_Per_Chain, Max_Map_Name_Len;
int     Max_Xsects, Max_Grid_Histogram, Cell_Header_Len, Hash_Table_Disp;
int     Polygon_Id_Min, Polygon_Id_Max, Internal_Min, Internal_Max, Internal_Range;



/* =========================== Variables ============================ */

int     grid_size;		/* Number of grid cells per side.  The grid is a square array of
				 * arrays of edges. */

int     im;			/* In many loops, the number of the current map. */

EDGE_NO_T ***grid;
POLYGON_ID_T **polygon_containing_cell[2];

float   cell_scale;

/* These control the amount of output. */
int     debug_print_grid, debug_add_map_to_grid, debug_add_edge_to_cell, debug_calc_areas;
int     debug_inclusions, debug_print_chains_vertices, debug_print_xsect;
int     debug_zero_len_edges;

/* Combined bounds of input maps */
RANGE_T ext_xmin, ext_xmax, ext_ymin, ext_ymax;


/* scaling factors between external and internal coords */
RANGE_T rx, ry, rrx, rry;

/* deltas for scaling */
RANGE_T deltax, deltay, ddeltax, ddeltay;

/* Actual sizes of input maps */
int     n_edges[2], n_verts[2], n_pols[2];

/* Input maps */
VERTEX_T vertices[2][MAX_VERTS];
EDGE_T  edges[2][MAX_EDGES];

/* Counters */
int     n_edge_pairs_tested_for_xsect;
int     n_dupl_xsect;
int     n_hash_compar;		/* # times hash_compare called when sorting packed
				 * hash tables . */
int     n_zero_len_edges;

CHAIN   chains[2][MAX_CHAINS];
int     n_chains[2];
RANGE_T xmins[2], xmaxs[2], ymins[2], ymaxs[2];

static int     nxsect;			/* Number of intersections */
static XSECT_T* xsect;

#define LASTMODDATE " Wed Jan 6 12:10:57 EST 2010 "



/* =========================== Routines ============================ */

void myerror(char *msg) {
    printf("[Error: %s]\n", msg);
    exit(1);
}









void check_polygon_id(int    *id) {
    if (*id < POLYGON_ID_MIN || *id > POLYGON_ID_MAX) {
	/**
		printf("Polygon id=%d must be between %d and %d. Changed.\n",
		       *id, POLYGON_ID_MIN, POLYGON_ID_MAX);
	*/
	/* Fix later - just a hack */
	*id = -(*id);
    }
}


/** calc_edge_eqns.c   Calculate all the edge equations for this map,
and store into the edge structure.

Assumes the vertex coords were scaled so that no division is necessary
*/
void calc_edge_eqns(int     mapno) {
    int     ie;
    int     v1, v2;
    VERT_COORD_T x1, y1, x2, y2;
    EDGE_T *cur;

    for (ie = 0; ie < n_edges[mapno]; ie++) {
	cur = &edges[mapno][ie];
	v1 = cur->v1;
	v2 = cur->v2;
	x1 = vertices[mapno][v1].x;
	y1 = vertices[mapno][v1].y;
	x2 = vertices[mapno][v2].x;
	y2 = vertices[mapno][v2].y;

	cur->c = -x1 * (INTERMED_COORD_T) (cur->a = y1 - y2) -
	    y1 * (INTERMED_COORD_T) (cur->b = x2 - x1);

	if (cur->a == 0 && cur->b == 0)
	    printf("Map %d, edge %d between vertices %d %d has zero length.\n", mapno, ie, v1, v2);

	/* Normalize so points below in Y give -ve. */

	if (cur->b < 0) {
	    cur->a = -cur->a;
	    cur->b = -cur->b;
	    cur->c = -cur->c;
	}
    };
}


/*  Split the chains into edges.	*/
void extract_edges(int mapno, CHAIN chain[], int nchain) {
    int     ipt, npt, lpol, rpol, ichain;
    int     ne;
    int     base;		/* number of points in v before current chain */
    EDGE_T *this_edge;
    VERTEX_T *this_v1, *this_v2;

    base = ne = 0;

    for (ichain = 0; ichain < nchain; ichain++) {
	npt = chain[ichain].num_vert;
	lpol = chain[ichain].lpol;
	rpol = chain[ichain].rpol;
	check_polygon_id(&lpol);
	check_polygon_id(&rpol);

	for (ipt = 1; ipt < npt; ipt++) {
	    this_edge = &edges[mapno][ne];
	    this_edge->v1 = base + ipt - 1;
	    this_edge->v2 = base + ipt;
	    this_edge->pl = lpol;
	    this_edge->pr = rpol;

	    /* Delete this edge if it is zero length (after scaling) */

	    this_v1 = &vertices[mapno][this_edge->v1];
	    this_v2 = &vertices[mapno][this_edge->v2];
	    if (this_v1->x == this_v2->x && this_v1->y == this_v2->y) {
	      if (debug_zero_len_edges)
		printf("In map #%d, chain #%d, lpol=%d, rpol=%d, edge #%d has len=0. Deleted.\n",
		       mapno, ichain, lpol, rpol, ipt - 1);
	      n_zero_len_edges++;
	      ne--;
	    }
	    if (ne++ >= MAX_EDGES)
		myerror("Too many edges in extract_edges.");
	};
	base += npt;
    };
    n_edges[mapno] = ne;
    calc_edge_eqns(mapno);
}


/**    Hash table routines
There are 2 sets of hashing routines.

1. Store partial polygon areas.  The hash record contains  the key and
the float area.  There is an op for adding to an existing area.

2. Store polygon ids.  The has record contains only the key.  There is
an op for returning  the has location  and automatically assigning one
if it doesn't exist.

FOR THE FIRST TYPE:

Keys are long ints, values are floats

create_hash_table(m) Return a new table of m  elements. m must include
extra space for hashing efficiency.

The  hash function is quite  simple:  location=(key)%(table size).  If
this causes problems in the future, it can be changed.

The table is actually allocated  HASH_TABLE_DISP =  2  entries larger,
with the 0th entry key holding the  max number of  entries and the 1st
the actual number.

The key must be  a positive int.   0 keys are ignored for convenience,
since they arise in calc_areas, and negative keys cause an error.

find_hash_key(table,key) Return the associated value, or 0.

find_hash_key_add_value(table,key,value) If key doesn't  exist, insert
it with value.  If  it does exist,  then add the  value to the current
value.  Return the value.

pack_hash_table(table) Return a pointer  to a compacted table with the
zero entries and the two header entries removed.  Sort the table.

get_hash_n_records(table) Return the current number of records.
	*/


HASH_RECORD_T *create_hash_table(int m) {
    HASH_RECORD_T *p;
    if (m <= 0)
	myerror("m must be positive in create_hash_table.");
    p = (HASH_RECORD_T *) calloc((unsigned) (m + HASH_TABLE_DISP), sizeof(HASH_RECORD_T));
    p->k = m;
    (p + 1)->k = 0;
    return (p);
};

float find_hash_key(HASH_RECORD_T *table, HASH_KEY_T key) {
    int     i, j, m, m8;
    HASH_RECORD_T *top, *bot, *p;
    float   val;

    if (key <= 0)
	if (key < 0)
	    myerror("In find_hash_key_add_value, the hash key must be a positive int.");
	else
	    return 0.0;

    m = table->k;
    m8 = m * 8 / 10;
    i = (key) % m;
    bot = table + HASH_TABLE_DISP;
    top = bot + m;
    p = bot + i;
    val = 0.0;
    for (j = 0; j < m; j++) {
	if (p->k == key) {
	    val = p->v;
	    break;
	};
	if (p->k == 0) {
	    val = 0;
	    break;
	};
	p++;
	if (p >= top)
	    p = bot;
    };
    if (j >= m8) {
	printf("Hash table size = %d, .8 size=%d\n", m, m8);
	myerror("Hash table too full in find_hash_key");
    }
    if (j >= 3)
	printf("In find_hash_key_add_value, key %ld took %d probes.\n", key, j);
    return (val);
}


float find_hash_key_add_value(HASH_RECORD_T *table, HASH_KEY_T key, float   value) {
    int     i, j, m, m8;
    HASH_RECORD_T *top, *bot, *p;
    float   val;

    if (key <= 0)
	if (key < 0)
	    myerror("In find_hash_key_add_value, the hash key must be a positive int.");
	else
	    return 0.0;

    m = table->k;
    m8 = m * 8 / 10;
    i = (key) % m;
    bot = table + HASH_TABLE_DISP;
    top = bot + m;
    p = bot + i;
    val = 0.0;
    for (j = 0;; j++) {
	if (j >= m8) {
	    printf("Hash table size = %d, .8 size=%d\n", m, m8);
	    myerror("Hash table too full in find_hash_key_add_value");
	}
	if (p->k == key) {
	    val = (p->v += value);
	    break;
	};
	if (p->k == 0) {
	    p->k = key;
	    val = p->v = value;
	    (table + 1)->k += 1;/* # entries in table */
	    break;
	};
	p++;
	if (p >= top)
	    p = bot;
    };
    if (j >= 3)
	printf("In find_hash_key_add_value, key %ld took %d probes.\n", key, j);

    return (val);
}


int get_hash_n_records(HASH_RECORD_T *table) {
    return ((table + 1)->k);
}



HASH_RECORD_T *pack_hash_table(HASH_RECORD_T *table) {
    int     n;
    HASH_RECORD_T *p, *r, *s, *pbot, *ptop;
    int     hash_compar();

    n = get_hash_n_records(table);
    s = r = (HASH_RECORD_T *) calloc((unsigned) n, sizeof(HASH_RECORD_T));
    pbot = table + HASH_TABLE_DISP;
    ptop = pbot + (table->k);	/* 1 past top */
    for (p = pbot; p != ptop; p++) {
	if (p->k != 0) {
	    s->k = p->k;
	    (s++)->v = p->v;
	};
    };
    if (s != r + n)
	myerror("Wrong number in pack_hash_table");

    /* Sort the table. */

    qsort((char *) r, n, sizeof(HASH_RECORD_T), hash_compar);

    return (r);
}

int hash_compar(HASH_RECORD_T *a, HASH_RECORD_T *b) {
    n_hash_compar++;
    return (a->k - b->k);
}


/* malloc2  malloc with a check for failure and an error message */
char   *malloc2(unsigned int n, char   *msg) {
    char   *c;
    c = malloc(n);
    if (c == NULL)
	myerror(msg);
    return (c);
}


/* calc_areas  Calculate and print the areas of the polygons in this map. Ret # pols.	*/

int calc_areas(VERTEX_T v[], EDGE_T e[], int ne) {
    int     hsize;		/* Use the number of edges as the hash table size
				 * since the number of polygons isn't known yet.  It
				 * should be more than adequate. */
    int     i, n, pl, pr;
    long int v1, v2;
    float   x1, y1, x2, y2, a, unscale;
    HASH_RECORD_T *table, *list;

    hsize = ne;
    unscale = rrx * rry;
    table = create_hash_table(hsize);
    for (i = 0; i < ne; i++) {
	GET_EDGE_COORDS(i);
	a = 0.5 * (x1 * y2 - x2 * y1);
	if (pl != 0)
	    find_hash_key_add_value(table, (HASH_KEY_T) pl, a);
	if (pr != 0)
	    find_hash_key_add_value(table, (HASH_KEY_T) pr, -a);
    };
    n = get_hash_n_records(table);
    list = pack_hash_table(table);
    if (debug_calc_areas) {
	printf("\n= Areas of %d polygons in this map:\n", n);
	for (i = 0; i < n; i++)
	    printf("%5ld: %9.5g\n", (list + i)->k, (list + i)->v * unscale);
    }
    return (n);
}


/* grid:  Put the edges of map into a grid
 *
 * The grid data structure is a square array of pointers to arrays, which are
 * realloced and grown when necessary. For space each cell is initially left a null
 * pointer until the first edge is inserted.
 */

/** Array elements for each grid cell:
  0: Size of this array,
  1: Number of elements used so far,
  2: Loc of 1st edge of map #1 in this array (not set till map #0 all entered),
  CELL_HEADER_LEN=3,4,...a[2]-1:  edges of map #0
  a[2],...a[1]-1: edges of map #1
*/


int     no_cell_increases;
int     initialsize = 6;	/* Initial array size per cell */

void make_grid() {
    int     i, j;

    no_cell_increases = 0;
    if (grid_size <= 0)
	myerror("Grid size must be positive.");

    /* The 0.9999 is to prevent any points at the right side */
    cell_scale = (float) grid_size / (float) INTERNAL_RANGE *0.9999;

    grid = (EDGE_NO_T ***) malloc2((unsigned) (grid_size * sizeof(EDGE_NO_T **)),
				   "malloc failure trying to alloc grid-1");

    for (i = 0; i < grid_size; i++) {
	grid[i] =
	    (EDGE_NO_T **) malloc2((unsigned) (grid_size * sizeof(EDGE_NO_T *)),
				   "malloc failure trying to alloc grid-2");
	for (j = 0; j < grid_size; j++) {
	    grid[i][j] = NULL;
	}
    }

    /*
     * Allocate the array to store which polygon each cell is completely in, if any.
     */

    FOR2 {
	polygon_containing_cell[im] =
	    (POLYGON_ID_T **)
	    malloc2((unsigned) (grid_size * sizeof(POLYGON_ID_T *)),
		    "malloc failure trying to alloc polygon_containing_cell-1");

	for (i = 0; i < grid_size; i++) {
	    polygon_containing_cell[im][i] =
		(POLYGON_ID_T *)
		malloc2((unsigned) (grid_size * sizeof(POLYGON_ID_T)),
			"malloc failure trying to alloc polygon_containing_cell-2");

	    for (j = 0; j < grid_size; j++) {
		polygon_containing_cell[im][i][j] = DONTKNOW;
	    }
	}
    }


}


void add_edge_to_cell(int i, int j, EDGE_NO_T edge) {
    EDGE_NO_T *arr;
    int     m, m2, n;
    arr = grid[i][j];
    if (arr == NULL) {		/* No edges in this cell so far */
	arr = grid[i][j] =
	    (EDGE_NO_T *) malloc2((unsigned) (initialsize * sizeof(EDGE_NO_T)),
				  "malloc failure trying to alloc a grid cell");
	m = arr[0] = initialsize;
	n = arr[1] = arr[2] = CELL_HEADER_LEN;
    } else {
	m = arr[0];
	n = arr[1];
    }
    if (n == m) {		/* alloc more space */
	m2 = m * 2;
	grid[i][j] = arr =
	    (EDGE_NO_T *) realloc((char *) arr, (unsigned) (m2 * sizeof(EDGE_NO_T)));
	if (arr == NULL)
	    myerror("Realloc failure trying to grow grid cell");
	arr[0] = m2;
	no_cell_increases++;
	if (debug_add_edge_to_cell)
	    printf("Increasing size of cell %d,%d to %d\n", i, j, m2);
    };
    arr[n++] = edge;
    arr[1] = n;
}


/*
 * Add the edges of this map to the grid.  If this is map #0, then store in each
 * cell the loc of the next free edge slot.
 */

void add_map_to_grid(VERTEX_T v[],EDGE_T  e[], int     ne, int mapno) {
    int     ix1, iy1, ix2, iy2, temp;
    int     i, j, pl, pr;
    long int v1, v2;
    float   x1, y1, x2, y2;
    EDGE_NO_T iedge, *arr;

    for (iedge = 0; iedge < ne; iedge++) {
	GET_EDGE_COORDS(iedge);

	ix1 = CELL(x1);
	iy1 = CELL(y1);
	ix2 = CELL(x2);
	iy2 = CELL(y2);

	/* Be lazy for now.  Put a box around the edge */

	if (ix1 > ix2)
	    SWAP(ix1, ix2);
	if (iy1 > iy2)
	    SWAP(iy1, iy2);

	if (debug_add_map_to_grid && ix1 < ix2 && iy1 < iy2)
	    printf("Edge %d llc cells %d %d, urc %d %d\n", iedge, ix1, iy1, ix2, iy2);

	for (i = ix1; i <= ix2; i++)
	    for (j = iy1; j <= iy2; j++)
		add_edge_to_cell(i, j, iedge);
    }

    /*
     * If this is map #0, record in each cell the loc of next free slot, so we'll
     * know where map #1 starts.
     */

    if (mapno == 0)
	for (i = 0; i < grid_size; i++)
	    for (j = 0; j < grid_size; j++) {
		arr = grid[i][j];
		if (arr != NULL)
		    arr[2] = arr[1];
	    }
}





void
print_grid()
{
    int     i, j;
    EDGE_NO_T k, *arr;
    for (i = 0; i < grid_size; i++)
	for (j = 0; j < grid_size; j++) {
	    arr = grid[i][j];
	    printf("[%3d,%3d]:", i, j);
	    if (arr != NULL)
		for (k = 0; k < arr[1]; k++)
		    printf(" %3d", arr[k]);
	    printf("\n");
	};
}



void
print_grid_histogram()
{
    int     hist[MAX_GRID_HISTOGRAM];
    int     i, j, k, n;
    EDGE_NO_T *arr;

    for (i = 0; i < MAX_GRID_HISTOGRAM; hist[i++] = 0);
    for (i = 0; i < grid_size; i++)
	for (j = 0; j < grid_size; j++) {
	    arr = grid[i][j];
	    if (arr == NULL)
		n = 0;
	    else
		n = arr[1] - CELL_HEADER_LEN;	/* Number of edges in this cell,
						 * excl header info */
	    if (n >= MAX_GRID_HISTOGRAM) {
		printf("Warning: Cell (%d,%d) has %d edges: ", i, j, n);
		for (k = 0; k < n; k++)
		    printf(" %3d", arr[k + CELL_HEADER_LEN]);
		printf("\n");
		n = MAX_GRID_HISTOGRAM - 1;
	    }
	    hist[n]++;
	};

    /* Find highest non-zero element */
    for (j = MAX_GRID_HISTOGRAM - 1; j >= 0; j--)
	if (hist[j] != 0)
	    break;

    printf("\n= Histogram of number of cells with n edges, for 0<=n<=%d:\n", j);
    for (i = 0; i <= j; i++)
	printf(" %d", hist[i]);
    printf("\n");

    printf("Number of times grid cells had to be realloced with more space= %d\n",
	   no_cell_increases);
}






/** intersect_edges  Intersect all the edges
 * Remember that the 1st CELL_HEADER_LEN elts of each grid cell are the number of
 * allocated entries, the number used up to the end of map #0, and the total number
 * of cells used including this header and both maps, (CELL_HEADER_LEN more than the
 * number of edges).
 */
void    intersect_one_cell();

static VERTEX_T *v0, *v1;	/* globalize the args */
static EDGE_T *e0, *e1;
static XSECT_T* xsect;
static int nxsect;
int ig, jg;


void intersect_edges(VERTEX_T *av0, EDGE_T *ae0, VERTEX_T *av1, EDGE_T *ae1, XSECT_T *axsect, int    *anxsect) {
  /*    anxsect: Number of intersections */

  /* Copy over args for speed so they don't have to be passed explicitly */
    v0 = av0;
    v1 = av1;
    e0 = ae0;
    e1 = ae1;
    xsect = axsect;

    nxsect = 0;
    n_edge_pairs_tested_for_xsect = 0;
    for (ig = 0; ig < grid_size; ig++)
	for (jg = 0; jg < grid_size; jg++) {
	    intersect_one_cell();
	}
    *anxsect = nxsect;
}


/* intersect the edges in one cell */

void
intersect_one_cell()
{
    int     i, j, ie, je, ne, base0, base1;
    EDGE_NO_T *cell;
    VERT_COORD_T x0, y0, x1, y1, xx0, yy0, xx1, yy1, xsectx, xsecty, t;
    INTERMED_COORD_T se00, se01, se10, se11;
    float   denom, numx, numy, fsectx, fsecty;
    int     icell, jcell;
    EDGE_T *ee0, *ee1;

    cell = grid[ig][jg];
    if (cell == NULL)
	return;
    base0 = CELL_HEADER_LEN;
    base1 = cell[2];
    ne = cell[1];
    if (ne == base0)
	return;			/* No edges in this cell */
    if (base0 == base1 || base1 == ne)
	return;			/* All the edges are one type */

    for (i = base0; i < base1; i++) {
	ie = cell[i];		/* The number of the edge of map 0 being xsected */
	ee0 = &e0[ie];		/* A pointer to this edge's struct */
	x0 = v0[ee0->v1].x;	/* The coords of its endpoints */
	y0 = v0[ee0->v1].y;
	x1 = v0[ee0->v2].x;
	y1 = v0[ee0->v2].y;

	for (j = base1; j < ne; j++) {
	    n_edge_pairs_tested_for_xsect++;
	    je = cell[j];
	    ee1 = &e1[je];
	    xx0 = v1[ee1->v1].x;
	    yy0 = v1[ee1->v1].y;
	    xx1 = v1[ee1->v2].x;
	    yy1 = v1[ee1->v2].y;

	    /* Substitute a point into the equation of an edge */

#define SUBEDGE(x,y,e) ((x)*e->a+(y)*e->b+e->c)

	    se00 = SUBEDGE(xx0, yy0, ee0);
	    se10 = SUBEDGE(xx1, yy1, ee0);
	    se01 = SUBEDGE(x0, y0, ee1);
	    se11 = SUBEDGE(x1, y1, ee1);

	    /*
	     * Move map1 by (eps, eps^2) relative to map 0 (Simulation of
	     * Simplicity)
	     */

	    if (se01 == 0)
		se01 = -ee1->a;
	    if (se01 == 0)
		se01 = -ee1->b;
	    if (se01 == 0)
		continue;	/* Zero length edge */
	    if (se11 == 0)
		se11 = -ee1->a;
	    if (se11 == 0)
		se11 = -ee1->b;
	    if (se11 == 0)
		continue;	/* Zero length edge */
	    if ((se01 > 0 && se11 > 0) || (se01 < 0 && se11 < 0))
		continue;

	    if (se00 == 0)
		se00 = ee0->a;
	    if (se00 == 0)
		se00 = ee0->b;
	    if (se00 == 0)
		continue;	/* Zero length edge */
	    if (se10 == 0)
		se10 = ee0->a;
	    if (se10 == 0)
		se10 = ee0->b;
	    if (se10 == 0)
		continue;	/* Zero length edge */
	    if ((se10 > 0 && se00 > 0) || (se10 < 0 && se00 < 0))
		continue;


	    /*
	     * Check if both edges are the same.  If so, they shouldn't be
	     * intersecting.
	     */

	    if ((x0 == xx0 && y0 == yy0 && x1 == xx1 && y1 == yy1) ||
		(x0 == xx1 && y0 == yy1 && x1 == xx0 && y1 == yy0))
		printf("=ERROR: In intersect_edges, cell %d,%d, edges %d, %d, \
which are identical, have been found to intersect.  Endpoints: (%d,%d), (%d,%d)\n",
		       ig, jg, ie, je, x0, y0, x1, y1);

	    /**		    if (se01 * se11 >= 0.0)
				    continue;
			        if (se00 * se10 >= 0.0)
				    continue;  */

	    denom = (float) (ee0->a) * (float) (ee1->b) - (float) (ee1->a) * (float) (ee0->b);
	    numx = ((float) (ee0->c) * (float) (ee1->b) - (float) (ee1->c) * (float) (ee0->b));

	    /*
	     * converting float to int truncates towards 0, not towards -infinity.
	     * We want a round to the nearest int regardless of sign.
	     */

	    fsectx = -numx / denom;
	    if (fsectx > 0.0)
		xsectx = (VERT_COORD_T) (fsectx + 0.5);
	    else
		xsectx = (VERT_COORD_T) (fsectx - 0.5);

	    numy = ((float) (ee0->a) * (float) (ee1->c) - (float) (ee1->a) * (float) (ee0->c));

	    fsecty = -numy / denom;
	    if (fsecty > 0.0)
		xsecty = (VERT_COORD_T) (fsecty + 0.5);
	    else
		xsecty = (VERT_COORD_T) (fsecty - 0.5);

	    /*
	     * Ensure that the intersection point is not in an adjacent cell because
	     * of roundoff.  The following is not perfect, but is better than
	     * nothing.
	     */

	    t = MIN4(x0, x1, xx0, xx1);
	    if (xsectx < t) {
		printf("Intersection of edges %d and %d has x=%d below xmin=%d.  Rounded up.\n", ie, je, xsectx, t);
		xsectx = t;
	    }
	    t = MAX4(x0, x1, xx0, xx1);
	    if (xsectx > t) {
		printf("Intersection of edges %d and %d has x=%d above xmax=%d.  Rounded down.\n", ie, je, xsectx, t);
		xsectx = t;
	    }
	    t = MIN4(y0, y1, yy0, yy1);
	    if (xsecty < t) {
		printf("Intersection of edges %d and %d has y=%d below ymin=%d.  Rounded up.\n", ie, je, xsecty, t);
		xsecty = t;
	    }
	    t = MAX4(y0, y1, yy0, yy1);
	    if (xsecty > t) {
		printf("Intersection of edges %d and %d has y=%d above ymax=%d.  Rounded down.\n", ie, je, xsecty, t);
		xsecty = t;
	    }
	    xsect[nxsect].x = xsectx;
	    xsect[nxsect].y = xsecty;
	    xsect[nxsect].e1 = ie;
	    xsect[nxsect].e2 = je;
	    icell = CELL(xsectx);
	    jcell = CELL(xsecty);
	    if (icell == ig && jcell == jg) {
		if (debug_print_xsect)
		    printf("Xsect #%d, edges %dx%d, (x,y)=(%d,%d), or (%g,%g), cell (%d,%d)\n",
			   nxsect, ie, je, xsectx, xsecty,
			   UNSCALEX(xsectx), UNSCALEY(xsecty),
			   icell, jcell);
	    } else {		/* Intersection not in this cell */
		n_dupl_xsect++;
		nxsect--;
	    }
	    if (MAX_XSECTS <= nxsect++)
		myerror("Too many intersections.\n");
	}

    }
}




/**	read_pgraph: Read one map.  Don't scale now; all the maps will be scaled together
later.  Also calc bounds.

Created by:	Venkatesh K. Sivaswami (Venki).
Modified by:    Wm. Randolph Franklin, 2/90

Output:		FLOAT_VERTEX_T fvertex []: Vertices
		CHAIN chain[]; Chains
		int *pnv: # verts
		int *pn_chains; Number of chains
		RANGE_T *xmin etc:  Map bounds.
*/

void read_pgraph(char    map_name[], 
		 FLOAT_VERTEX_T fvertex[], 
		 int    *pnv,
		 CHAIN   chain[],
		 int    *pn_chains,
		 RANGE_T *xmin, RANGE_T *xmax, RANGE_T *ymin, RANGE_T *ymax) {
    int     i, j, llp, rrp;
    int     temp_num_vert;	/* Number of vertices in each polygon chain */
    int     dum;
    int     hi_pts_per_chain;
    FILE   *fp_pgraph;		/* Pointer to planar graph data file */

    if ((fp_pgraph = fopen(map_name, "r")) == NULL) {
	fprintf(stderr, "File does not exist\n");
	exit(1);
    }
    i = 0;
    hi_pts_per_chain = 0;
    *pn_chains = 0;

    /* Read in the number of vertices  */

    while ((fscanf(fp_pgraph, "%d%d%d%d", &dum, &temp_num_vert, &dum, &dum)) != EOF) {
	/* Need an extra chain for last base. Hence the -1. */
	if (*pn_chains >= MAX_CHAINS - 1)
	    myerror("Too many input chains.");

	/* various criteria for determining the end of the file */

	if (temp_num_vert <= 0 || temp_num_vert == 999 || temp_num_vert == 9999)
	    break;
	if (temp_num_vert >= MAX_PTS_PER_CHAIN) {
	  printf("temp_num_vert=%d, MAX_PTS_PER_CHAIN=%d\n", temp_num_vert, MAX_PTS_PER_CHAIN);
	  myerror("Too many points in this chain.");
	}

	/*
	 * Read in the left and right polygons for each chain. Reading into an int
	 * and then assigning to chain.lpol means that if we change the type of
	 * lpol, we don't have to change the scan format.
	 */

	if (EOF == fscanf(fp_pgraph, "%d%d", &llp, &rrp)) {
	    perror("unexpectedly while reading chain header");
	    exit(1);
	};
	chain[*pn_chains].base = i;
	chain[*pn_chains].lpol = llp;
	chain[*pn_chains].rpol = rrp;

	/* Read in the coordinates of the vertices  */

	for (j = 0; j < temp_num_vert; j++) {

	    if (EOF == fscanf(fp_pgraph, "%f %f", &fvertex[i].x, &fvertex[i].y)) {
		perror("unexpectedly while reading chain");
		exit(1);
	    };
	    i++;

	}			/* for j */

	/* Store the number of vertices in polygon chain in array */

	chain[(*pn_chains)++].num_vert = temp_num_vert;
	if (hi_pts_per_chain < temp_num_vert)
	    hi_pts_per_chain = temp_num_vert;

    }

    chain[*pn_chains].base = *pnv = i;


    /* Find the minimum and maximum */

    *xmin = *xmax = fvertex[0].x;
    *ymin = *ymax = fvertex[0].y;

    for (i = 1; i < *pnv; i++) {

	if (fvertex[i].x < *xmin)
	    *xmin = fvertex[i].x;
	if (fvertex[i].x > *xmax)
	    *xmax = fvertex[i].x;
	if (fvertex[i].y < *ymin)
	    *ymin = fvertex[i].y;
	if (fvertex[i].y > *ymax)
	    *ymax = fvertex[i].y;
    }
    fclose(fp_pgraph);
    printf("Number of chains= %d\nGreatest number of points per chain= %d\n",
	   *pn_chains, hi_pts_per_chain);
}


/* locate_vertices_in_other_map

For each vertex of map #im, determine which polygon of the other map it is in.

This uses global vars: im, verts, edges, n_verts, n_edges,
polygon_containing_cell, grid.

Method:

1. Run a ray up from the point and see whether it crosses any edges in the same
cell.  If so take the first one and return the appropriate adjacent polygon.
Note that the edge must cross the ray while it is in the current cell, or the
crossing doesn't count.

2. If the ray crosses no lines in this cell, then try the next cell up, and so
on.  If a cell is completely inside a polygon, then return that polygon.

3. If a cell being traversed has no edges from this map at all, not just none
crossing the ray, then when the polygon is determined, then label this cell as
being completely inside that polygon.

*/


static int iv;			/* current vertex number */
static int cx, cy;		/* cell containing current vertex */
static int cy2, cy3;		/* current cell number */
static VERTEX_T *tv;		/* pointer to current vertex */
static EDGE_NO_T *tc;		/* pointer to current cell */
static int ne;			/* number edges (of other map) in current cell */
static int ipol;		/* current polygon */
static int im2;			/* the other map */
static int base;		/* base of edges in this cell */
static EDGE_T *te;		/* current edge */
static int ie;			/* current edge */
static VERT_COORD_T vx, vy;	/* current vertex */
static VERTEX_T *v1, *v2;	/* endpoints of current edge */
static VERT_COORD_T xl, xh;	/* of current edge */
static double xsecty;		/* Y coord of xsect of edge with vertical line from
				 * point */
static double besty;		/* Lowest xsecty seen so far */
double  diffy;			/* Vertical distance from point to edge. +ve =>
				 * point higher. */
static EDGE_T *beste;		/* best edge so far */
static VERT_COORD_T bestyh;
static int *nec;		/* number of edges in some cells of current column */
static int plot_cell = 0;	/* Plot current cell ? */
static float ffmin, ffmax;	/* internal coord min and max */
static float glen;		/* size of a grid cell in internal units */
static float ttx, tty;		/* Total translation for debugging plot */
static float ts;		/* last scale " */


void test_against_edges_of_this_cell() {
    int     flag;

    for (ie = 0; ie < ne; ie++) {
	te = &edges[im2][tc[base + ie]];
	v1 = &vertices[im2][te->v1];
	v2 = &vertices[im2][te->v2];
	xl = MIN(v1->x, v2->x);
	xh = MAX(v1->x, v2->x);

	/*
	 * Is point outside x bounds of this edge?  Use simulation of simplicity:
	 * shift map 1 by epsilon relative to map 0.  This also eliminates vertical
	 * edges.
	 */

	if (vx < xl || vx > xh || vx == ((im == 0) ? xl : xh))
	    continue;

	/* Is point above edge?  If point is on edge, use simulation of simplicity. */

	xsecty = ((double) (-te->a * vx - te->c)) / (double) (te->b);
	diffy = vy - xsecty;

	if (diffy == 0)
	    diffy = ((im == 0) ? -te->a : te->a);
	if (diffy == 0)
	    diffy = ((im == 0) ? -te->b : te->b);
	if (diffy == 0)
	    myerror("Zero length edge in locate_vertices_in_other_map");

	if (diffy > 0)
	    continue;		/* Yes, point is above edge. */

	if (xsecty > besty)
	    continue;		/* Point is below, but another edge is closer. */

	if (xsecty == besty) {	/* Line up from point cuts this edge and another
				 * edge at the same Y.  This should only happen at a
				 * vertex.  Roundoff error should not cause it, I
				 * hope.  If im==0, we're at the right end of both
				 * edges.  im==1 => left end.  */

	    /* flag:  Is this slope algebraically less than the last one? */

	    flag = (((double) (te->a) / (double) (te->b)) > ((double) (beste->a) / (double) (beste->b)));

	    /* If im==0 we want the bigger slope, if im==1, the smaller. */

	    if ((im && !flag) || (flag && !im))
		continue;

	}
	besty = xsecty;		/* We have a new closer edge.  Update out records. */
	beste = te;
	bestyh = MAX(v1->y, v2->y);
    }

    /*
     * Check that the best edge intersects the ray within the current cell.  If not
     * ignore it and act as if there were no edges in this cell crossing the ray. If
     * the hi end of the edge is in the cell then the intersection point certainly
     * is.
     */

    if (CELL(bestyh) == cy2)
	return;
    if (CELL(besty) > cy2) {
	/* printf("Intersection of edge and ray is not in cell %d, %d\n", cx, cy2); */
	beste = NULL;
    }
}


void locate_vertices_in_other_map() {
    im2 = 1 - im;
    ffmin = INTERNAL_MIN;
    ffmax = INTERNAL_MAX;
    glen = (ffmax - ffmin) / grid_size;

    /*
     * Alloc nec only once even though locate_vertices_in_other_map is called twice.
     * This assumes locate_vertices_in_other_map is called first with im==0.
     */

    if (im == 0)
	nec = (int *)
	    malloc2((unsigned) grid_size * sizeof(int),
	    "Malloc failure trying to alloc nec in locate_vertices_in_other_map.");

    for (iv = 0; iv < n_verts[im]; iv++) {
	tv = &vertices[im][iv];	/* Pointer to this vertex's struct */
	vx = tv->x;
	vy = tv->y;
	cx = CELL(vx);
	cy = CELL(vy);

	for (cy2 = cy; cy2 <= grid_size; cy2++)	/* interate up the column of cells */
	    if (cy2 == grid_size)	/* fell off top of grid */
		ipol = 0;
	    else
	     /* Is whole cell in one polygon? */ if ((ipol = polygon_containing_cell[im2][cx][cy2]) != DONTKNOW)
		break;
	    else {
		tc = grid[cx][cy2];
		if (tc == NULL)
		    ne = 0;
		else {
		    if (im2 == 0)
			ne = tc[2] - (base = CELL_HEADER_LEN);	/* for map 0 */
		    else
			ne = tc[1] - (base = tc[2]);
		}
		nec[cy2] = ne;
		if (ne == 0)
		    continue;	/* no edges in this cell */

		besty = HUGE_VAL;
		beste = NULL;
		test_against_edges_of_this_cell();

		if (beste == NULL)
		    continue;	/* no edges in this cell above this vertex */

		/*
		 * We have the edge!  Iff it is running left to right then we want
		 * the right polygon.
		 */

		if (vertices[im2][beste->v1].x < vertices[im2][beste->v2].x)
		    ipol = beste->pr;
		else
		    ipol = beste->pl;

		break;
	    }

	tv->p = ipol;
	for (cy3 = cy2 - 1; cy3 >= cy; cy3--) {	/* Iterate down labelling cells when
						 * possible. */
	    if (polygon_containing_cell[im2][cx][cy3] != DONTKNOW)
		break;		/* Stop at first cell where we know the containing
				 * polygon. */
	    if (nec[cy3] > 0)
		break;		/* Stop if cell has edges; then it can't be
				 * completely in one polygon. */
	    polygon_containing_cell[im2][cx][cy3] = ipol;
	}
    }				/* for(iv=0... */
}


int
cell(VERT_COORD_T xy) {
    return (CELL(xy));
}

/** scale_vertices
 * Scale the map's vertices to fall in [INTERNAL_MIN, INTERNAL_MAX].  Do this for
 * both maps after they are read in so that they are scaled together. Print average
 * edge length.
 */

void scale_vertices(FLOAT_VERTEX_T fv[], VERTEX_T v[], CHAIN chain[], int n_chains) {
    int     i, j, k;
    float   sum = 0., avg_edge;
    int     num_edges;
    INTERMED_COORD_T dx, dy;

    i = 0;
    num_edges = 0;

    for (k = 0; k < n_chains; k++) {
	for (j = 0; j < chain[k].num_vert; j++) {
	    v[i].x = SCALEX(fv[i].x);
	    v[i].y = SCALEY(fv[i].y);
	    i++;
	}
    }

    /* Find the average edge length */

    i = 1;

    for (k = 0; k < n_chains; k++) {

	for (j = 1; j < chain[k].num_vert; j++) {

	    /* abolish sqrt for speed.  Each is 590 msec on a Sun 3/60 using cc -g. */
	    dx = v[i].x - v[i - 1].x;
	    dy = v[i].y - v[i - 1].y;
	    /* sum += sqrt((double)(dx * dx) + (double)(dy * dy)); */
#define ABS(x) ((x)>0 ? (x) : (-x))
	    sum += ABS(dx) + ABS(dy);
	    i++;
	    num_edges++;

	}			/* for j */
	i++;
    }				/* for k */

    avg_edge = sum / num_edges / INTERNAL_RANGE / 2;	/* 2 for dx and dy */
    printf("Average edge length component as fraction of map size= %f\n", avg_edge);
    printf("Scaling: intx=extx*%f+%f, inty=exty*%f+%f\n", rx, deltax, ry, deltay);

}




/** accumulate_areas:  accumulate_vertex_areas, accumulate_xsect_areas

/* Accumulate the areas of the output polygons due to the input vertices. */

/* Calc unscaled squared length of edge from dx and dy */

#define CALCDD(dx,dy)  ( rx*ry*(SQ((float)(dx))+SQ((float)(dy))) )

void accumulate_vertex_areas(int     mapno, HASH_RECORD_T *area_table) {
    int     ie, pol1, pol2;
    long int outpol;
    /*
     * Keep dx, dy float since otherwise they would have to be coerced to float
     * whenever used.
     */
    float   dx, dy;
    float   a, a0, a1, a2, dd;
    VERTEX_T *v1, *v2;
    EDGE_T *this_edge;
    int     ne = n_edges[mapno];
    long int badpol;

    /* Trace one output polygon, e.g., badpol = OUTPUT_POLYGON(28,28); */

    for (ie = 0; ie < ne; ie++) {

	this_edge = &edges[mapno][ie];
	v1 = &vertices[mapno][this_edge->v1];
	v2 = &vertices[mapno][this_edge->v2];

	dx = this_edge->dx = v2->x - v1->x;
	dy = this_edge->dy = v2->y - v1->y;
	dd = CALCDD(dx, dy);

	if (dd == 0.0) {
	    printf("Error in accumulate_areas: Zero length edge, map #%d, edge #%d, lpol= %d, rpol= %d\n",
		   mapno, ie, this_edge->pl, this_edge->pr);
	    continue;
	}
	a1 = (v1->x * dx + v1->y * dy) * (float) (v1->x * dy - v1->y * dx) / dd;
	a2 = (v2->x * dx + v2->y * dy) * (float) (v2->x * dy - v2->y * dx) / dd;

	/*
	 * The size of the following code could be reduced by using arrays for the 2
	 * ends of each edge, etc.  However the structures would be bigger and the
	 * code would be slower.
	 */

	/* 1st end of edge */
	a0 = a1;
	pol2 = v1->p;

	/* left side of 1st end */
	pol1 = this_edge->pl;
	a = -a0;
	outpol = ((mapno == 0) ? OUTPUT_POLYGON(pol1, pol2) : OUTPUT_POLYGON(pol2, pol1));

	/**	if (outpol==badpol)  printf("Adding area %f to badpol, map=%d, ie=%d, 1l, edge verts= %d %d, edge pols= %d %d\n", a, mapno, ie, this_edge->v1, this_edge->v2, this_edge->pl, this_edge->pr); */

	find_hash_key_add_value(area_table, (HASH_KEY_T) outpol, a);

	/* right side of 1st end */
	pol1 = this_edge->pr;
	a = a0;
	outpol = ((mapno == 0) ? OUTPUT_POLYGON(pol1, pol2) : OUTPUT_POLYGON(pol2, pol1));
	/**	if (outpol==badpol)  printf("Adding area %f to badpol, map=%d, ie=%d, 1r, edge verts= %d %d, edge pols= %d %d\n", a, mapno, ie, this_edge->v1, this_edge->v2, this_edge->pl, this_edge->pr); */
	find_hash_key_add_value(area_table, (HASH_KEY_T) outpol, a);


	/* 2nd end of edge */
	a0 = a2;
	pol2 = v2->p;

	/* left side of 2nd end (looking from 2nd end) */
	pol1 = this_edge->pr;
	a = -a0;
	outpol = ((mapno == 0) ? OUTPUT_POLYGON(pol1, pol2) : OUTPUT_POLYGON(pol2, pol1));
	/**	if (outpol==badpol)  printf("Adding area %f to badpol, map=%d, ie=%d, 2l, edge verts= %d %d, edge pols= %d %d\n", a, mapno, ie, this_edge->v1, this_edge->v2, this_edge->pl, this_edge->pr); */
	find_hash_key_add_value(area_table, (HASH_KEY_T) outpol, a);

	/* right side of 2nd end */
	pol1 = this_edge->pl;
	a = a0;
	outpol = ((mapno == 0) ? OUTPUT_POLYGON(pol1, pol2) : OUTPUT_POLYGON(pol2, pol1));
	/**	if (outpol==badpol)  printf("Adding area %f to badpol, map=%d, ie=%d, 2r, edge verts= %d %d, edge pols= %d %d\n", a, mapno, ie, this_edge->v1, this_edge->v2, this_edge->pl, this_edge->pr); */
	find_hash_key_add_value(area_table, (HASH_KEY_T) outpol, a);
    }
}


void accumulate_xsect_areas(xsect, nxsect, area_table)
    XSECT_T xsect[];
    int     nxsect;
    HASH_RECORD_T *area_table;
{
    int     i;
    long int outpol;
    float   a, a1, a2, dd1, dd2;
    int     p1l, p1r, p2l, p2r;
    int     cas;		/* to help debugging */
    EDGE_T *edge1, *edge2;
    long int badpol;

    /* badpol= -999999; */

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

	edge1 = &edges[0][xsect[i].e1];
	edge2 = &edges[1][xsect[i].e2];

	dd1 = CALCDD(edge1->dx, edge1->dy);
	dd2 = CALCDD(edge2->dx, edge2->dy);

	a1 = (xsect[i].x * (float) edge1->dx + xsect[i].y * (float) edge1->dy) *
	    (xsect[i].x * (float) edge1->dy - xsect[i].y * (float) edge1->dx) / dd1;
	a2 = (xsect[i].x * (float) edge2->dx + xsect[i].y * (float) edge2->dy) *
	    (xsect[i].x * (float) edge2->dy - xsect[i].y * (float) edge2->dx) / dd2;

	p1l = edge1->pl;
	p1r = edge1->pr;
	p2l = edge2->pl;
	p2r = edge2->pr;

	a = a1 - a2;
	if ((edge1->dx * (float) edge2->dy) < (edge1->dy * (float) edge2->dx))
	    a = -a;

	outpol = OUTPUT_POLYGON(p1l, p2l);
	cas = 11;
	/**	if (outpol==badpol) printf("Adding area %f to badpol, ix=%d, edges=%d %d, case ll\n", a, i, xsect[i].e1, xsect[i].e2); */
	find_hash_key_add_value(area_table, (HASH_KEY_T) outpol, a);

	outpol = OUTPUT_POLYGON(p1r, p2r);
	cas = 22;
	/**	if (outpol==badpol) printf("Adding area %f to badpol, ix=%d, edges=%d %d, case rr\n", a, i, xsect[i].e1, xsect[i].e2); */
	find_hash_key_add_value(area_table, (HASH_KEY_T) outpol, a);

	a = -a;

	outpol = OUTPUT_POLYGON(p1l, p2r);
	cas = 12;
	/**	if (outpol==badpol) printf("Adding area %f to badpol, ix=%d, edges=%d %d, case lr\n", a, i, xsect[i].e1, xsect[i].e2); */
	find_hash_key_add_value(area_table, (HASH_KEY_T) outpol, a);

	outpol = OUTPUT_POLYGON(p1r, p2l);
	cas = 21;
	/**	if (outpol==badpol) printf("Adding area %f to badpol, ix=%d, edges=%d %d, case rr\n", a, i, xsect[i].e1, xsect[i].e2); */
	find_hash_key_add_value(area_table, (HASH_KEY_T) outpol, a);


    }
}


void total_the_areas(area_table)
    HASH_RECORD_T *area_table;
{
    HASH_RECORD_T *(inarea[2]), *(pinarea[2]), *poutarea;	/* p=packed */
    int     pol1, pol2, noutpol, i, n, mapno;
    HASH_KEY_T outpol;
    float   a;

    noutpol = get_hash_n_records(area_table);
    printf("\n# output polygons=%d\n", noutpol);
    poutarea = pack_hash_table(area_table);

    for (mapno = 0; mapno < 2; mapno++)
	inarea[mapno] = create_hash_table(n_pols[mapno] * 2);	/* 50% occupancy for
								 * hash table */

    for (i = 0; i < noutpol; i++) {
	outpol = (poutarea + i)->k;
	pol1 = INPUT_POLYGON_1(outpol);
	pol2 = INPUT_POLYGON_2(outpol);

	a = (poutarea + i)->v;
	find_hash_key_add_value(inarea[0], (HASH_KEY_T) pol1, a);
	find_hash_key_add_value(inarea[1], (HASH_KEY_T) pol2, a);
    }

    for (mapno = 0; mapno < 2; mapno++) {
	printf("\nAreas of input polygons in map %d, from summing over the output polygons\n", mapno);
	n = get_hash_n_records(inarea[mapno]);
	if (n != n_pols[mapno])
	    printf("Calcareas found %d polygons in map %d, while total the areas finds %d.\n", n, mapno, n_pols[mapno]);

	pinarea[mapno] = pack_hash_table(inarea[mapno]);

	for (i = 0; i < n; i++)
	    printf("%5ld: %9.5g\n", (pinarea[mapno] + i)->k, 0.5 * (pinarea[mapno] + i)->v);
    }
}



/** timers.c
 * Returns time in seconds since last read_delta_time.  Automatically initializes
 * itself on 1st call and returns 0.
 */

double read_delta_time() {
    static struct tms *time_buffer;
    static time_t old_time, new_time;	/* in 60ths of a second */
    double  delta;

    if (time_buffer == NULL) {
	time_buffer = (struct tms *) malloc((unsigned) sizeof(struct tms));
	return old_time = 0;
    }
    (void) times(time_buffer);
    new_time = time_buffer->tms_utime + time_buffer->tms_stime;
    delta = (new_time - old_time) / 60.;
    old_time = new_time;
    return delta;
}


/** Print:   Print assorted data structures */


/* Print the chains in one map */

void print_chains(CHAIN   chain[], int     n) {
    int     i;
    printf("\n# Chains= %d. i, num_vert, lpol, rpol= \n", n);
    for (i = 0; i < n; i++)
	printf("   %d: %d %d %d %d\n", i, chain[i].base, chain[i].num_vert, chain[i].lpol, chain[i].rpol);
}

/* Print the vertices in one map, in both formats */

void print_vertices(v, n, fvertex)
    VERTEX_T v[];
    int     n;
    FLOAT_VERTEX_T fvertex[];

{
    int     i;
    printf("\n# Vertices= %d. Internal: x,y. External: x,y\n", n);
    for (i = 0; i < n; i++)
	printf("   %3d: (%6d, %6d).  (%8.3f, %8.3f).\n", i, v[i].x, v[i].y, fvertex[i].x, fvertex[i].y);
}


void print_output_areas(table)
    HASH_RECORD_T *table;
{
    int     i, n, k1, k2;
    HASH_KEY_T k;
    HASH_RECORD_T *list;
    float   this_area, tol;

    tol = rrx * rry * 200;	/* zero any smaller areas */
    n = get_hash_n_records(table);
    list = pack_hash_table(table);
    printf("\nAreas of %d output polygons in this map:\n", n);
    for (i = 0; i < n; i++) {
	k = (list + i)->k;
	k1 = INPUT_POLYGON_1(k);
	k2 = INPUT_POLYGON_2(k);
	/* The 0.5 is part of the area formula */
	this_area = (list + i)->v * 0.5;
	if ((-tol) < this_area && this_area < tol);
	else
	    printf(" %5d x%5d: %9.5g\n", k1, k2, this_area);
    }
}



void print_int_array(title, a, n)	/* Print an int array with title and appropriate
				 * \ns. */
    char   *title;
    int    *a, n;
{
    int     i;
    printf("%s", title);
    for (i = 0; i < n; i++) {
	if ((i % 20) == 0)
	    printf("\n");
	printf(" %3d", a[i]);
    }
    printf("\n");
}



void print_short_int_array(title, a, n)	/* Print an int array with title and
					 * appropriate \ns. */
    char   *title;
    short int *a;
    int     n;
{
    int     i;
    printf("%s", title);
    for (i = 0; i < n; i++) {
	if ((i % 20) == 0)
	    printf("\n");
	printf(" %3d", a[i]);
    }
    printf("\n");
}


void print_ushort_int_array(title, a, n)	/* Print an unsigned short int array with
					 * title and appropriate \ns. */
    char   *title;
    unsigned short int *a;
    int     n;
{
    int     i;
    printf("%s", title);
    for (i = 0; i < n; i++) {
	if ((i % 20) == 0)
	    printf("\n");
	printf(" %3d", a[i]);
    }
    printf("\n");
}



int main() {
    char    map_names[2][MAX_MAP_NAME_LEN];
    float   t_locate[2], timers[10], tottime;
    int     i;
    HASH_RECORD_T *area_table;
    int     area_table_size;
    FLOAT_VERTEX_T *fverts[2];


    (void) read_delta_time();

    printf("Overpropf was compiled on %s\n", __DATE__);
    printf("= Compiled constants for this run:\n   MAX_CHAINS= %d\n   MAX_VERTS= %d\n",
	   MAX_CHAINS, MAX_VERTS);
    printf("   MAX_EDGES= %d\n   MAX_PTS_PER_CHAIN= %d\n   MAX_MAP_NAME_LEN= %d\n   MAX_XSECTS= %d\n",
	   MAX_EDGES, MAX_PTS_PER_CHAIN, MAX_MAP_NAME_LEN, MAX_XSECTS);
    printf("Sizes of some structures:\n   VERTEX_T= %lu\n   FLOAT_VERTEX_T=%lu\n",
	   sizeof(VERTEX_T), sizeof(FLOAT_VERTEX_T));
    printf("   EDGE_T= %lu\n   HASH_RECORD_T= %lu\n   XSECT_T= %lu\n   SLAB= %lu\n   CHAIN= %lu\n",
	   sizeof(EDGE_T), sizeof(HASH_RECORD_T), sizeof(XSECT_T), sizeof(SLAB), sizeof(CHAIN));

    debug_print_grid = 0;	/* These control printing of debug info */
    debug_add_map_to_grid = 0;
    debug_add_edge_to_cell = 0;
    debug_calc_areas = 0;
    debug_inclusions = 0;
    debug_print_xsect = 0;
    debug_print_chains_vertices = 0;
    debug_zero_len_edges = 0;
    n_dupl_xsect = 0;
    n_hash_compar = 0;
    n_zero_len_edges = 0;

    /* Copy constants into variables so they will be available at debugging time   */
    Max_Chains = MAX_CHAINS;
    Max_Verts = MAX_VERTS;
    Max_Edges = MAX_EDGES;
    Max_Pts_Per_Chain = MAX_PTS_PER_CHAIN;
    Max_Map_Name_Len = MAX_MAP_NAME_LEN;
    Max_Xsects = MAX_XSECTS;
    Max_Grid_Histogram = MAX_GRID_HISTOGRAM;
    Cell_Header_Len = CELL_HEADER_LEN;
    Hash_Table_Disp = HASH_TABLE_DISP;
    Polygon_Id_Min = POLYGON_ID_MIN;
    Polygon_Id_Max = POLYGON_ID_MAX;
    Internal_Min = INTERNAL_MIN;
    Internal_Max = INTERNAL_MAX;
    Internal_Range = INTERNAL_RANGE;

    xsect = (XSECT_T*) malloc2((unsigned) (MAX_XSECTS*sizeof(XSECT_T)), 
			       "Malloc of xsect failed in main.");

    /* Alloc floating vertex space */
    FOR2 {
	fverts[im] =
	    (FLOAT_VERTEX_T *) malloc2((unsigned) (MAX_VERTS * sizeof(FLOAT_VERTEX_T)),
				       "Malloc of fverts failed in main.");
    }
    /* Prompt for map names and read the chains in floating coords. */

    FOR2 {
	printf("= Map #%d? ", im);
	scanf("%50s", map_names[im]);
	read_pgraph(map_names[im], fverts[im], &n_verts[im], chains[im],
		    &n_chains[im], &xmins[im], &xmaxs[im], &ymins[im], &ymaxs[im]);
    }

    timers[0] = read_delta_time();

    /* Find common bounds and scales */
    ext_xmax = MAX(xmaxs[0], xmaxs[1]);
    ext_ymax = MAX(ymaxs[0], ymaxs[1]);
    ext_xmin = MIN(xmins[0], xmins[1]);
    ext_ymin = MIN(ymins[0], ymins[1]);

    rx = (((float) INTERNAL_RANGE) / (ext_xmax - ext_xmin));
    ry = (((float) INTERNAL_RANGE) / (ext_ymax - ext_ymin));
    rrx = 1.0 / rx;
    rry = 1.0 / ry;

    deltax = 0.5 * ((INTERNAL_MAX + INTERNAL_MIN) - (ext_xmax + ext_xmin) * rx);
    deltay = 0.5 * ((INTERNAL_MAX + INTERNAL_MIN) - (ext_ymax + ext_ymin) * ry);
    ddeltax = 0.5 * ((ext_xmax + ext_xmin) - (INTERNAL_MAX + INTERNAL_MIN) * rrx);
    ddeltay = 0.5 * ((ext_ymax + ext_ymin) - (INTERNAL_MAX + INTERNAL_MIN) * rry);

    /* Scale the float vers into ints. */

    FOR2    scale_vertices(fverts[im], vertices[im], chains[im], n_chains[im]);

    if (debug_print_chains_vertices) {
	FOR2 {
	    printf("-- Map #%d --\n", im);
	    print_vertices(vertices[im], n_verts[im], fverts[im]);
	    print_chains(chains[im], n_chains[im]);
	}
    };

    /* Free the float vertex space */
    FOR2 {
	free((char *) fverts[im]);
	fverts[im] = NULL;
    }

    timers[1] = read_delta_time();

    /* Split the chains into edges. */
    FOR2    extract_edges(im, chains[im], n_chains[im]);

    timers[2] = read_delta_time();

    /* Calculate input polygon areas and print. */
    FOR2    n_pols[im] = calc_areas(vertices[im], edges[im], n_edges[im]);

    FOR2    printf("= Map #%d: %d vertices, %d edges, %d polygons\n", im, n_verts[im], n_edges[im], n_pols[im]);

    timers[3] = read_delta_time();

    printf("= Gridsize? ");
    scanf("%d", &grid_size);
    (void) make_grid();

    timers[4] = read_delta_time();

    /* Determine the cells each edge passes through and insert into grid. */
    FOR2    add_map_to_grid(vertices[im], edges[im], n_edges[im], im);

    if (debug_print_grid)
	print_grid();
    print_grid_histogram();

    timers[5] = read_delta_time();

    /* Intersect all the edges. */
    intersect_edges(vertices[0], edges[0], vertices[1], edges[1], xsect, &nxsect);
    printf("Number of pairs of edges tested for intersection= %d\n",
	   n_edge_pairs_tested_for_xsect);
    printf("Number of intersections found= %d\n", nxsect);
    printf("Number of duplicate intersections found= %d\n", n_dupl_xsect);
    printf("Number of zero length edges (after scaling)= %d\n", n_zero_len_edges);

    timers[6] = read_delta_time();

    FOR2 {
	locate_vertices_in_other_map();
	t_locate[im] = read_delta_time();
    }

    if (debug_inclusions) {
	printf("\nPolygons in map 0 that the vertices of map 1 fall in:");
	for (i = 0; i < n_verts[1]; i++) {
	    if ((i % 20) == 0)
		printf("\n");
	    printf(" %3d", vertices[1][i].p);
	}
	printf("\n");
	printf("\nPolygons in map 1 that the vertices of map 0 fall in:");
	for (i = 0; i < n_verts[0]; i++) {
	    if ((i % 20) == 0)
		printf("\n");
	    printf(" %3d", vertices[0][i].p);
	}
	printf("\n");
    };

    /* The hash table size is impossible to predict in advance; it might range from
     * the total number of polygons up to the product of the numbers of the polygons
     * in the 2 maps.  Therefore, guess, and if it overflows, then change it. */
    area_table_size = (n_pols[0] + n_pols[1] + n_verts[0] + n_verts[1]) * 5;
    area_table = create_hash_table(area_table_size);

    FOR2    accumulate_vertex_areas(im, area_table);

    accumulate_xsect_areas(xsect, nxsect, area_table);

    timers[7] = read_delta_time();

    print_output_areas(area_table);

    /* Check that the components of each polygon add up correctly */
    if (debug_calc_areas)
	total_the_areas(area_table);

    timers[8] = read_delta_time();

   printf("\n= Execution times:\n\
   Read map:                     %5.2f\n\
   Scale vertices:               %5.2f\n\
   Extract edges:                %5.2f\n\
   Calculate areas:              %5.2f\n\
   Make grid:                    %5.2f\n",
	   timers[0], timers[1], timers[2], timers[3], timers[4]);

    printf("\
   Add map to grid:              %5.2f\n\
   Intersect edges:              %5.2f\n\
   Locate map 0 points in map 1: %5.2f\n\
   Locate map 1 points in map 0: %5.2f\n\
   Accumulate areas:             %5.2f\n\
   Print areas:                  %5.2f\n",
	   timers[5], timers[6], t_locate[0], t_locate[1], timers[7], timers[8]);

    tottime = timers[0] + timers[1] + timers[2] + timers[3] + timers[4] +
	timers[5] + timers[6] + timers[7] + timers[8] +
	t_locate[0] + t_locate[1];
    printf("\nTOTAL TIME=                    %7.2f\n\n", tottime);
}

