#include <stdio.h>
#include <math.h>
#include "types.h"

/* Freeman: (note that to make all the line elements roughly the same length,
 *   we skip a pixel at some points where we don't have to).
 *
 *    Y|X=  -2  -1   0   1   2
 *    -|----------------------
 *    2|     6   5   4   3   2
 *     |
 *    1|     7   .   .   .   1
 *     |
 *    0|     8   .   X   .   0
 *     |
 *   -1|     9   .   .   .  15
 *     |
 *   -2|    10  11  12  13  14
 */
static int
  Xoffset16[] = {2, 2, 2, 1, 0, -1, -2, -2, -2, -2, -2, -1,  0,  1,  2,  2},
  Yoffset16[] = {0, 1, 2, 2, 2,  2,  2,  1,  0, -1, -2, -2, -2, -2, -2, -1};

/* Skipping 3 pixels
 *
 *    Y|X=  -3  -2  -1   0   1   2   3
 *    -|------------------------------
 *    3|     9   8   7   6   5   4   3
 *     |
 *    2|    10   .   .   .   .   .   2
 *     |
 *    1|    11   .   .   .   .   .   1
 *     |
 *    0|    12   .   .   X   .   .   0
 *     |
 *   -1|    13   .   .   .   .   .  23
 *     |
 *   -2|    14   .   .   .   .   .  22
 *     |
 *   -3|    15  16  17  18  19  20  21
 */
static int
  Xoffset24[] = {3, 3, 3, 3, 2, 1, 0, -1, -2, -3, -3, -3, -3, -3, -3, -3, -2, -1,  0,  1,  2,  3,  3,  3},
  Yoffset24[] = {0, 1, 2, 3, 3, 3, 3,  3,  3,  3,  2,  1,  0, -1, -2, -3, -3, -3, -3, -3, -3, -3, -2, -1};



void
set_xy_offset(Xoffset,Yoffset, K, scale)
int **Xoffset, **Yoffset, K, scale;
{
  int i;
  
  switch(K) {
  case 16: *Xoffset = Xoffset16; *Yoffset = Yoffset16; break;
  case 24: *Xoffset = Xoffset24; *Yoffset = Yoffset24; break;
  default: fprintf(stderr,
		   "set_xy_offset: Cannot handle %d orientations. exiting...\n", K);
    exit(1); }
  if(scale != 1)
    for(i=0; i<K; i++) {
      (*Xoffset)[i] *= scale; (*Yoffset)[i] *= scale; }
}


/* K = # orientations
 */
element ***
  make_map(w,h,K)
int w,h,K;
{
  char ***iiialloc();
  
  return (element ***) iiialloc(w,h,K,sizeof(element));
}


void
  free_map(map)
element ***map;
{
  void iiifree();
  
  iiifree((char ***)map);
}


void
  elt_list_to_map(map, xs,ys,ks,sals,neighs,n, w,h,K)
int *xs, *ys, *ks, *neighs, n, w,h,K;
double *sals;
element ****map;
{
  int i, x,y,k;
  element *elt_a;
  real sigma, rho;
  
  switch(K) {
  case 16: sigma = 2.; rho= .49; break;
  case 24: sigma = 3.; rho= .343; break;
  default: fprintf(stderr, "Cannot handle %d orientations. exiting...\n", K); exit(1); }
  
  *map = make_map(w,h,K);
  
  for(x=0;x<w;x++) for(y=0;y<h;y++) for(k=0;k<K;k++) {
    elt_a = &((*map)[x][y][k]);
    elt_a->sigma = elt_a->sal = 0.;                   /* set all elements to be gaps */
    elt_a->rho = rho;
    elt_a->neigh = -1;
  }  
  for(i=0; i<n; i++) {
    elt_a = &((*map)[xs[i]][ys[i]][ks[i]]);
    elt_a->sal = sals[i];
    elt_a->neigh = neighs[i];
    elt_a->sigma = sigma;
    elt_a->rho = 1;
  }
}


/* Given the starting element and the number of elements to trace,
 * writes the saliencies of the elements onto the image pixels at the tails
 * of the arrows.
 * Also sets elts of bmap to used.
 */
void
  trace_curve_bmap(image, x,y,k, n_steps, map,bmap, w,h,K, printcurve, Xoffset,Yoffset)
imagetype **image;
element ***map;
short ***bmap;
int x,y,k, w,h,K, n_steps, printcurve, *Xoffset,*Yoffset;
{
  int i, numpts = K == 16 ? 5 : 7;
  element *elt_a;
  void scanls_max_no_last();
  /* void write_block(); */

  for(i=0; i < n_steps; i++) {
    bmap[x][y][k] = 0;               /* set element to unactive (gap) */
    elt_a =  &(map[x][y][k]);
    if(printcurve)
      printf("  Elt (%d,%d,%d): sal=%f rho=%.2f sigma=%.3f neigh=%d\n",
	     x,y,k, elt_a->sal, elt_a->rho, elt_a->sigma, elt_a->neigh);
    if(inbounds(x + Xoffset[k], y + Yoffset[k], w,h))
      scanls_max_no_last(x,y, x+Xoffset[k], y+Yoffset[k], image, numpts, (imagetype) 1);
    /* write_block(x,y, 1.0, image, w,h); */
    x += Xoffset[k];
    y += Yoffset[k];
    if(!inbounds(x, y, w,h)) {
      printf("  Curve ran outside image at step %d\n", i);
      return; }
    if(elt_a->neigh == -1) {
      fprintf(stderr, "trace_curve_map: Current element has no neighbor. ");
      fprintf(stderr, "Step= %d\n", i); }
    k = elt_a->neigh; }
  /* write_block(x,y, 1.0, image, w,h); */ /* write the head of the last element */
}
