/*  
    Copyright (C) 2003 Johan Borg

    This file is part of xmerge.

    xmerge 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.
                
    xmerge 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 xmerge; if not, write to the Free Software
    Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
*/


#include "xmerge.h"


Display *disp;  
int scrn;        
Visual *visual;
Window win1;
XEvent event,nevent;      

GC gc;       

Colormap color;

//with this, expose messages directly following an configure notify are ignored
//#define CONF_EXP_SKIP  1

int mode=0;
int Bpp,bpp;	//Bytes/pixel	(2 or 3)
int Bgr;	//byte order
int Dx,Dxx,Dy;	//display size
int Dxo,Dyo;	//display origin
int Dxm,Dym;	//total display size
int DxM,DyM;	//origin
int Dxm1,Dym1;
int zoom;


unsigned char *xdata,*xdata2,*xdata3;
int improve=1;
int Integers=1;
int dmd=0;

int Ml0,Mt0,Mr0,Mb0;	//outer limits of the mapped image

int RCOL_r=255,RCOL_g=255,RCOL_b=255;

int aborting;

XImage *gimg,*img2,*img3;



#define EDGE_DIST 10


XColor Cblack,Cred,Cyellow,Cgreen,Cblue,Cwhite;
//unsigned int Cblack,Cred,Cyellow,Cgreen,Cblue,Cwhite;
Cursor Bcursor,Dcursor;

/*
void setname(const char *fmt, ...) {
 char buf[128]="xmerge: ";
 va_list l;
 va_start(l, fmt);
 a = vsnprintf(buf+8, 120, fmt, l);
 va_end(l);
 XStoreName(disp,win1,buf);
}*/


void setname(char * Mode) {
 char buf[128];
 static char nbuf[32];
 
 if (Mode) strncpy(nbuf,Mode,32); else Mode=nbuf;
 if (zoom>zoommax) snprintf(buf,128,"xmerge: %s view, 1/%dx, %s mode %s%s",(dmd?"target":"source"),zoom/zoommax,Mode,(improve?"(Auto) ":""),(Integers?"":"(Int)"));
  else snprintf(buf,128,"xmerge: %s view, %dx, %s mode %s%s",(dmd?"target":"source"),zoommax/zoom,Mode,(improve?"(Auto)":""),(Integers?"":"(Int)"));
 XStoreName(disp,win1,buf);
}


void disable_cursor () {
 XDefineCursor(disp,win1,Bcursor);
}

void enable_cursor() { 
 XDefineCursor(disp,win1,Dcursor);
}



edget * edge_add(IMG *img,edget *pos,int x,int y) {
 edget *a;
 a=malloc(sizeof(edget));
 a->x=x;
 a->stat=0;
 a->y=y;
 if (pos) { 
  a->next=pos->next;
  if (pos->next) pos->next->prev=a;
  pos->next=a;
 } else {
  img->edge=a;
  a->next=0;  
 } 
 a->prev=pos;
 img->edgen++;
 return a;
}


void edge_del(IMG *img,edget *pos) {
 edget *a,*b;
 if (!pos) return;
 
 a=pos->next;
 b=pos->prev;
 
 if (a) a->prev=b;
 if (b) b->next=a; else img->edge=a;
 img->edgen--;
 free(pos);
}


edget *edge_find(IMG **Img,int *j,int x,int y) {
 edget *pos,*mpose,*mposc;
 IMG *img;
 double x1,y1,x2,y2;
 double X,Y,d,dmine,dminc; 
 int n,Ne=0,Nc=0;
 d=0;
 mpose=0;
 mposc=0;
 

 dmine=1e43; 
 dminc=1e43; 

 for(n=0;n<Ot;n++) {
  img=simg[n];
  pos=img->edge;
  x2=pos->X;
  y2=pos->Y;


  while(pos) {
   x1=x2;
   y1=y2;
   if (pos->next) { x2=pos->next->X; y2=pos->next->Y; } else 
                  { x2=img->edge->X; y2=img->edge->Y; }

      
   X=x-x1;
   Y=y-y1;
   
   d=X*X+Y*Y;
   if (d<dminc) {  dminc=d; mposc=pos; Nc=n; }
   
   d=(X*(x2-x1)+Y*(y2-y1))/((x2-x1)*(x2-x1)+(y2-y1)*(y2-y1));
   if ((d>0) && (d<1)) {
    X=X-(x2-x1)*d;
    Y=Y-(y2-y1)*d;
    d=X*X+Y*Y;
    if (d<dmine) { dmine=d; mpose=pos; Ne=n; }
   } 
   pos=pos->next;
  }
 } 
 
 dmine=sqrt(dmine);
 dminc=sqrt(dminc);
 
// printf("dmin: %f %f\n",dminc,dmine);

 if (dminc<EDGE_DIST) {
  *Img=simg[Nc];
  *j=1;
  return mposc;
 } 
 
 if (dmine<EDGE_DIST) {
  *Img=simg[Ne];
  *j=0;
  return mpose;
 } 
 
 return 0;
}





void draw_edges(IMG *img) {
 edget *edge;
 double x1,y1,x2,y2;
 edge=img->edge;
 x2=edge->X;
 y2=edge->Y;
 while(edge) {
  x1=x2;
  y1=y2;
   
  if (edge->next) { x2=edge->next->X; y2=edge->next->Y; } else 
                  { x2=img->edge->X; y2=img->edge->Y; }
  
  if (!(edge->stat&1)) mline(xdata,Dx,Dy,x1,y1,x2,y2,Cyellow.pixel,Cblack.pixel);
  edge=edge->next;
 } 
}




void adjust_xy(IMG *img,double *x,double *y) {
 double x1,y1,x2,y2;
 double X,Y,d,dmin,e,f,xmin,ymin,dminc,XX[4],YY[4]; 
 int n,Nc=0;
 d=0;
 
 dmin=1e43; 
 dminc=1e43;

 
 x2=img->dx1;
 y2=img->dy1;
 
 XX[0]=img->dx2; YY[0]=img->dy2;
 XX[1]=img->dx4; YY[1]=img->dy4;
 XX[2]=img->dx3; YY[2]=img->dy3;
 XX[3]=img->dx1; YY[3]=img->dy1; 
 

 for(n=0;n<4;n++) {

  x1=x2;
  y1=y2;
  x2=XX[n];
  y2=YY[n];
      
  X=*x-x1;
  Y=*y-y1;
  
  d=X*X+Y*Y;
  if (d<dminc) {dminc=d; xmin=x1; ymin=y1; Nc=n;}
  
   //this should be possible to simplify somehow... soo tired :/
  f=(X*(x2-x1)+Y*(y2-y1))/((x2-x1)*(x2-x1)+(y2-y1)*(y2-y1));
  X=X-(x2-x1)*f;
  Y=Y-(y2-y1)*f;
  e=X*(y2-y1)-Y*(x2-x1);
  if (e>0) {
   if (f<0) f=0;
   if (f>1) f=1;
   *x=(x2-x1)*f+x1;
   *y=(y2-y1)*f+y1;
  }
  
 }
}





// return the image at the end of the list, if overlapping images at this point
//(this way we can rotate through the list of images)
int find_cimg2(int x,int y){
 int a,d,n;
 double X,Y,XX[4],YY[4],e,x2,y2,x1,y1;
 IMG *img;
 
 for(a=0;a<Ot;a++) {
  img=simg[a];
 
  x2=img->dx1;
  y2=img->dy1;
 
  XX[0]=img->dx2; YY[0]=img->dy2;
  XX[1]=img->dx4; YY[1]=img->dy4;
  XX[2]=img->dx3; YY[2]=img->dy3;
  XX[3]=img->dx1; YY[3]=img->dy1; 
 
  d=0;
  for(n=0;n<4;n++) {
 
   x1=x2;
   y1=y2;
   x2=XX[n];
   y2=YY[n];
      
   X=x-x1;
   Y=y-y1;
  
   e=X*(y2-y1)-Y*(x2-x1);
   
   if (e<0) d++;
  }
  if (d==4) return a;	//well, non-convex targets won't work quite correctly, but then again, the image mapping doesn't work for all such shapes anyway
 } 		       
 return -1;
}   		       





//some windowing would probbably be a good thing? 
//we use a hamming window, might not be exactly optimal for this application, but should suffice
//disabled now, I think it works better like this

//coarse match calculation
double calc_match_c(IMG *img1,IMG *img2,int x1,int y1,int x2,int y2,int dx,int dy) {
 int x,y,p1,p2,p1_,p2_,sx1,sx2;
 double err,c,e;
// double i1,i2;
 pixt *pix1,*pix2; 
// double xw[MAXMATCH],yw;
 
 pix1=img1->pix;
 pix2=img2->pix;
 sx1=img1->sx;
 sx2=img2->sx;

// printf("x1: %d %d %d %d\n",x1,y1,x2,y2);

// for(x=0;x<dx;x++) xw[x]=0.54-0.46*cos(2*3.1415926535*x/dx); 
 
 c=0;
 err=0;
 for(y=0;y<=dy;y++) {
  if (y1+y<0) continue;
  if (y2+y<0) continue;
  if (y1+y>=img1->sy) continue;
  if (y2+y>=img2->sy) continue;  
  p1=img1->sx*(y1+y)+x1;
  p2=img2->sx*(y2+y)+x2;
//  yw=0.54-0.46*cos(2*3.1415926535*y/dy); 
  
  for(x=0;x<=dx;x++) {
   p1_=p1++;
   p2_=p2++;
   if (x1+x<0) continue;
   if (x2+x<0) continue;
   if (x1+x>=sx1) continue;
   if (x2+x>=sx2) continue;
   e=((pix1[p1].R-pix2[p2].R)*(pix1[p1].R-pix2[p2].R)+
      (pix1[p1].G-pix2[p2].G)*(pix1[p1].G-pix2[p2].G)+
      (pix1[p1].B-pix2[p2].B)*(pix1[p1].B-pix2[p2].B));//*xw[x]*yw;

//   i1=pix1[p1].R*pix1[p1].R+pix1[p1].G*pix1[p1].G+pix1[p1].B*pix1[p1].B;
//   i2=pix2[p2].R*pix2[p2].R+pix2[p2].G*pix2[p2].G+pix2[p2].B*pix2[p2].B;
//  i1=sqrt(i1);
//   i2=sqrt(i2);
//   e=(i1-i2)*(i1-i2);   
   


   err+=e;		//we square it again, theoretically questionable
//   c+=xw[x]*yw;
  }
 }
// err=err/c;
 return err;
}


//coarse improvement
double improve_match_c(IMG *img1,IMG *img2,int x1,int y1,double *x2,double *y2,int dx,int dy) {
 double a,bm;
 signed int x,y,bx=0,by=0;
 *x2=rint(*x2);
 *y2=rint(*y2);
 
 bm=1e43;
 for(y=-SEARCH_SIZE;y<=SEARCH_SIZE;y++)
  for(x=-SEARCH_SIZE;x<=SEARCH_SIZE;x++) {
  a=calc_match_c(img1,img2,x1,y1,*x2+x,*y2+y,dx,dy)+(x*x+y*y)/10000.0;
//  printf("a: %f %d %d\n",a,x2+x,y2+y);
  if (a<bm) {
   bm=a;
   bx=x;
   by=y;
  }
 } 

 *x2+=bx;
 *y2+=by;

 printf("bm: %f %d %d\n",bm,bx,by);
 return bm;
}




//fine match calculation, oversample and use nearest neighbors (for speed, the ewa version takes 1.5s on my system, pretty useless)
double calc_match_f(IMG *img1,IMG *img2,double x1,double y1,double x2,double y2,int dx,int dy,double Res) {
 int sx1,sx2,xx1,yy1,xx2,yy2;
 unsigned char R1,R2,G1,G2,B1,B2;
 int n;
 double err,e,x,y;
 pixt *pix1,*pix2; 


 x1+=dx/2.0;
 y1+=dx/2.0;
 x2+=dx/2.0;
 y2+=dx/2.0;
 


 pix1=img1->pix;
 pix2=img2->pix;
 sx1=img1->sx;
 sx2=img2->sx;

 err=0;
 n=0;
 for(y=-dy/2.0/Res;y<=dy/2.0/Res;y++) {
  yy1=y1+y*Res;
  yy2=y2+y*Res;
  if (yy1<0) continue;	
  if (yy2<0) continue;	
  if (yy1>=img1->sy) continue;
  if (yy2>=img2->sy) continue; 

  
  for(x=-dx/2.0/Res;x<=dx/2.0/Res;x++) {
   xx1=x1+x*Res;
   xx2=x2+x*Res;   
    
   if (xx1<0) continue;
   if (xx2<0) continue;
   if (xx1>=sx1) continue;
   if (xx2>=sx2) continue;

   R1=pix1[yy1*img1->sx+xx1].R;   
   G1=pix1[yy1*img1->sx+xx1].G;   
   B1=pix1[yy1*img1->sx+xx1].B;   

   R2=pix2[yy2*img2->sx+xx2].R;   
   G2=pix2[yy2*img2->sx+xx2].G;   
   B2=pix2[yy2*img2->sx+xx2].B;   


   e=((R1-R2)*(R1-R2)+(G1-G2)*(G1-G2)+(B1-B2)*(B1-B2));

   n++;
   err+=e;	
  }
 }

 printf("n: %d\n",n);
 return err/n;
}



double improve_match_f(IMG *img1,IMG *img2,int x1,int y1,double *x2,double *y2,int dx,int dy) {
 double a,bm,b,c;
 double x,y,bx=0,by=0;

 
 b=0.5;
 for(c=0;c<3;c++) {
  bm=1e43;
  for(y=-1;y<=1;y++)
  for(x=-1;x<=1;x++) {
   a=calc_match_f(img1,img2,x1,y1,*x2+x*b,*y2+y*b,dx,dy,b)+(x*x+y*y)/1000000.0;
   printf("x,y,a: %f %f %f\n",x,y,a);
   if (a<bm) {
    bm=a;
    bx=x*b;
    by=y*b;
   }
  } 
  b=b/2.0;
  *x2+=bx;
  *y2+=by; 
  bx=0;
  by=0;
 }  
 
 
 printf("bm2: %f %f %f\n",*x2,*y2,bm);
 return bm;
}



extern double ewa_W[4096];
extern double merge_L[4096];


//ewa match calculation
double calc_match_ewa(IMG *img1,IMG *img2,double x1,double y1,double x2,double y2,int dx,int dy) {
 int sx1,sx2;
 double R1,R2,G1,G2,B1,B2,Rg,Gg,Bg;
// double i1,i2;
 double err,c,e,x,y;
 double X1,X2,Y1,Y2;
 pixt *pix1,*pix2; 
 int n;

 x1+=dx/2.0;
 y1+=dx/2.0;
 x2+=dx/2.0;
 y2+=dx/2.0;
 

 Rg=img1->Gr/img2->Gr;
 Gg=img1->Gg/img2->Gg; 
 Bg=img1->Gb/img2->Gb; 

 mapc(img1,x1,y1,&X1,&Y1);
 mapc(img2,x2,y2,&X2,&Y2);

 pix1=img1->pix;
 pix2=img2->pix;
 sx1=img1->sx;
 sx2=img2->sx;

 n=0; 
 c=0;
 err=0;
 for(y=-dy/2;y<=dy/2;y++) {
/*  if (y1+y<0) continue;	//we should somehow check this, but this isn't how, is it?
  if (y2+y<0) continue;	
  if (y1+y>=img1->sy) continue;
  if (y2+y>=img2->sy) continue;  */

  
  for(x=-dx/2;x<=dx/2;x++) {
/*   if (x1+x<0) continue;
   if (x2+x<0) continue;
   if (x1+x>=sx1) continue;
   if (x2+x>=sx2) continue;*/
   
   ewa_pixel(img1,X1+x,Y1+y,&R1,&G1,&B1,ewa_W); //mapping twice... (yeah, should optimize this)
   ewa_pixel(img2,X2+x,Y2+y,&R2,&G2,&B2,ewa_W);   
   R1*=Rg;
   G1*=Gg;
   B1*=Bg;

   e=((R1-R2)*(R1-R2)+(G1-G2)*(G1-G2)+(B1-B2)*(B1-B2));


   err+=e;	
   n++;
  }
 }

 return err/n;
}



//we could speed this up almost a factor of 2, if we store the ewa of the reference image
void improve_match_ewa(IMG *img1,IMG *img2,int x1,int y1,double *x2,double *y2,int dx,int dy,int t) {
 double a,bm,b,c;
 double x,y,bx=0,by=0;
 int n;
 double X[4],Y[4];
 

  
//#define C (-0.5)
#define C 0
 if (t) { 
  X[0]=img1->dx1+C; Y[0]=img1->dy1+C;
  X[1]=img1->dx2+C; Y[1]=img1->dy2+C;
  X[2]=img1->dx3+C; Y[2]=img1->dy3+C;
  X[3]=img1->dx4+C; Y[3]=img1->dy4+C;
  mapcupd(img1,X,Y);
 
  X[0]=img2->dx1+C; Y[0]=img2->dy1+C;
  X[1]=img2->dx2+C; Y[1]=img2->dy2+C;
  X[2]=img2->dx3+C; Y[2]=img2->dy3+C;
  X[3]=img2->dx4+C; Y[3]=img2->dy4+C;
  mapcupd(img2,X,Y);
  b=2.0;
  n=6;
 }else {

  X[0]=C;          Y[0]=C;
  X[1]=img1->sx+C; Y[1]=C;
  X[2]=C;          Y[2]=img1->sy+C;
  X[3]=img1->sx+C; Y[3]=img1->sy+C;   
  mapcupd(img1,X,Y);
  
 
  X[0]=C;          Y[0]=C;
  X[1]=img2->sx+C; Y[1]=C;
  X[2]=C;          Y[2]=img2->sy+C;
  X[3]=img2->sx+C; Y[3]=img2->sy+C;   
  mapcupd(img2,X,Y); 
  b=1.0;
  n=5;
 }


 

 for(c=0;c<n;c++) {
  bm=1e43;
  for(y=-1;y<=1;y++)
  for(x=-1;x<=1;x++) {
   a=calc_match_ewa(img1,img2,x1,y1,*x2+x*b,*y2+y*b,dx,dy)+(x*x+y*y)/1000000.0;
   if (a<bm) {
    bm=a;
    bx=x*b;
    by=y*b;
   }
  } 
  b=b/2.0;
  *x2+=bx;
  *y2+=by; 
  bx=0;
  by=0;
 }  
 
 
// printf("bm2: %f %f %f\n",*x2,*y2,bm);

 X[0]=img1->dx1*zoommax/zoom-Dxo; Y[0]=img1->dy1*zoommax/zoom-Dyo;
 X[1]=img1->dx2*zoommax/zoom-Dxo; Y[1]=img1->dy2*zoommax/zoom-Dyo;
 X[2]=img1->dx3*zoommax/zoom-Dxo; Y[2]=img1->dy3*zoommax/zoom-Dyo;
 X[3]=img1->dx4*zoommax/zoom-Dxo; Y[3]=img1->dy4*zoommax/zoom-Dyo;   
 mapcupd(img1,X,Y);
 
 X[0]=img2->dx1*zoommax/zoom-Dxo; Y[0]=img2->dy1*zoommax/zoom-Dyo;
 X[1]=img2->dx2*zoommax/zoom-Dxo; Y[1]=img2->dy2*zoommax/zoom-Dyo;
 X[2]=img2->dx3*zoommax/zoom-Dxo; Y[2]=img2->dy3*zoommax/zoom-Dyo;
 X[3]=img2->dx4*zoommax/zoom-Dxo; Y[3]=img2->dy4*zoommax/zoom-Dyo;   
 mapcupd(img2,X,Y);
}






void draw_rlink(linkp *sel) {
 int dx=0,dy=0;
 int sx1,sy1,sx2,sy2,lx=0,ly=0,y,x,x0,y1,y2,llx;
 
 
 if (!(sel->stat&1)) return;
 
   sx1=(sel->sx1+sel->si->Tx)*zoommax/zoom-Dxo;
  sy1=(sel->sy1+sel->si->Ty)*zoommax/zoom-Dyo;
  dx=(sel->dx+sel->di->Tx)*zoommax/zoom-Dxo;
  dy=(sel->dy+sel->di->Ty)*zoommax/zoom-Dyo;

 if (sel->type==1) {

  mline(xdata,Dx,Dy,sx1,sy1,dx,dy,Cgreen.pixel,Cblue.pixel); 
  mline(xdata,Dx,Dy,sx1-cos(sel->angle)*5,sy1-sin(sel->angle)*5,sx1+cos(sel->angle)*15,sy1+sin(sel->angle)*15,Cgreen.pixel,Cblue.pixel); 
  return;  
 } 

 sx2=(sel->sx2+sel->si->Tx)*zoommax/zoom-Dxo;
 sy2=(sel->sy2+sel->si->Ty)*zoommax/zoom-Dyo;
 lx=sx2-sx1;
 ly=sy2-sy1;



 if ((Bpp*lx)&3) llx=lx*Bpp+(4-((lx*Bpp)&3)); else llx=lx*Bpp;
// if ((Bpp*Dx)&3) dxl=Dx*Bpp+(4-((Dx*Bpp)&3)); else dxl=Dx*Bpp;
 
 xdata3=malloc(llx*ly*Bpp);
 //we can't map a small area to a large target right now, so we map it to a small target and copy it
 //(yeah, quite ugly)
 
 if ((sx2>0) && (sx1<Dx) && (sy2>0) && (sy1<Dy)) {
 
  imapx(xdata3,lx,ly,dx+Dxo,dy+Dyo,zoom,sel->di);
  if (sy1<0) {y1=0; } else y1=sy1;
  if (sx1<0) {x0=0; x=lx+sx1; } else {x0=sx1; x=lx;}
  if (x0+x>Dx) x=Dx-x0;
  if (sy2>Dy) y2=Dy; else y2=sy2;
  
  
  if (x>0) for(y=y1;y<y2;y++) memcpy(xdata+y*Dxx+x0*Bpp,xdata3+(y-sy1)*llx+Bpp*(x0-sx1),x*Bpp);
 } 
 if ((dx+lx>0) && (dx<Dx) && (dy+ly>0) && (dy<Dy)) { 
  imapx(xdata3,lx,ly,sx1+Dxo,sy1+Dyo,zoom,sel->si);   	

  if (dy<0) {y1=0; } else y1=dy;
  if (dx<0) {x0=0; x=lx+dx; } else {x0=dx; x=lx;}
  if (x0+x>Dx) x=Dx-x0;
  if (dy+ly>Dy) y2=Dy; else y2=dy+ly;
   
  if (x>0) for(y=y1;y<y2;y++) memcpy(xdata+y*Dxx+x0*Bpp,xdata3+(y-dy)*llx+Bpp*(x0-dx),x*Bpp);
 } 
 free(xdata3);

 mline(xdata,Dx,Dy,sx1,sy1,sx2-1,sy1,Cgreen.pixel,Cblue.pixel);
 mline(xdata,Dx,Dy,sx2-1,sy1,sx2-1,sy2-1,Cgreen.pixel,Cblue.pixel);
 mline(xdata,Dx,Dy,sx1,sy1,sx1,sy2-1,Cgreen.pixel,Cblue.pixel);
 mline(xdata,Dx,Dy,sx1,sy2-1,sx2-1,sy2-1,Cgreen.pixel,Cblue.pixel);

 if (!(sel->stat&2)) return;
 
 mline(xdata,Dx,Dy,dx,dy,dx+lx-1,dy,Cred.pixel,Cgreen.pixel);
 mline(xdata,Dx,Dy,dx,dy,dx,dy+ly-1,Cred.pixel,Cgreen.pixel);
 mline(xdata,Dx,Dy,dx+lx-1,dy,dx+lx-1,dy+ly-1,Cred.pixel,Cgreen.pixel);
 mline(xdata,Dx,Dy,dx,dy+ly-1,dx+lx-1,dy+ly-1,Cred.pixel,Cgreen.pixel);

}




#define LPL 10

void draw_rlinkm(linkp *sel) {
 double sx,sy,dx,dy;

 
 if (!(sel->stat&1)) return;
 if (sel->type==1) { 
 
   mapc(sel->si,sel->sx1,sel->sy1,&sx,&sy);
   mapc(sel->di,sel->dx,sel->dy,&dx,&dy);
   
   mline(xdata,Dx,Dy,sx,sy,dx,dy,Cgreen.pixel,Cblue.pixel);
   mline(xdata,Dx,Dy,sx-cos(sel->angle)*5,sy-sin(sel->angle)*5,sx+cos(sel->angle)*15,sy+sin(sel->angle)*15,Cgreen.pixel,Cblue.pixel);
   
 
 } else {
  if (sel->si->stat&2){
   mapc(sel->si,(sel->sx1+sel->sx2)/2.0,(sel->sy1+sel->sy2)/2.0,&sx,&sy);
   mline(xdata,Dx,Dy,sx-LPL,sy-LPL,sx+LPL,sy+LPL,Cgreen.pixel,Cblue.pixel);
   mline(xdata,Dx,Dy,sx+LPL,sy-LPL,sx-LPL,sy+LPL,Cgreen.pixel,Cblue.pixel);
  }
 
  if (sel->di->stat&2) {
   mapc(sel->di,sel->dx+(sel->sx2-sel->sx1)/2.0,sel->dy+(sel->sy2-sel->sy1)/2.0,&dx,&dy);
  
   mline(xdata,Dx,Dy,dx-LPL,dy,dx+LPL,dy,Cred.pixel,Cgreen.pixel);
   mline(xdata,Dx,Dy,dx,dy-LPL,dx,dy+LPL,Cred.pixel,Cgreen.pixel);
  } 
 } 


}




 
 
IMG * find_cimg(int x,int y){
 int a;
 for(a=0;a<Ot;a++) if ((x<(simg[a]->sx+simg[a]->Tx)*zoommax/zoom-Dxo) && (x>=(simg[a]->Tx)*zoommax/zoom-Dxo) &&
  		       (y<(simg[a]->sy+simg[a]->Ty)*zoommax/zoom-Dyo) && (y>=(simg[a]->Ty)*zoommax/zoom-Dyo)) return simg[a];
 return 0;
}   		       
 


int find_link(IMG *csi,int x,int y,int *d){
 int a,sx1,sx2,sy1,sy2;
 *d=0;
 
 for(a=0;a<MAXLINKS;a++) {
  if ((rlink[a].stat&3)!=3) continue;
  if (rlink[a].si==csi) {
   sx1=(rlink[a].sx1+csi->Tx)*zoommax/zoom-Dxo;
   sy1=(rlink[a].sy1+csi->Ty)*zoommax/zoom-Dyo;

   if (rlink[a].type==1) {
    if ((sx1-5<=x) && (sx1+5>=x)  && (sy1-5<=y) && (sy1+5>=y)) return a;   
   } else { 
    sx2=(rlink[a].sx2+csi->Tx)*zoommax/zoom-Dxo;
    sy2=(rlink[a].sy2+csi->Ty)*zoommax/zoom-Dyo;
    if ((sx1<=x) && (sx2>=x) && (sy1<=y) && (sy2>=y)) return a;
   }
  } 
  if (rlink[a].di==csi) { 
   sx1=(rlink[a].dx+csi->Tx)*zoommax/zoom-Dxo;
   sy1=(rlink[a].dy+csi->Ty)*zoommax/zoom-Dyo;
   if (rlink[a].type==1) {
    if ((sx1-5<=x) && (sx1+5>=x) && (sy1-5<=y) && (sy1+5>=y)) {
     *d=1;
     return a;
    }    
   } else { 
    sx2=(rlink[a].sx2-rlink[a].sx1)*zoommax/zoom;
    sy2=(rlink[a].sy2-rlink[a].sy1)*zoommax/zoom;    
    
    if ((sx1<=x) && (sx1+sx2>=x) && (sy1<=y) && (sy1+sy2>=y)) {
     *d=1;
     return a;
    } 
   } 
  } 
 } 
 return -1; 
}




void update_mapc() {
 int n;
 IMG *cimg;
 double x[4],y[4];
 
 for(n=0;n<Ot;n++) {
  cimg=simg[n];

  x[0]=cimg->dx1*zoommax/zoom-Dxo; y[0]=cimg->dy1*zoommax/zoom-Dyo;
  x[1]=cimg->dx2*zoommax/zoom-Dxo; y[1]=cimg->dy2*zoommax/zoom-Dyo;
  x[2]=cimg->dx3*zoommax/zoom-Dxo; y[2]=cimg->dy3*zoommax/zoom-Dyo;
  x[3]=cimg->dx4*zoommax/zoom-Dxo; y[3]=cimg->dy4*zoommax/zoom-Dyo;   
  mapcupd(cimg,x,y);	//make sure the coordinate mappings are ok anyway, some things require this
  continue;   
 }
}



 
void update_ximg1() {

 int a;
 bzero(xdata,Dxx*Dy);
 for(a=0;a<Ot;a++) {
  imapx(xdata,Dx,Dy,Dxo,Dyo,zoom,simg[a]);
  mline(xdata,Dx,Dy,simg[a]->Tx*zoommax/zoom-Dxo,simg[a]->Ty*zoommax/zoom-Dyo,(simg[a]->Tx+simg[a]->sx)*zoommax/zoom-Dxo,simg[a]->Ty*zoommax/zoom-Dyo,Cwhite.pixel,Cblack.pixel); 
  mline(xdata,Dx,Dy,(simg[a]->Tx+simg[a]->sx)*zoommax/zoom-Dxo,simg[a]->Ty*zoommax/zoom-Dyo,(simg[a]->Tx+simg[a]->sx)*zoommax/zoom-Dxo,(simg[a]->Ty+simg[a]->sy)*zoommax/zoom-Dyo,Cwhite.pixel,Cblack.pixel);
  mline(xdata,Dx,Dy,(simg[a]->Tx+simg[a]->sx)*zoommax/zoom-Dxo,(simg[a]->Ty+simg[a]->sy)*zoommax/zoom-Dyo,simg[a]->Tx*zoommax/zoom-Dxo,(simg[a]->Ty+simg[a]->sy)*zoommax/zoom-Dyo,Cwhite.pixel,Cblack.pixel);
  mline(xdata,Dx,Dy,simg[a]->Tx*zoommax/zoom-Dxo,(simg[a]->Ty+simg[a]->sy)*zoommax/zoom-Dyo,simg[a]->Tx*zoommax/zoom-Dxo,simg[a]->Ty*zoommax/zoom-Dyo,Cwhite.pixel,Cblack.pixel); 
 } 
 for(a=0;a<MAXLINKS;a++) draw_rlink(&rlink[a]);
}



void update_ximg2() {
 unsigned int a,b;
 int n;
 int mr,ml,mt,mb;
 unsigned char q;
 IMG *cimg;
 double x[4],y[4];
 
 a=b=0;
 q=0;
 
 bzero(xdata,Dxx*Dy);

 
 for(n=0;n<Ot;n++) {
  cimg=simg[n];
  cimg->stat&=~2;
  if (cimg->stat&1) continue;

  x[0]=cimg->dx1*zoommax/zoom-Dxo; y[0]=cimg->dy1*zoommax/zoom-Dyo;
  x[1]=cimg->dx2*zoommax/zoom-Dxo; y[1]=cimg->dy2*zoommax/zoom-Dyo;
  x[2]=cimg->dx3*zoommax/zoom-Dxo; y[2]=cimg->dy3*zoommax/zoom-Dyo;
  x[3]=cimg->dx4*zoommax/zoom-Dxo; y[3]=cimg->dy4*zoommax/zoom-Dyo;   

  if (((x[1]<0) && (x[2]<0) && (x[3]<0) && (x[0]<0)) ||
      ((y[1]<0) && (y[2]<0) && (y[3]<0) && (y[0]<0)) ||
      ((x[1]>=Dx) && (x[2]>=Dx) && (x[3]>=Dx) && (x[0]>=Dx)) ||
      ((y[1]>=Dy) && (y[2]>=Dy) && (y[3]>=Dy) && (y[0]>=Dy))) {
      
   
   mapcupd(cimg,x,y);	//make sure the coordinate mappings are ok anyway, some things require this
   continue;   
  }

  cimg->stat|=2;

  imapx_near(xdata,Dx,Dx,Dy,x,y,cimg);
  if (aborting) {
   update_mapc();
   update_edges();
   return;
  } 

  mline(xdata,Dx,Dy,x[0],y[0],x[1],y[1],Cwhite.pixel,Cblack.pixel);
  mline(xdata,Dx,Dy,x[1],y[1],x[2],y[2],Cwhite.pixel,Cblack.pixel);   
  mline(xdata,Dx,Dy,x[2],y[2],x[3],y[3],Cwhite.pixel,Cblack.pixel);
  mline(xdata,Dx,Dy,x[3],y[3],x[0],y[0],Cwhite.pixel,Cblack.pixel);
 }

 update_edges();   
 
 for(n=0;n<Ot;n++) if (simg[n]->stat&2) draw_edges(simg[n]);
 
 
 for(a=0;a<MAXLINKS;a++) draw_rlinkm(&rlink[a]); 
 
 mr=Ml*zoommax/zoom-Dxo;
 ml=Mr*zoommax/zoom-Dxo;
 mt=Mt*zoommax/zoom-Dyo;
 mb=Mb*zoommax/zoom-Dyo;
 
 if ((mode<4) || (mode>7))  {
  mline(xdata,Dx,Dy,mr,mt,ml,mt,Cred.pixel,Cblack.pixel);
  mline(xdata,Dx,Dy,ml,mt,ml,mb,Cred.pixel,Cblack.pixel);
  mline(xdata,Dx,Dy,ml,mb,mr,mb,Cred.pixel,Cblack.pixel);
  mline(xdata,Dx,Dy,mr,mb,mr,mt,Cred.pixel,Cblack.pixel);
 }
 
} 





void update_ximg() {
 if (dmd) update_ximg2(); else update_ximg1();
}










 

int mode,lmode,cur_img,cur_edge;

double lx2,ly2,lx1,ly1;
void display_ximg1(int d,int x,int y) {	//bit0: full redraw  bit1: xy not valid
 static  int x1,x2,y1,y2;
 static double tsx1,tsy1,tsx2,tsy2;
 static double angle;
 static int show=1;
 static int unshow=0;
 double X,Y;
 int tx1,ty1,tx2,ty2,llx;
 XPoint lines[5];
 struct timeval tm;
 static IMG *csi,*cdi;
 static int csl=-1;
 double t;


 if (d&64) show=0;
 if (d&128) show=1;
 
 
 if (d&4096) {
  int e;
  e=d&15;
  printf("e: %d\n",e);
  if (e==5) {
   display_ximg1(512,x,y);
   mode=5;
   return;
  }
  
  if (e<4) {
   if ((mode<3) || (mode>4)) display_ximg1(512,x,y);
   printf("entering direction constraint mode\n");
   switch(e) {
    case 0: angle=0; break;
    case 1: angle=3.14159/2.0; break;
    case 2: angle=3.14159/4.0; break;
    case 3: angle=3.14159*(7.0/4.0); break;
   } 
   printf("angle: %f\n",angle/3.14159*180.0);
   
   if (mode==4) display_ximg1(0,x,y); else mode=3;
  } 
 }
 
 



 if (d&64) {
  if ((mode==0) || (mode==3)) {
   csi=find_cimg(x,y);
   if (csi) { 
   
    csl=find_link(csi,x,y,&d);
    if (csl>=0) {
     int xx1,yy1,fx1,fy1,fx2,fy2;

     x1=(rlink[csl].sx1+rlink[csl].si->Tx)*zoommax/zoom-Dxo;
     y1=(rlink[csl].sy1+rlink[csl].si->Ty)*zoommax/zoom-Dyo;
     x2=(rlink[csl].sx2+rlink[csl].si->Tx)*zoommax/zoom-Dxo;
     y2=(rlink[csl].sy2+rlink[csl].si->Ty)*zoommax/zoom-Dyo;
     lx1=(rlink[csl].dx+rlink[csl].di->Tx)*zoommax/zoom-Dxo;
     ly1=(rlink[csl].dy+rlink[csl].di->Ty)*zoommax/zoom-Dyo;
    
     
     if ((Bpp*(x2-x1))&3) llx=(x2-x1)*Bpp+(4-(((x2-x1)*Bpp)&3)); else llx=(x2-x1)*Bpp;
     
     xdata2=malloc(Bpp*llx*(y2-y1)); 
     img2=XCreateImage(disp,visual,bpp,ZPixmap,0,xdata2,x2-x1,y2-y1,32,llx);
     XInitImage(img2);
     imapx(xdata2,x2-x1,y2-y1,x1+Dxo,y1+Dyo,zoom,rlink[csl].si);  
    
     xdata3=malloc(Bpp*llx*(y2-y1)); 
     img3=XCreateImage(disp,visual,bpp,ZPixmap,0,xdata3,x2-x1,y2-y1,32,llx);
     XInitImage(img3);
     imapx(xdata3,x2-x1,y2-y1,lx1+Dxo,ly1+Dyo,zoom,rlink[csl].di);  
  
  
     if (x1<0) { xx1=-x1; fx1=0; } else { xx1=0; fx1=x1; }
     if (y1<0) { yy1=-y1; fy1=0; } else { yy1=0; fy1=y1; } 
  
     if (x2>=Dx) fx2=Dx-1; else fx2=x2;
     if (y2>=Dy) fy2=Dy-1; else fy2=y2;
     
     if ((fx1<Dx) && (fx2>0) && (fy1<Dy) && (fy2>0)) XPutImage(disp,win1,gc,img2,xx1,yy1,fx1,fy1,fx2-fx1,fy2-fy1);
     
     
     
     if (lx1<0) { xx1=-lx1; fx1=0; } else { xx1=0; fx1=lx1; }
     if (ly1<0) { yy1=-ly1; fy1=0; } else { yy1=0; fy1=ly1; } 
  
     if (lx1+(x2-x1)>=Dx) fx2=Dx-1; else fx2=lx1+(x2-x1);
     if (ly1+(y2-y1)>=Dy) fy2=Dy-1; else fy2=ly1+(y2-y1);
     
     if ((fx1<Dx) && (fx2>0) && (fy1<Dy) && (fy2>0)) XPutImage(disp,win1,gc,img3,xx1,yy1,fx1,fy1,fx2-fx1,fy2-fy1);
     unshow=1;
     return;
    } 
   }  
  } 
 } 
 
   
 if (unshow && d && (!(d&1))) {
  int fx1,fy1,fx2,fy2;
  if (x1<0) fx1=0; else fx1=x1; 
  if (y1<0) fy1=0; else fy1=y1;  
  if (x2>=Dx) fx2=Dx-1; else fx2=x2;
  if (y2>=Dy) fy2=Dy-1; else fy2=y2;
  XPutImage(disp,win1,gc,gimg,fx1,fy1,fx1,fy1,fx2-fx1,fy2-fy1); 

  if (x1<0) fx1=0; else fx1=lx1; 
  if (y1<0) fy1=0; else fy1=ly1; 
  if (lx1+(x2-x1)>=Dx) fx2=Dx-1; else fx2=lx1+(x2-x1);
  if (ly1+(y2-y1)>=Dy) fy2=Dy-1; else fy2=ly1+(y2-y1);
  XPutImage(disp,win1,gc,gimg,fx1,fy1,fx1,fy1,fx2-fx1,fy2-fy1); 
  
  XDestroyImage(img2);
  XDestroyImage(img3);
  unshow=0;
 }


 
 
 
 if (d&1) {
  XPutImage(disp,win1,gc,gimg,0,0,0,0,Dx,Dy);  
 } 
 switch(mode) {
  case 0:

   if (zoommax>zoom) {
    x&=~(zoommax/zoom-1);
    y&=~(zoommax/zoom-1);
   }

   if (d&4) {

    csi=find_cimg(x,y);
    if (!csi) break;
    csl=find_link(csi,x,y,&d);
rl1:    
    if ((csl>=0) && (d)) {
     if (rlink[csl].type==1) {
      int A;
  
      tsx1=rlink[csl].sx1;	
      tsy1=rlink[csl].sy1;
      csi=rlink[csl].si;
      lx1=(tsx1+csi->Tx)*zoommax/zoom-Dxo;
      ly1=(tsy1+csi->Ty)*zoommax/zoom-Dyo;    
      angle=rlink[csl].angle;
      lx2=x;
      ly2=y;
      mode=4;
      A=angle*180.0/3.14159+0.5;
      
      
      switch(A) {
       case 0:
        setname("horizontal constraint");
        break; 
       case 90:
        setname("vertical constraint");
        break;     
    
       case 45:
        setname("45deg constraint");
        break; 

       case 315:
        setname("315deg constraint");
        break;
     
       default:
        setname("direction constraint");
        break;
      } 
      
      
      rlink[csl].stat=4;
      update_ximg1();
      XPutImage(disp,win1,gc,gimg,0,0,0,0,Dx,Dy);      //well, we could just update a smaller region, should fix this someday
     
      break;
     }
    
     mode=2;
     setname("point constraint (target)");
     rlink[csl].stat=4;
     update_ximg1();
     XPutImage(disp,win1,gc,gimg,0,0,0,0,Dx,Dy);      
     d=256;
     csi=rlink[csl].si;
     tsx1=rlink[csl].sx1;	
     tsy1=rlink[csl].sy1;
     tsx2=rlink[csl].sx2;	
     tsy2=rlink[csl].sy2;
     
     disable_cursor();
     goto lc2;
    }
    if (csl==-1) {
     for (d=0;d<MAXLINKS;d++) if ((rlink[d].stat&3)!=3) break;
     if (d==MAXLINKS) break;
     csl=d;
    } else {
     rlink[csl].stat=0;
     update_ximg();    
     XPutImage(disp,win1,gc,gimg,0,0,0,0,Dx,Dy);      
     break;
    } 
    
    
    lx2=x;	
    ly2=y;
    lx1=x;
    ly1=y;
    x1=-1;
    mode++;
    setname("point constraint (source)"); 
   }
   
    
   break;
 
  case 1:
   if (zoommax>zoom) {
    x&=~(zoommax/zoom-1);
    y&=~(zoommax/zoom-1);
   }
    
   if (!(d&1) && (x1!=-1)) {
    XPutImage(disp,win1,gc,gimg,x1,y1,x1,y1,x2-x1,1);   
    XPutImage(disp,win1,gc,gimg,x1,y1,x1,y1,1,y2-y1);   
    XPutImage(disp,win1,gc,gimg,x1,y2-1,x1,y2-1,x2-x1,1);   
    XPutImage(disp,win1,gc,gimg,x2-1,y1,x2-1,y1,1,y2-y1);   
   }
   
   if (d&512) { //abort current operation
    rlink[csl].stat=0;
    mode=0;
    setname("normal");
    csl=-1;
    break;
   }
   
    
   if (x>=(csi->sx+csi->Tx)*zoommax/zoom-Dxo) x=(csi->sx+csi->Tx)*zoommax/zoom-Dxo-1; else 
   if (x<(csi->Tx)*zoommax/zoom-Dxo) x=csi->Tx*zoommax/zoom-Dxo;
    
   if (y>=(csi->sy+csi->Ty)*zoommax/zoom-Dyo) y=(csi->sy+csi->Ty)*zoommax/zoom-Dyo-1; else 
   if (y<(csi->Ty)*zoommax/zoom-Dyo) y=csi->Ty*zoommax/zoom-Dyo;
   
   if (x>lx1+MAXMATCH*zoommax/zoom) x=lx1+MAXMATCH*zoommax/zoom; else if (x<lx1-MAXMATCH*zoommax/zoom) x=lx1-MAXMATCH*zoommax/zoom;
   if (y>ly1+MAXMATCH*zoommax/zoom) y=ly1+MAXMATCH*zoommax/zoom; else if (y<ly1-MAXMATCH*zoommax/zoom) y=ly1-MAXMATCH*zoommax/zoom;
    
   lx2=x;	
   ly2=y;
    
   
   if (lx1<lx2) {
    x1=lx1;
    x2=lx2;
   } else  {
    x2=lx1;
    x1=lx2;
   } 
   if (ly1<ly2) {
    y1=ly1;
    y2=ly2;
   } else  {
    y2=ly1;
    y1=ly2;
   } 
   tx1=x1;
   ty1=y1;
   tx2=x2;
   ty2=y2;
   

   if (d&4) { 
    tsx1=(tx1+Dxo)*zoom/zoommax-csi->Tx;	
    tsy1=(ty1+Dyo)*zoom/zoommax-csi->Ty;
    tsx2=(tx2+Dxo)*zoom/zoommax-csi->Tx;	
    tsy2=(ty2+Dyo)*zoom/zoommax-csi->Ty;    
    if (tsx2-tsx1<5) break;
    if (tsy2-tsy1<5) break;
   

    disable_cursor();
   
    
//    rlink[csl].stat|=1;
//    draw_rlink(&rlink[csl]);
    
//    XPutImage(disp,win1,gc,gimg,0,0,0,0,Dx,Dy);  

    mode++;
    setname("point constraint (target)");
    
    if ((Bpp*(tx2-tx1))&3) llx=(tx2-tx1)*Bpp+(4-(((tx2-tx1)*Bpp)&3)); else llx=(tx2-tx1)*Bpp;    
    xdata2=malloc(Bpp*llx*(ty2-ty1)); 
    img2=XCreateImage(disp,visual,bpp,ZPixmap,0,xdata2,tx2-tx1,ty2-ty1,32,llx);
    XInitImage(img2);



    lx1=tx1;
    lx2=tx2;
    ly1=ty1;
    ly2=ty2;
    
    
    imapx(xdata2,tx2-tx1,ty2-ty1,Dxo+tx1,Dyo+ty1,zoom,csi);
  
    x1=-1;
    break;
    
   } 
   

   if ((x2>=0) && (y2>=0) && (x1<Dx) && (y1<Dy) && (x1!=x2) && (y1!=y2)) {
    lines[0].x=x1; lines[0].y=y1;    
    lines[1].x=x2-1; lines[1].y=y1;    
    lines[2].x=x2-1; lines[2].y=y2-1;    
    lines[3].x=x1; lines[3].y=y2-1;    
    lines[4].x=x1; lines[4].y=y1;
  
    XSetForeground(disp, gc, Cgreen.pixel);
    XSetBackground(disp, gc, Cred.pixel);	
    XDrawLines(disp,win1,gc,lines,5,CoordModeOrigin);
    
    if (x1<0) x1=0;
    if (y1<0) y1=0;
    if (x2>=Dx) x2=Dx-1; 
    if (y2>=Dy) y2=Dy-1; 
   } else x1=-1; 
   


   break;
   
  case 2:

   if (d&512) { //abort current operation
    if (rlink[csl].stat&4) rlink[csl].stat=3; else rlink[csl].stat=0;
    mode=0;
    setname("normal");
    draw_rlink(&rlink[csl]);
    csl=-1;
    

    XPutImage(disp,win1,gc,gimg,0,0,0,0,Dx,Dy);    
    
    enable_cursor();
    break;
   }



   if ((zoommax>zoom) && (!Integers)){
    x&=~(zoommax/zoom-1);
    y&=~(zoommax/zoom-1);
   }

   if (!(d&1) && (x1!=-1)) XPutImage(disp,win1,gc,gimg,x1,y1,x1,y1,x2,y2);  



   if (d&256) {
    XDestroyImage(img2);
lc2:   
    lx1=(tsx1+csi->Tx)*zoommax/zoom-Dxo;
    lx2=(tsx2+csi->Tx)*zoommax/zoom-Dxo;
    ly1=(tsy1+csi->Ty)*zoommax/zoom-Dyo;
    ly2=(tsy2+csi->Ty)*zoommax/zoom-Dyo;
    
    
    if ((Bpp*(int)(lx2-lx1))&3) llx=(int)(lx2-lx1)*Bpp+(4-(((int)(lx2-lx1)*Bpp)&3)); else llx=(int)(lx2-lx1)*Bpp;
    xdata2=malloc(Bpp*llx*(ly2-ly1)); 
    img2=XCreateImage(disp,visual,bpp,ZPixmap,0,xdata2,lx2-lx1,ly2-ly1,32,llx);
    XInitImage(img2);

    imapx(xdata2,lx2-lx1,ly2-ly1,lx1+Dxo,ly1+Dyo,zoom,csi);  
   } 




   
   
   //maybe we should give it some border?
   if (d&4) {
    IMG * a;
    cdi=find_cimg(x,y);
    a=find_cimg(x+(lx2-lx1),y+(ly2-ly1));
    
    
    if ((!cdi) || (cdi!=a) || (cdi==csi)) break;


    X=(double)(x+Dxo)*zoom/zoommax-cdi->Tx;
    Y=(double)(y+Dyo)*zoom/zoommax-cdi->Ty;
    if (improve) {
     gettimeofday(&tm,NULL);
     t=-tm.tv_sec-(float)tm.tv_usec/1000000;

     improve_match_c(csi,cdi,tsx1,tsy1,&X,&Y,tsx2-tsx1,tsy2-tsy1); 
     
     gettimeofday(&tm,NULL);
     t+=tm.tv_sec+(float)tm.tv_usec/1000000;
     printf("\nt1: %f\n",t);

     
     gettimeofday(&tm,NULL);
     t=-tm.tv_sec-(float)tm.tv_usec/1000000;
     improve_match_ewa(csi,cdi,tsx1,tsy1,&X,&Y,tsx2-tsx1,tsy2-tsy1,0);      
     gettimeofday(&tm,NULL);
     t+=tm.tv_sec+(float)tm.tv_usec/1000000;
     printf("\nt2: %f\n",t);
    } 


    rlink[csl].si=csi;
    rlink[csl].sx1=tsx1;	
    rlink[csl].sy1=tsy1;
    rlink[csl].sx2=tsx2;	
    rlink[csl].sy2=tsy2;


    rlink[csl].dx=X;
    rlink[csl].dy=Y;
    rlink[csl].stat=3;
    rlink[csl].type=0;
    rlink[csl].di=cdi;
    printf("X: %f Y: %f\n",X,Y);
    
    draw_rlink(&rlink[csl]);
    


    x1=(X+cdi->Tx)*zoommax/zoom-Dxo-1; 
    y1=(Y+cdi->Ty)*zoommax/zoom-Dyo-1; 
    
    x2=x1+1+(lx2-lx1); y2=y1+1+(ly2-ly1);
    
    if (x1<0) x1=0;
    if (y1<0) y1=0;
    if (x2>=Dx) x2=Dx-1; 
    if (y2>=Dy) y2=Dy-1; 
    XPutImage(disp,win1,gc,gimg,x1,y1,x1,y1,x2-x1,y2-y1);    
    
    if (lx1<0) lx1=0;
    if (ly1<0) ly1=0;
    if (lx2>=Dx) lx2=Dx-1;
    if (ly2>=Dy) ly2=Dy-1;
    if ((lx2>=0) && (ly2>=0) && (lx1<Dx) && (ly1<Dy) && (lx1!=lx2) && (ly1!=ly2)) XPutImage(disp,win1,gc,gimg,lx1,ly1,lx1,ly1,lx2-lx1+1,ly2-ly1+1);
    
    //XPutImage(disp,win1,gc,gimg,0,0,0,0,Dx,Dy);  
    XDestroyImage(img2);
    mode=0;
    setname("normal");
    csl=-1;
    enable_cursor();
    break;
   }
   
   
   x1=lx1;
   x2=lx2;
   y1=ly1;
   y2=ly2;

   
   if ((x2>=0) && (y2>=0) && (x1<Dx) && (y1<Dy) && (x1!=x2) && (y1!=y2)) {
    lines[0].x=x1; lines[0].y=y1;    
    lines[1].x=x2-1; lines[1].y=y1;    
    lines[2].x=x2-1; lines[2].y=y2-1;    
    lines[3].x=x1; lines[3].y=y2-1;    
    lines[4].x=x1; lines[4].y=y1;
  
    XSetForeground(disp, gc, Cgreen.pixel);
    XSetBackground(disp, gc, Cred.pixel);	
    XDrawLines(disp,win1,gc,lines,5,CoordModeOrigin);
   }
   
   
   if (x<Dx-(lx2-lx1)) x1=x; else x1=Dx-(lx2-lx1)-1; 
   if (y<Dy-(ly2-ly1)) y1=y; else y1=Dy-(ly2-ly1)-1; 

   if (x1<0) x1=0;
   if (y1<0) y1=0;

   if (x1+(lx2-lx1)>Dx) x2=Dx-x1; else x2=lx2-lx1;
   if (y1+(ly2-ly1)>Dy) y2=Dy-y1; else y2=ly2-ly1;
   
  
   if (show) XPutImage(disp,win1,gc,img2,0,0,x1,y1,x2,y2);  
   
   break;
   
  case 3: 
  
   if (d&512) {
    csl=-1;
    mode=0;
    setname("normal");
    printf("returning to normal mode\n");
    break;
   }
    
   if (d&4) {
    csi=find_cimg(x,y);
    if (!csi) break;
    csl=find_link(csi,x,y,&d);
    if (csl>=0) goto rl1; 
    for (d=0;d<MAXLINKS;d++) if ((rlink[d].stat&3)!=3) break;
    if (d==MAXLINKS) break;
    csl=d;
    
    lx1=lx2=x;
    ly1=ly2=y;
    tsx1=(double)(x+Dxo)*zoom/zoommax-csi->Tx;	
    tsy1=(double)(y+Dyo)*zoom/zoommax-csi->Ty;
     

    mode=4;
   }
   break;
  
  case 4:



   if (d&512) {
    if (rlink[csl].stat&4) rlink[csl].stat=3; else rlink[csl].stat=0;
    mode=3;
    draw_rlink(&rlink[csl]);
    csl=-1;
    XPutImage(disp,win1,gc,gimg,0,0,0,0,Dx,Dy);
    break;
   }




   if (d&1024) {
    rlink[csl].stat=0;
    mode=3;
    XPutImage(disp,win1,gc,gimg,0,0,0,0,Dx,Dy);
    break;   
   }


   if (!(d&1)) {
    if (lx1<lx2) { x1=lx1; x2=lx2; } else { x1=lx2; x2=lx1; }
    if (ly1<ly2) { y1=ly1; y2=ly2; } else { y1=ly2; y2=ly1; }
   

    if (x1<0) x1=0;
    if (y1<0) y1=0;
    if (x2>=Dx) x2=Dx-1;
    if (y2>=Dy) y2=Dy-1;

    if ((x1<=x2) && (y1<=y2)) XPutImage(disp,win1,gc,gimg,x1,y1,x1,y1,x2-x1+1,y2-y1+1);   
   }
   
   
   lx2=x;
   ly2=y;
   
   
   if (d&256) {
    lx1=(tsx1+csi->Tx)*zoommax/zoom-Dxo;
    ly1=(tsy1+csi->Ty)*zoommax/zoom-Dyo;    
   }
   

   
   x1=lx1;
   y1=ly1;
   x2=lx2;
   y2=ly2;

   XSetForeground(disp, gc, Cgreen.pixel);
   XSetBackground(disp, gc, Cred.pixel);
   XDrawLine(disp,win1,gc,lx1,ly1,lx2,ly2);
   XDrawLine(disp,win1,gc,lx1-cos(angle)*5,ly1-sin(angle)*5,lx1+cos(angle)*15,ly1+sin(angle)*15);



   
   
   if (d&4) {
    cdi=find_cimg(x,y);
    if (!cdi) break;
    
    X=(double)(x+Dxo)*zoom/zoommax-cdi->Tx;
    Y=(double)(y+Dyo)*zoom/zoommax-cdi->Ty;

    rlink[csl].si=csi;
    rlink[csl].sx1=tsx1;	
    rlink[csl].sy1=tsy1;
    rlink[csl].angle=angle;	

    rlink[csl].dx=X;
    rlink[csl].dy=Y;
    rlink[csl].stat=3;
    rlink[csl].type=1;
    rlink[csl].di=cdi;

    printf("X: %f Y: %f\n",X,Y);
    
    draw_rlink(&rlink[csl]);
    XPutImage(disp,win1,gc,gimg,0,0,0,0,Dx,Dy);  
    mode=3;
    csl=-1;
   }
   
   break;
   
  case 5:
   if (d&512) {
    csl=-1;
    mode=0;
    setname("normal");
    printf("returning to normal mode\n");
    break;
   }
   
   if (zoommax>zoom) {
    x&=~(zoommax/zoom-1);
    y&=~(zoommax/zoom-1);
   }
    
   if (d&4) {
    csi=find_cimg(x,y);
    if (!csi) break;
    
    lx1=lx2=x;
    ly1=ly2=y;
    tsx1=(double)(x+Dxo)*zoom/zoommax-csi->Tx;	
    tsy1=(double)(y+Dyo)*zoom/zoommax-csi->Ty;
    mode=6;
   }
   break;  




  case 6:
   if (zoommax>zoom) {
    x&=~(zoommax/zoom-1);
    y&=~(zoommax/zoom-1);
   }
    
   if (!(d&1) && (x1!=-1)) {
    XPutImage(disp,win1,gc,gimg,x1,y1,x1,y1,x2-x1,1);   
    XPutImage(disp,win1,gc,gimg,x1,y1,x1,y1,1,y2-y1);   
    XPutImage(disp,win1,gc,gimg,x1,y2-1,x1,y2-1,x2-x1,1);   
    XPutImage(disp,win1,gc,gimg,x2-1,y1,x2-1,y1,1,y2-y1);   
   }
   
   if (d&512) { 
    mode=5;
    break;
   }
   
    
   if (x>=(csi->sx+csi->Tx)*zoommax/zoom-Dxo) x=(csi->sx+csi->Tx)*zoommax/zoom-Dxo-1; else 
   if (x<(csi->Tx)*zoommax/zoom-Dxo) x=csi->Tx*zoommax/zoom-Dxo;
    
   if (y>=(csi->sy+csi->Ty)*zoommax/zoom-Dyo) y=(csi->sy+csi->Ty)*zoommax/zoom-Dyo-1; else 
   if (y<(csi->Ty)*zoommax/zoom-Dyo) y=csi->Ty*zoommax/zoom-Dyo;
   
//   if (x>lx1+MAXMATCH*zoommax/zoom) x=lx1+MAXMATCH*zoommax/zoom; else if (x<lx1-MAXMATCH*zoommax/zoom) x=lx1-MAXMATCH*zoommax/zoom;
//   if (y>ly1+MAXMATCH*zoommax/zoom) y=ly1+MAXMATCH*zoommax/zoom; else if (y<ly1-MAXMATCH*zoommax/zoom) y=ly1-MAXMATCH*zoommax/zoom;
    
   lx2=x;	
   ly2=y;
    
   
   if (lx1<lx2) {
    x1=lx1;
    x2=lx2;
   } else  {
    x2=lx1;
    x1=lx2;
   } 
   if (ly1<ly2) {
    y1=ly1;
    y2=ly2;
   } else  {
    y2=ly1;
    y1=ly2;
   } 
   tx1=x1;
   ty1=y1;
   tx2=x2;
   ty2=y2;
   
   
   
   if (d&4) { 
    double R=0,G=0,B=0,n=0;
    tsx1=(x1+Dxo)*zoom/zoommax-csi->Tx;	
    tsy1=(y1+Dyo)*zoom/zoommax-csi->Ty;
    tsx2=(x2+Dxo)*zoom/zoommax-csi->Tx;	
    tsy2=(y2+Dyo)*zoom/zoommax-csi->Ty;    
    if (tsx2-tsx1<2) break;
    if (tsy2-tsy1<2) break;

    
    for (y=tsy1;y<tsy2;y++) 
     for(x=tsx1;x<tsx2;x++) {
     R+=csi->pix[csi->sx*y+x].R; 
     G+=csi->pix[csi->sx*y+x].G;
     B+=csi->pix[csi->sx*y+x].B;
     
     n+=1;
    }
    
   
    if (R>0) {
     csi->Gr=1/((1/csi->Gr*csi->Grn+R/RCOL_r)/(csi->Grn+n));
     csi->Grn+=n;
     printf("Gr: %f\n",csi->Gr);
    }
    
    if (G>0) {
     csi->Gg=1/((1/csi->Gg*csi->Ggn+G/RCOL_g)/(csi->Ggn+n));
     csi->Ggn+=n;
     printf("Gg: %f\n",csi->Gg);
    }
    
    if (B>0) {
     csi->Gb=1/((1/csi->Gb*csi->Gbn+B/RCOL_b)/(csi->Gbn+n));
     csi->Gbn+=n;
     printf("Gb: %f\n",csi->Gb);
    }
     
   
    
   
    csl=-1;  
    x1=-1;
    mode=5;
    break;
   } 

   if ((x2>=0) && (y2>=0) && (x1<Dx) && (y1<Dy) && (x1!=x2) && (y1!=y2)) {
    lines[0].x=x1; lines[0].y=y1;    
    lines[1].x=x2-1; lines[1].y=y1;    
    lines[2].x=x2-1; lines[2].y=y2-1;    
    lines[3].x=x1; lines[3].y=y2-1;    
    lines[4].x=x1; lines[4].y=y1;
  
    XSetForeground(disp, gc, Cwhite.pixel);
    XSetBackground(disp, gc, Cblue.pixel);	
    XDrawLines(disp,win1,gc,lines,5,CoordModeOrigin);
    
    if (x1<0) x1=0;
    if (y1<0) y1=0;
    if (x2>=Dx) x2=Dx-1; 
    if (y2>=Dy) y2=Dy-1; 
   } else x1=-1; 
   

   
   break;
   
   
   
   
   
   
   

 }
 XFlush(disp);	//we do not use XNextEvent in a normal fasion...
}







void display_ximg2(int d,int x,int y) {	//bit0: full redraw  bit1: xy not valid
 static edget *edge,*edge2,*edge3;
 static int lx,ly;
 static IMG *imgn;
 double X,Y;
 char *xv_args[3]={"xv","-",0};
 int x1,y1,x2,y2;
 int j,fd[2];
 
 if (d&64) {
  IMG *timg;
  X=(x+Dxo)*zoom/zoommax; Y=(y+Dyo)*zoom/zoommax;
  j=find_cimg2(X,Y);
  if (j<0) return;
  timg=simg[j];
  for(x1=j;x1<Ot;x1++) simg[x1]=simg[x1+1];
  simg[Ot-1]=timg;
  update_ximg2();
  XPutImage(disp,win1,gc,gimg,0,0,0,0,Dx,Dy);  
  return;
 }
 
 
 
 
 if (d&1) {
  XPutImage(disp,win1,gc,gimg,0,0,0,0,Dx,Dy);  
 } 
 
 
 if (d&2048) {
  if (mode) display_ximg2(512,x,y);
  
  mode=3;
  printf("entering crop region selection mode\n");
  return;
 } 
 
 
 if ((d&(4096+15))==(4096+4)) { //create preview
  display_ximg2(512,x,y);
  mode=8;
  printf("entering preview selection mode\n");
  return;
 }
 
 
 
 switch(mode) {
  case 0:
   if (d&4) {
    edge=edge_find(&imgn,&j,x,y);
    if (!edge) break;
    if (j) {
     mode=1;
     setname("margin adjust");
     edge->stat|=1;
     if (edge->prev) edge2=edge->prev; else {
      edge2=edge;
      while(edge2->next) edge2=edge2->next;
     }
     if (edge->next) edge3=edge->next; else  edge3=imgn->edge;
     edge2->stat|=1;
     
    } else {
     mode=2;
     setname("margin adjust (new corner)");
     edge->stat|=1;
     edge2=edge;
     if (edge->next) edge3=edge->next; else  edge3=imgn->edge;
    }
    
    lx1=edge2->X;  ly1=edge2->Y;
    lx2=edge3->X;  ly2=edge3->Y;    


    update_ximg2();
    XPutImage(disp,win1,gc,gimg,0,0,0,0,Dx,Dy);      


    X=(x+Dxo)*zoom/zoommax; Y=(y+Dyo)*zoom/zoommax;    
    adjust_xy(imgn,&X,&Y);
    x=X*zoommax/zoom-Dxo; y=Y*zoommax/zoom-Dyo;
    
    lx=x;
    ly=y;


    XSetForeground(disp, gc, Cgreen.pixel);
    XSetBackground(disp, gc, Cred.pixel);	
    XDrawLine(disp,win1,gc,lx1,ly1,x,y);
    XDrawLine(disp,win1,gc,lx2,ly2,x,y);
   } 
   
   break;
     
  case 1:
  
   if (d&1024) {
    if (imgn->edgen==3) break;
    edge_del(imgn,edge);
    edge2->stat&=~1;
    update_ximg2();
    XPutImage(disp,win1,gc,gimg,0,0,0,0,Dx,Dy);      
    mode=0;
    setname("normal");
    break;
   }  
   
   
  case 2:
  

  
   if (d&512) {	//abort current operation
    edge2->stat&=~1;
    if (mode==1) edge->stat&=~1;
    mode=0;
    setname("normal");
    update_ximg2();
    XPutImage(disp,win1,gc,gimg,0,0,0,0,Dx,Dy);      
    break;
   }
  
  
   if (d&256) {
    lx1=edge2->X;  ly1=edge2->Y;
    lx2=edge3->X;  ly2=edge3->Y;    
    
    X=(x+Dxo)*zoom/zoommax; Y=(y+Dyo)*zoom/zoommax;    
    adjust_xy(imgn,&X,&Y);
    x=X*zoommax/zoom-Dxo;  y=Y*zoommax/zoom-Dyo; 

    lx=x;
    ly=y; 
   }
  
  
   if (!(d&1)) {
//yeah, this is slow, but experiments with only erasing the line was not very successfull
//atleast we only update the area in which the lines are

    x1=x2=lx;
    y1=y2=ly;
    
    if (lx1<x1) x1=lx1;
    if (ly1<y1) y1=ly1;
    if (lx2<x1) x1=lx2;
    if (ly2<y1) y1=ly2;
    if (lx1>x2) x2=lx1;
    if (ly1>y2) y2=ly1;
    if (lx2>x2) x2=lx2;
    if (ly2>y2) y2=ly2;
    if (x1<0) x1=0;
    if (y1<0) y1=0;
    if (x2>=Dx) x2=Dx-1;
    if (y2>=Dy) y2=Dy-1;

    if ((x1<x2) && (y1<y2)) XPutImage(disp,win1,gc,gimg,x1,y1,x1,y1,x2-x1+1,y2-y1+1);
   
   } 
   X=(x+Dxo)*zoom/zoommax; Y=(y+Dyo)*zoom/zoommax;
   adjust_xy(imgn,&X,&Y);
   x=X*zoommax/zoom-Dxo; y=Y*zoommax/zoom-Dyo;

   if (d&4) {
    edget *tedge,*tedge2;
    double f,g1,g2;
    int a;
    //check if we intersect some other edge
    tedge=imgn->edge;
    a=0;
    mapcrs(imgn,x,y,&X,&Y);
    
    
    
    while(tedge) {
     tedge->t1=(tedge->x-X)*(edge2->y-Y)-(tedge->y-Y)*(edge2->x-X);
     tedge->t2=(tedge->x-X)*(edge3->y-Y)-(tedge->y-Y)*(edge3->x-X);
     tedge=tedge->next;
    }
    
     a=0;
    tedge=imgn->edge;    
    
    while(tedge) {
     if (tedge->next) tedge2=tedge->next; else tedge2=imgn->edge;
     if ((tedge!=edge2) && (tedge2!=edge3)) {
      f=(tedge2->x-tedge->x)*(Y-tedge->y)-(tedge2->y-tedge->y)*(X-tedge->x);
      g1=(tedge2->x-tedge->x)*(edge2->y-tedge->y)-(tedge2->y-tedge->y)*(edge2->x-tedge->x);
      g2=(tedge2->x-tedge->x)*(edge3->y-tedge->y)-(tedge2->y-tedge->y)*(edge3->x-tedge->x);
      
      
      if ((((tedge->t1>0) && (tedge2->t1<0)) || ((tedge->t1<0) && (tedge2->t1>0))) &&
          (((f>0) && (g1<0)) || ((f<0)  && (g1>0)))) a=1;
          
      if ((((tedge->t2>0) && (tedge2->t2<0)) || ((tedge->t2<0) && (tedge2->t2>0))) &&
          (((f>0) && (g2<0)) || ((f<0)  && (g2>0)))) a=1;
          
     } 
     
     tedge=tedge->next;
    }
   
    if (a) break;
   

    if (mode==2) edge=edge_add(imgn,edge2,X,Y); else {
     edge->x=X;
     edge->y=Y;
     edge->X=x;
     edge->Y=y;
     edge->stat&=~1;
    }
    
    edge->X=x;
    edge->Y=y;
    
    edge2->stat&=~1;
    edge3->stat&=~1;
    mode=0;
    setname("normal");
    update_ximg2();
    XPutImage(disp,win1,gc,gimg,0,0,0,0,Dx,Dy);      
    break;
   } 

   lx=x;
   ly=y;

   XSetForeground(disp, gc, Cgreen.pixel);
   XSetBackground(disp, gc, Cred.pixel);	
   XDrawLine(disp,win1,gc,lx1,ly1,x,y);
   XDrawLine(disp,win1,gc,lx2,ly2,x,y);
   
   break;
   
   
  case 3:
  
   if (d&512) {	//abort current operation
    printf("returning to normal mode\n");
    mode=0;
    setname("normal");
    return;
   }
  
   if (d&4) { 

   
    X=(x+Dxo)*zoom/zoommax; 
    Y=(y+Dyo)*zoom/zoommax;
   
    if ((X>=Ml) && (X<Mr)) {
     if ((Mt-Y<10) && (Mt-Y>=0)) mode=4; else if ((Y-Mb<10) && (Y-Mb>=0)) mode=6; else
      if (Y-Mt<Mb-Y) {if (Y-Mt<10) mode=4; } else if (Mb-Y<10) mode=6;
    } 
   
   
    if ((Y>=Mt) && (Y<Mb)) {
     if ((Ml-X<10) && (Ml-X>=0)) mode=5; else if ((X-Mr<10) && (X-Mr>=0)) mode=7; else
     if (X-Ml<Mr-X) { if (X-Ml<10) mode=5; } else  if (Mr-X<10) mode=7;
    } 
    
    update_ximg();
    display_ximg2(1,x,y);
    
   }
/*   

    x1=Ml*zoommax/zoom-Dxo;
    x2=Mr*zoommax/zoom-Dxo;
    y1=Mt*zoommax/zoom-Dyo;
    y2=Mb*zoommax/zoom-Dyo;
   if (d&1) {
    XSetForeground(disp, gc, Cblack.pixel);
    XSetBackground(disp, gc, Cred.pixel);	
    
    XDrawLine(disp,win1,gc,x1,y1,x2,y1);   
    XDrawLine(disp,win1,gc,x2,y1,x2,y2);   
    XDrawLine(disp,win1,gc,x2,y2,x1,y2);   
    XDrawLine(disp,win1,gc,x1,y2,x1,y1);   
   }
   
   
   switch (mode) {
    case 4:
     ly=y1;
     break;
    case 5:
     lx=x1;
     break;     
    case 6:
     ly=y2;
     break;     
    case 7:
     lx=x2;
     break;     
   }   
   */
  break;
  
  
  case 4:
  case 5:  
  case 6:
  case 7:  
   


   
   if (zoommax>zoom) {
    x&=~(zoommax/zoom-1);
    y&=~(zoommax/zoom-1);
   }


   x1=Ml*zoommax/zoom-Dxo;
   x2=Mr*zoommax/zoom-Dxo;
   y1=Mt*zoommax/zoom-Dyo;
   y2=Mb*zoommax/zoom-Dyo;
   

   switch (mode) {
    case 4:
     if (ly<y2) y1=ly; else y1=y2-1;
     break;
    case 5:
     if (lx<x2) x1=lx; else x1=x2-1;
     break;     
    case 6:
     if (ly>y1) y2=ly; else y2=y1+1;
     break;     
    case 7:
     if (lx>x1) x2=lx; else x2=x1+1;
     break;     
   }   

   if (!(d&1)) {
    if (x1<0) x1=0;
    if (y1<0) y1=0;
    if (x2>=Dx) x2=Dx-1;
    if (y2>=Dy) y2=Dy-1;

    if ((x1<x2) && (y1<y2)) {
    
     XPutImage(disp,win1,gc,gimg,x1,y1,x1,y1,x2-x1+1,1);
     XPutImage(disp,win1,gc,gimg,x1,y1,x1,y1,1,y2-y1+1);
     XPutImage(disp,win1,gc,gimg,x1,y2,x1,y2,x2-x1+1,1);
     XPutImage(disp,win1,gc,gimg,x2,y1,x2,y1,1,y2-y1+1);
     
    }

   }
   
   
   if (d&512) {	//abort current operation
    mode=3;
    update_ximg();
    display_ximg2(1,x,y);
    return;
   }
   
   
   x1=Ml*zoommax/zoom-Dxo;
   x2=Mr*zoommax/zoom-Dxo;
   y1=Mt*zoommax/zoom-Dyo;
   y2=Mb*zoommax/zoom-Dyo;
   
   
   
   lx=x;
   ly=y;


   switch (mode) {
    case 4:
     if (ly<y2) y1=ly; else y1=y2-1;
     break;
    case 5:
     if (lx<x2) x1=lx; else x1=x2-1;
     break;     
    case 6:
     if (ly>y1) y2=ly; else y2=y1+1;
     break;     
    case 7:
     if (lx>x1) x2=lx; else x2=x1+1;
     break;     
   }   

   XSetForeground(disp, gc, Cblack.pixel);
   XSetBackground(disp, gc, Cred.pixel);

   XDrawLine(disp,win1,gc,x1,y1,x2,y1);   
   XDrawLine(disp,win1,gc,x2,y1,x2,y2);   
   XDrawLine(disp,win1,gc,x2,y2,x1,y2);   
   XDrawLine(disp,win1,gc,x1,y2,x1,y1);
   
      
   
   if (d&4) {
    X=(x+Dxo)*zoom/zoommax; 
    Y=(y+Dyo)*zoom/zoommax;

    switch (mode) {
     case 4:
      if (Y<=Mb-1) Mt=Y; else Mt=Mb-1;
      break;
     case 5:
      if (X<=Mr-1) Ml=X; else Ml=Mr-1;
      break;     
     case 6:
      if (Y>=Mt+1) Mb=Y; else Mb=Mt+1;
      break;     
     case 7:
      if (X>=Ml+1) Mr=X; else Mr=Ml+1;
      break;     
    }    
    printf("size: %dx%d              \n",Mr-Ml,Mb-Mt);
    mode=3;
    update_ximg();
    display_ximg2(1,x,y);
   } else {
    printf("size: %dx%d       \r",x2-x1,y2-y1);
    fflush(stdout);
   } 

   
   break;
   
   
  case 8:
   if (d&512) {
    mode=0;
    setname("normal");
    printf("returning to normal mode\n");
    return;
   }
   
   if (d&4) {
    lx1=x;
    ly1=y;
    lx2=-1;
    mode=9;
    break;
   }
  
   break;
   
   
  case 9: 
  
   if ((!(d&1)) && (lx2!=-1)) {
    if (lx1<lx2) { x1=lx1; x2=lx2; } else { x1=lx2; x2=lx1; }
    if (ly1<ly2) { y1=ly1; y2=ly2; } else { y1=ly2; y2=ly1; }
    if (x1<0) x1=0;
    if (x2>=Dx) x2=Dx-1;
    if (y1<0) y1=0;
    if (y2>=Dy) y2=Dy-1;
    if ((x1<=x2) && (y1<=y2)) {
     XPutImage(disp,win1,gc,gimg,x1,y1,x1,y1,x2-x1+1,1);
     XPutImage(disp,win1,gc,gimg,x1,y1,x1,y1,1,y2-y1+1);
     XPutImage(disp,win1,gc,gimg,x1,y2,x1,y2,x2-x1+1,1);
     XPutImage(disp,win1,gc,gimg,x2,y1,x2,y1,1,y2-y1+1);
    }
   }
   
   if (d&512) {
    mode=8;
    return;
   }
   
   
   if (d&4){

    if (lx1<lx2) { x1=lx1; x2=lx2; } else { x1=lx2; x2=lx1; }
    if (ly1<ly2) { y1=ly1; y2=ly2; } else { y1=ly2; y2=ly1; }
    x1=(x1+Dxo)*zoom/zoommax; 
    y1=(y1+Dyo)*zoom/zoommax;
    x2=(x2+Dxo)*zoom/zoommax; 
    y2=(y2+Dyo)*zoom/zoommax;
    
    if ((x1>x2-2) && (y1>y2-2)) break;

   
   
    pipe(fd);
   
    j=fork();
    if (j<0) printf("fork failed\n"); else if (!j) {
     close(fd[1]);
     dup2(fd[0],0);
     execvp("xv",xv_args);
     close(fd[0]);
     printf("execvp of xv failed!\n");
     exit(-1);
    } else {
     close(fd[0]);

     imap_ewa_merge(x1,y1,x2,y2,fd[1]);    
     update_mapc();
     update_edges();
     mode=8;
    } 
   
    break;
   }
   
   
   lx2=x;
   ly2=y;
   
   if (lx1<lx2) { x1=lx1; x2=lx2; } else { x1=lx2; x2=lx1; }
   if (ly1<ly2) { y1=ly1; y2=ly2; } else { y1=ly2; y2=ly1; }

   if ((x1<=x2) && (y1<=y2)) {
   
    XSetForeground(disp, gc, Cgreen.pixel);
    XSetBackground(disp, gc, Cred.pixel);

    XDrawLine(disp,win1,gc,x1,y1,x2,y1);   
    XDrawLine(disp,win1,gc,x2,y1,x2,y2);   
    XDrawLine(disp,win1,gc,x2,y2,x1,y2);   
    XDrawLine(disp,win1,gc,x1,y2,x1,y1);
   } 
  
   break; 
 } 
 
}
              



void display_ximg(int d,int x,int y){
 if (dmd) display_ximg2(d,x,y); else display_ximg1(d,x,y);
}
  




void update_edges() {
 IMG *img;
 edget *edge;
 int a;
 double X,Y;
 for(a=0;a<Ot;a++) {
  img=simg[a];
  edge=img->edge;
  while(edge) {
   mapc(img,edge->x,edge->y,&X,&Y); 
   edge->X=X;
   edge->Y=Y;
   edge=edge->next;   
  } 
 }
}




extern char *opt_wfile,*opt_Wfile;








void InitWin1(int dx,int dy) {
 int d,llx;
 XGCValues gs; 
 static unsigned char food[8]={0}; 

 XColor foo;
 Dx=dx;
 Dy=dy;


 
 
 color=XDefaultColormap(disp,XDefaultScreen(disp));

 XAllocNamedColor(disp,color,"black",&Cblack,&foo);	
 XAllocNamedColor(disp,color,"white",&Cwhite,&foo);	
 XAllocNamedColor(disp,color,"red",&Cred,&foo);	
 XAllocNamedColor(disp,color,"blue",&Cblue,&foo);	
 XAllocNamedColor(disp,color,"green",&Cgreen,&foo);	
 XAllocNamedColor(disp,color,"yellow",&Cyellow,&foo);	

 win1 = XCreateSimpleWindow(disp, RootWindow(disp, scrn),
         10, 10, Dx, Dy, 0, BlackPixel(disp, scrn),
          WhitePixel(disp, scrn));

 XSelectInput(disp, win1, ExposureMask | ButtonPressMask|ButtonReleaseMask|KeyPressMask|PointerMotionMask|StructureNotifyMask);


 gc = XCreateGC(disp, win1, 0, &gs);
 
 
 XSetForeground(disp, gc, Cwhite.pixel);
 XSetBackground(disp, gc, Cblack.pixel);	
 XSetLineAttributes(disp,gc,1,LineDoubleDash,CapButt,JoinMiter);
  
 XMapWindow(disp, win1);
 bpp=DefaultDepth(disp,scrn);
 
 if ((bpp!=16) && (bpp!=24) && (bpp!=32)) {
  fprintf(stderr,"Error: xmerge only works with 16,24 and 32bpp visuals\n");
  exit(-1);
 }

 
 printf("bpp: %d %d %d\n",bpp,Bpp*8,visual->class);

 xdata=malloc(64); 		//this is highly silly, but I can't find any other way :/
 gimg=XCreateImage(disp,visual,bpp,ZPixmap,0,xdata,4,4,32,16);

 if (gimg->byte_order==MSBFirst) Bgr=1; else Bgr=0;
 
 Bpp=gimg->bits_per_pixel/8;
 XDestroyImage(gimg);


 
 if ((Bpp*Dx)&3) llx=Dx*Bpp+(4-((Dx*Bpp)&3)); else llx=Dx*Bpp;
 
 Dxx=llx;
 xdata=malloc(Dxx*Dy); 	
 gimg=XCreateImage(disp,visual,bpp,ZPixmap,0,xdata,Dx,Dy,32,llx);
 
 d=XCreateBitmapFromData(disp,win1,food,8,8);    
 Bcursor=XCreatePixmapCursor(disp,d,d,&Cblack,&Cblack,0,0);									          
// Dcursor=XCreateFontCursor(disp,XC_crosshair);
 Dcursor=0;
 enable_cursor();

 
 lx1=ly1=0;
 lx2=ly2=0;

 update_ximg();
 XInitImage(gimg);

 
 XPutImage(disp,win1,gc,gimg,0,0,0,0,Dx,Dy);
}





int check_abort() {
 int d;
 if (nevent.type!=-1) return 0;
 do { 
  d=XCheckWindowEvent(disp,win1,ExposureMask | ButtonPressMask|ButtonReleaseMask|KeyPressMask|PointerMotionMask|StructureNotifyMask,&nevent);
 } while (d && (nevent.type==ButtonRelease) && (nevent.xbutton.button!=3));
 
 if (!d) nevent.type=-1;

 if (d && (nevent.type==event.type)) {
  if ((event.type==ButtonPress) && (nevent.xbutton.button==2)) return 1;
  if ((event.type==KeyPress) && (nevent.xkey.keycode==event.xkey.keycode) && (nevent.xkey.state==event.xkey.state)) return 1;
  if ((event.type==ConfigureRequest) && ((Dx!=nevent.xconfigure.width) || (Dy!=nevent.xconfigure.height))) return 1;
 }
 return 0;
}



void run_gui() {
 int x,y,dxo,dyo,d,llx;
// unsigned char *data;
 struct timeval tm;
 double t,X,Y;
 IMG * img;
 unsigned char buf[80];

 
 
/*
 Ml0=Ml=15;
 Mt0=Mt=15;
 Mr0=Mr=Dxm-15;
 Mb0=Mb=Dym-15;*/

 DxM=0;
 DyM=0;


 disp = XOpenDisplay(NULL); 
 if (disp == NULL) {
  fprintf(stderr,"Error: XOpenDisplay failed\n");
  exit(-1);
 }  
 scrn = DefaultScreen(disp);
 
 visual=DefaultVisual(disp,scrn); 


 printf("%d %d\n",WidthOfScreen(DefaultScreenOfDisplay(disp)),HeightOfScreen(DefaultScreenOfDisplay(disp)));

 for(zoom=zoommax;(WidthOfScreen(DefaultScreenOfDisplay(disp))-20<Dxm1*zoommax/zoom) || (HeightOfScreen(DefaultScreenOfDisplay(disp))-20<Dym1*zoommax/zoom);zoom*=2) ;
 
 Dxo=Dyo=0;  
 


 InitWin1(Dxm1*zoommax/zoom,Dym1*zoommax/zoom);
 
     
/* for(d=0;d<4;d++) {
  int a;
  unsigned int A;
  unsigned char * foo;
  A=0;
  foo=simg[d]->pix;
  for(a=0;a<simg[d]->sd;a++) A+=foo[a];
  printf("cs%d: %d\n",d,A);
  simg[d]->cs=A;
 }*/ 

 

 setname("normal");


 nevent.type=-1;
 
 while (1) {    
  
  aborting=0;
  
  /*
  for(d=0;d<4;d++) {
   int a;
   unsigned int A;
   unsigned char * foo;
   A=0;
   foo=simg[d]->pix;
   for(a=0;a<simg[d]->sd;a++) A+=foo[a];

   if (A!=simg[d]->cs) {
    printf("source image corruption detected, aborting\n");
    abort();
   }    
  }*/
  
  
  do  {		
   if (nevent.type==-1) XNextEvent(disp, &event); else memcpy(&event,&nevent,sizeof(XEvent));
   nevent.type=-1;
  } while ((event.type==ButtonRelease) && (event.xbutton.button!=3));	//a rather important case, unfortunately 
    
  do { 
   d=XCheckWindowEvent(disp,win1,ExposureMask | ButtonPressMask|ButtonReleaseMask|KeyPressMask|PointerMotionMask|StructureNotifyMask,&nevent);
  } while (d && (nevent.type==ButtonRelease) && (nevent.xbutton.button!=3)); 
  if (!d) nevent.type=-1;
   
 

  if (event.type==Expose) { 
 //  XPutImage(disp,win1,gc,img,0,0,0,0,Dx,Dy);
   if (nevent.type==Expose) {
//    printf("skipping update 1\n");
    continue;
   } 
   display_ximg(1,Dx/2,Dy/2);
  } 
  
  if (event.type==ConfigureNotify) { 
  
//on my system, I always get an expose after each ConfigureNotify, but it seems other people doesn't...  
//   int expose=0;
   
   
   
   if (nevent.type==Expose) {
//    expose=1;	//afaik this always happen
    		//nope, it does not
    		
    while(nevent.type==Expose) {
     do { 
      d=XCheckWindowEvent(disp,win1,ExposureMask | ButtonPressMask|ButtonReleaseMask|KeyPressMask|PointerMotionMask|StructureNotifyMask,&nevent);
     } while (d && (nevent.type==ButtonRelease) && (nevent.xbutton.button!=3)); 
     if (!d) nevent.type=-1;
    } 
   } 

   if (nevent.type==Expose) printf("BBlää\n");

   if (nevent.type==ConfigureNotify) {
    if ((Dx==nevent.xconfigure.width) && (Dy==nevent.xconfigure.height)) {
//     printf("not skipping, same size\n");
	//(it will be ignored anyway)
    } else {
//     printf("skipping update 2\n");
     continue;
    } 
   } 
   if ((Dx!=event.xconfigure.width) || (Dy!=event.xconfigure.height)) {
 
    Dx=event.xconfigure.width;
    Dy=event.xconfigure.height;
    printf("resize: %d %d\n",Dx,Dy);
    XDestroyImage(gimg);
    if ((Bpp*Dx)&3) llx=Dx*Bpp+(4-((Dx*Bpp)&3)); else llx=Dx*Bpp;
    Dxx=llx;
    xdata=malloc(Dxx*Dy);
    gimg=XCreateImage(disp,visual,bpp,ZPixmap,0,xdata,Dx,Dy,32,llx);
    XInitImage(gimg);
    update_ximg();
//    if (expose)
     display_ximg(1,Dx/2,Dy/2);
   } 
  } 
 
 
 
  if (event.type==MotionNotify) {
   if (nevent.type==MotionNotify) {
//    printf("skipping update 3\n");
    continue;
   } 
   x=event.xmotion.x;
   y=event.xmotion.y;
   display_ximg(0,x,y);
  }
    
  if ((event.type==ButtonPress) || (event.type==ButtonRelease)){
  
   x=event.xbutton.x;
   y=event.xbutton.y;
    
   
   switch(event.xbutton.button) {
    case 1:
     if (event.type==ButtonPress) display_ximg(4,x,y); else display_ximg(8,x,y);
     break;
    case 2:	//center on cursor
     if (event.type!=ButtonPress) break;
     dxo=Dxo;
     dyo=Dyo;

     Dxo-=(Dx/2)-x;
     Dyo-=(Dy/2)-y;

     if (zoommax>zoom) {
      Dxo&=(~(zoommax/zoom-1));	//keep the map on even multiples for faster mapping
      Dyo&=(~(zoommax/zoom-1));
     } 
       
   

     if (Dx/2+Dxo>Dxm*zoommax/zoom) Dxo=Dxm*zoommax/zoom-Dx/2;
     if (Dxo+Dx/2<DxM*zoommax/zoom) Dxo=DxM*zoommax/zoom-Dx/2; 
     if (Dy/2+Dyo>Dym*zoommax/zoom) Dyo=Dym*zoommax/zoom-Dy/2;
     if (Dyo+Dy/2<DyM*zoommax/zoom) Dyo=DyM*zoommax/zoom-Dy/2;       
       
      
     if (((lx1!=-1) /*&& (mode<5)*/) || (dmd)) {
      lx1+=dxo-Dxo;
      ly1+=dyo-Dyo;
     }
      
     if (((lx2!=-1) /*&& (mode<5)*/) || (dmd)) {
      lx2+=dxo-Dxo;
      ly2+=dyo-Dyo;
     }
       
       
     if ((nevent.type==ButtonPress) && (nevent.xbutton.button==2)) {
//      printf("skipping update 4\n");
      continue;       
     } 
     update_ximg();
     display_ximg(1,x,y);	
     break;
  
    case 3:
     if (event.type==ButtonPress) display_ximg(64,x,y); else display_ximg(128,x,y);
     break;
    
   }  
  }
    
  if (event.type==KeyPress) {
   x=event.xkey.x;
   y=event.xkey.y;
     
    
   d=XLookupString(&event.xkey,buf,80,0,0);
//  printf("d: %d\n",d);
   if (!d) continue;
   if (buf[1]) continue;	//only 1-char sequences accepted
   
    
   switch(buf[0]) {    
    case '-':
     dxo=(Dxo+Dx/2)/2-Dx/2;
     dyo=(Dyo+Dy/2)/2-Dy/2;     
      


     zoom=zoom*2;
 
     if (zoommax>zoom) {
      dxo&=(~(zoommax/zoom-1));	//keep the map on even multiples for faster mapping
      dyo&=(~(zoommax/zoom-1));
     } 
      
     if ((mode==1) || ((mode==6)&& (!dmd))||((mode>=8) && dmd)) {
      lx1=(lx1+Dxo)/2.0-dxo;
      ly1=(ly1+Dyo)/2.0-dyo;
     }
    
     

     Dxo=dxo;
     Dyo=dyo;

     
     if ((nevent.type==KeyPress) && (event.xkey.keycode==nevent.xkey.keycode) && (event.xkey.state==nevent.xkey.state)) { 
//      printf("skipping update 5\n");
      continue;
     } 
     
     update_ximg();
     display_ximg(257,x,y);	//redraw, but old screen coordinates
     setname(0);
     break;


    case '+':
     if (zoom>1) {
      dxo=(Dxo+Dx/2)*2-Dx/2;
      dyo=(Dyo+Dy/2)*2-Dy/2;
     

      zoom=zoom/2;
     
      if (zoommax>zoom) {
       dxo&=(~(zoommax/zoom-1));	//keep the map on even multiples for faster mapping
       dyo&=(~(zoommax/zoom-1));
      } 
  
      if ((mode==1) || ((mode==6)&& (!dmd))||((mode>=8) && dmd)) {   
//     if ((mode==1) || (mode>=8)) {
       lx1=(lx1+Dxo)*2.0-dxo;
       ly1=(ly1+Dyo)*2.0-dyo;
      }
     
     
 
      Dxo=dxo;
      Dyo=dyo;
     } 
     
     if ((nevent.type==KeyPress) && (event.xkey.keycode==nevent.xkey.keycode) && (event.xkey.state==nevent.xkey.state)) { 
//      printf("skipping update 6\n");
      continue;
     } 
     
     update_ximg();
     display_ximg(257,x,y);	//redraw, but old screen coordinates
     setname(0);
     break;
    
    case 'd':
     display_ximg(1024,x,y);
     break; 
    
    case 'c':
     display_ximg(2048,x,y);
     setname("crop select");
     break; 
    
    case '1':
     display_ximg(4096+0,x,y);
     setname("horizontal constraint");
     break; 

    case '2':
     display_ximg(4096+1,x,y);
     setname("vertical constraint");
     break;     
    
    case '3':
     display_ximg(4096+2,x,y);
     setname("45deg constraint");
     break; 

    case '4':
     display_ximg(4096+3,x,y);
     setname("315deg constraint");
     break;     
         
    case 'r':
     printf("reseting solution to initial values\n");
     for(d=0;d<Ot;d++) {
      simg[d]->dx1=simg[d]->dx3=simg[d]->Tx;
      simg[d]->dy1=simg[d]->dy2=simg[d]->Ty;
      simg[d]->dx2=simg[d]->dx4=simg[d]->Tx+simg[d]->sx;
      simg[d]->dy3=simg[d]->dy4=simg[d]->Ty+simg[d]->sy;
     }
     display_ximg(512,x,y);
     dmd=0;
     display_ximg(1,x,y);
     setname(0);
     break;
     
 
    
    case 'q':
     exit(0);
     
     
    case 'i':
     improve=improve^1;
     printf("improve: %d\n",improve);
     setname(0);
     break;
      
    case 'I':
     Integers=Integers^1;
     printf("Integers: %d\n",Integers);
     setname(0);
     break; 
     
    case 's':
     display_ximg(512,x,y);
 
     solve();
     dmd=1; 
     mode=0;

     Dxm=Mr+15;
     Dym=Mb+15;
     DxM=Ml-15;
     DyM=Mt-15;
 
     goto oupd;
  
     Dxo=(Ml+Mr)/2;
     Dyo=(Mt+Mb)/2;
     update_ximg();
     display_ximg(1,x,y);
     setname(0);
     break;
    
    case 'p':
     if (!dmd) break;
     display_ximg(4096+4,x,y);
     setname("preview");
     break;
   
    
    case 'b':
     if (dmd) break;
     display_ximg(4096+5,x,y);
     setname("brightness adjust");
     break;  
    
    case 'B':
     if (dmd) break;
     for(d=0;d<Ot;d++) {
      simg[d]->Gr=simg[d]->Gg=simg[d]->Gb=1;
      simg[d]->Grn=simg[d]->Ggn=simg[d]->Gbn=0;
     }
     printf("gains used for brightness adjust reset\n");
     break;  
    
    
    case 27:
     display_ximg(512,x,y);
    
     break; 
   
    case 'm':
     display_ximg(512,x,y);
     mode=0;
     dmd=!dmd;
oupd:    

     X=(Dx/2+Dxo)*zoom/zoommax; Y=(Dy/2+Dyo)*zoom/zoommax;
 
     if (dmd) {
     
      img=find_cimg(Dx/2,Dy/2);
      if (!img) {
       Dxo=((X-20)*(Mr0-Ml0)/(Dxm1-40)+Ml0)*zoommax/zoom-Dx/2;
       Dyo=((Y-20)*(Mb0-Mt0)/(Dym1-40)+Mt0)*zoommax/zoom-Dy/2;
      } else {
       Dxo=Dyo=0;
       update_mapc();        
      
       mapc(img,X-img->Tx,Y-img->Ty,&X,&Y);
 
       Dxo=X-Dx/2;
       Dyo=Y-Dy/2;     
      }
      Dxm=Mr0+15;
      Dym=Mb0+15;
      DxM=Ml0-15;
      DyM=Mt0-15;
     } else {
      update_mapc();
      d=find_cimg2(X,Y);
      if(d<0) {
       Dxo=((X-Ml0)*(Dxm1-40)/(Mr0-Ml0)+20)*zoommax/zoom-Dx/2;  
       Dyo=((Y-Mt0)*(Dym1-40)/(Mb0-Mt0)+20)*zoommax/zoom-Dy/2;
      } else {
       mapcrs(simg[d],Dx/2,Dy/2,&X,&Y);
       Dxo=(X+simg[d]->Tx)*zoommax/zoom-Dx/2;
       Dyo=(Y+simg[d]->Ty)*zoommax/zoom-Dy/2;
      }
      
      DxM=0;
      DyM=0; 
      Dxm=Dxm1;
      Dym=Dym1;
     }

     update_ximg();
     display_ximg(1,x,y);
     setname(0);
     break;
    
    case 'a': 
     for(d=0;d<MAXLINKS;d++) if ((rlink[d].stat&2) && (rlink[d].type==0)) {
      improve_match_ewa(rlink[d].si,rlink[d].di,rlink[d].sx1,rlink[d].sy1,&rlink[d].dx,&rlink[d].dy,rlink[d].sx2-rlink[d].sx1,rlink[d].sy2-rlink[d].sy1,1);      
     }
     printf("auto improve completed\n");
     break;
    
    case 'W':
     write_list(opt_Wfile);
     printf("wrote file %s\n",opt_Wfile);
     break;
    
    case 'w':
 

     gettimeofday(&tm,NULL);
     t=-tm.tv_sec-(float)tm.tv_usec/1000000;
     d=open(opt_wfile,O_WRONLY|O_CREAT|O_TRUNC,0777);
     imap_ewa_merge(Ml,Mt,Mr,Mb,d);
    
     update_mapc();
     update_edges();
    
     gettimeofday(&tm,NULL);
     t+=tm.tv_sec+(float)tm.tv_usec/1000000;
     printf("\nt: %f\n",t);
     break;
   }       
  }
 }
}

