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

#include "labImage.h"

#include "labFont.h"

#include "labImgDraw.h"

#define NINT(a) (a > 0)? ((int)(a+0.5)) : ((int)(a-0.5)) 
#define SQRT_OF_05 0.70710678119
#define ZWEIPI 6.2832  
#define FABSi(a) ((a)>0.0?(a):(-a))

/*Standard DrawColor and Grayvalue                                    */
static unsigned char MyDrawColor[3] = {255, 255, 255};
static unsigned char MyDrawGrayval  =  255;
static short MyDrawGrayvalShort = 255;
/***************************/
int createSinusoid(Picture *p_image,int xoffset,int yoffset, 
		   int facx,int facy)
{
  int x,y;
  double val;
  
  for(y=0; y<p_image->height; y++)
    {
      for(x=0; x<p_image->width; x++)
	{
	  val=sin((x+xoffset)*ZWEIPI/facx)*sin((y+yoffset)*ZWEIPI/facy);
	  p_image->data[y * p_image->width +x ]=
	    (unsigned char) (FABSi(val)*250.0+5.0);
	}
    }
  
  return 1;
  
}


/**********************************************************************/

int setDrawColorImage(unsigned char *p_colors)
{
  if(!p_colors) return(0);
  MyDrawColor[0] = *p_colors++;
  MyDrawColor[1] = *p_colors++;
  MyDrawColor[2] = *p_colors;
  return(1);
}

/**********************************************************************/

void setDrawColorImageR(unsigned char r)
{
  MyDrawColor[0] = r;
}

/**********************************************************************/

void setDrawColorImageG(unsigned char g)
{
  MyDrawColor[1] = g;
}

/**********************************************************************/

void setDrawColorImageB(unsigned char b)
{
  MyDrawColor[2] = b;
}

/**********************************************************************/

void setDrawGValImage(unsigned char grayval)
{
  MyDrawGrayval = grayval;
}


/**********************************************************************/
void setDrawGShort(short grayshort)
{
  MyDrawGrayvalShort = grayshort;
}


/**********************************************************************/
/**********************************************************************/

int reshapeImage_g(Picture *p_image, int xs, int ys, int w, int h, 
                                               unsigned char bgnd)
{
  int            ii, jj;             /*Countervariables               */
  unsigned char *p_data, *p_zwdata;  /*Auxiliary Pointers to Imagedata*/
  
  if(!p_image) return(0);
  if(p_image->format != pix_grey) return(0);
  if((w <=0) || (h <= 0)) return(0);
  if(!(p_zwdata =(unsigned char *)malloc(w*h*sizeof(unsigned char))))
    return(0);
  memset(p_zwdata, bgnd, w*h);
  p_data = (unsigned char *)p_image->data;
  for(ii = 0; ii < (int)p_image->height; ii++)
  {
    for(jj = 0; jj < (int)p_image->width; jj++)
    {
      if(((xs + jj) < w ) && ((ys + ii) < h ) &&
     ((xs + jj) >= 0) && ((ys + ii) >= 0)   )
      { 
    p_zwdata[(ii+ys)*w+xs+jj] = p_data[ii*p_image->width+jj];
      }
    }
  }
  p_image->width = w;
  p_image->height = h;
  free(p_image->data);
  p_image->data = p_zwdata;
  return(1);
}

/**********************************************************************/

int reshapeImage_rgb(Picture *p_image, int xs, int ys, int w, int h, 
                   unsigned char r, unsigned char g, unsigned char b)
{
  int            ii, jj;                        /*Countervariables    */
  unsigned char *p_data, *p_zwdata, *p_zwdata2; /*Auxiliary Pointers  */
  
  if(!p_image)               return(0);
  if(p_image->format != pix_rgb24) return(0);
  if((w <=0) || (h <= 0))    return(0);
  if(!(p_zwdata =(unsigned char *)malloc(3*w*h*sizeof(unsigned char))))
    return(0);
  p_zwdata2 = p_zwdata;
  for(ii = 0; ii < w*h; ii++) 
  {
    *p_zwdata2++ = r;
    *p_zwdata2++ = g;
    *p_zwdata2++ = b;
  }
  p_data = (unsigned char *)p_image->data;
  for(ii = 0; ii < (int)p_image->height; ii++)
  {
    for(jj = 0; jj < (int)p_image->width; jj++)
    {
      if(((xs + jj) < w ) && ((ys + ii) < h ) &&
     ((xs + jj) >= 0) && ((ys + ii) >= 0)   )
      { 
        p_zwdata[3*((ii+ys)*w+xs+jj)+0] = 
          p_data[3*(ii*p_image->width+jj)+0];      
        p_zwdata[3*((ii+ys)*w+xs+jj)+1] = 
          p_data[3*(ii*p_image->width+jj)+1];      
        p_zwdata[3*((ii+ys)*w+xs+jj)+2] = 
         p_data[3*(ii*p_image->width+jj)+2];      
      }
    }
  }
  p_image->width = w;
  p_image->height = h;
  free(p_image->data);
  p_image->data = p_zwdata;
  return(1);
}

/**********************************************************************/

int reshapeImage(Picture *p_image, int xs, int ys, int w, int h)
{
  int            ii, jj, kk;                   /*Countervariables     */
  int            mydepth;                      /*Bytes per Pixel      */
  unsigned char *p_data, *p_zwdata;            /*Auxiliary Pointers   */
  
  if(!p_image) return(0);
  switch (p_image->format)
    {
      case pix_grey   : mydepth=1; break;
      
    case pix_rgb24    : mydepth=3; break;
      
      default       : return(0); 
    }
  if((w <=0) || (h <= 0)) return(0);
  if(!(p_zwdata =
          (unsigned char *)malloc(w*h*sizeof(unsigned char)*mydepth)))
    return(0);
  memset(p_zwdata, 0, w*h*mydepth);
  p_data = (unsigned char *)p_image->data;
  for(ii = 0; ii < (int)p_image->height; ii++)
  {
    for(jj = 0; jj < (int)p_image->width; jj++)
    {
      if(((xs + jj) < w ) && ((ys + ii) < h ) &&
     ((xs + jj) >= 0) && ((ys + ii) >= 0)   )
      { 
        for(kk = 0; kk < mydepth; kk++) 
        {
          p_zwdata[mydepth *((ii+ys)*w+xs+jj)+kk] = 
                    p_data[mydepth*(ii*p_image->width+jj)+kk];
        }      
      }
    }
  }
  p_image->width = w;
  p_image->height = h;
  free(p_image->data);
  p_image->data = p_zwdata;
  return(1);
}

/**********************************************************************/
/*p_image: Image into which p_img2 is put                             */
/*p_img2: Image which is put into p_image                             */
/*x, y: left upper edge of img2 in image                              */
/*overlay: if(overlay) blend out parts of p_img2 having the value     */
/*         MyDrawColor if RGB image or MyDrawGrayval if Mono,         */
/*         showing p_image in these places instead                    */
/*cutimg2: if set p_img2 will be cut to fit into p_image,             */
/*         else p_image will be resized to be able to hold p_img2     */
/*bgnd:    if !cutimg2 bgnd will be used to fill the enlarged         */
/*         p_image (RGB = bgnd bgnd bgnd)                             */
/**********************************************************************/

int putImageInImageOverlay(Picture *p_image, Picture *p_img2, int x, int y, 
                          int overlay, int cutimg2, unsigned char bgnd)
{
  int     ii, jj;      /*Countervariables                             */
  int     w, h;        /*Imagewidth and height                        */
  int     xstart = 0;  /*Startpoint in Image 2                        */
  int     ystart = 0;  /*Startpoint in Image 2                        */
  Picture  *p_zwimg;     /*Auxiliary Image                              */
  
  if(!p_image || !p_img2)     return(0);
  if((p_image->format == pix_grey) && (p_img2->format == pix_rgb24))
  {
    fprintf(stderr, "Function putImageInImage not implemented");
    fprintf(stderr, " for putting RGB into MONO yet\n");
    return(0);
  }
  if(((p_image->format != pix_grey) && (p_image->format != pix_rgb24)) ||
     ((p_img2->format  != pix_grey) && (p_img2->format  != pix_rgb24))   )
  {
    fprintf(stderr, "Function putImageInImage not implemented");
    fprintf(stderr, " for Typecombination %d %d yet\n", 
                                    p_image->format, p_img2->format);
    return(0);
  }
  w = p_image->width;
  h = p_image->height;
  if( (x < 0) || (y < 0) ||
      (x+p_img2->width > p_image->width) || 
            (y+p_img2->height > p_image->height))
  {
    if(cutimg2)
    {
      if(x < 0) xstart = -x;
      if(y < 0) ystart = -y;
      if(x+p_img2->width > p_image->width) w=p_image->width-x-xstart;
      else                                 w =  p_img2->width-xstart;
      if(y+p_img2->height>p_image->height) h=p_image->height-y-ystart;
      else                                 h = p_img2->height-ystart;
      if((xstart > (int)p_img2->width) || (w < 0) || 
         (ystart > (int)p_img2->height)|| (h < 0)   )      return(0);
      if(!(p_zwimg = cropImage(p_img2,xstart,ystart,w,h))) return(0);
      if(x < 0) xstart = -xstart;
      if(y < 0) ystart = -ystart;

    }
    else
    {
      if(x < 0) {xstart = -x; w -= x;}
      else      {xstart =  0; w  = 0;}
      if(y < 0) {ystart = -y; h -= y;}
      else      {ystart =  0; h  = 0;}
      if(x+p_img2->width > p_image->width)
        w += x+p_img2->width;
      else w = p_image->width;
      if(y+p_img2->height > p_image->height)
        h += y+p_img2->height;
      else h = p_image->height;
      if(p_image->format == pix_grey)
      {
        if(!reshapeImage_g(p_image,xstart,ystart,w,h,bgnd)) return(0);
      }
      else if(p_image->format == pix_rgb24)
      {
        if(!reshapeImage_rgb(p_image,xstart,ystart,w,h,bgnd,bgnd,bgnd)) 
          return(0);
      }
      else
      {
       if(!reshapeImage(p_image, xstart, ystart, w, h)) return(0);
      }
      p_zwimg = copyImage(p_img2);
    }
  }
  else 
  {
    p_zwimg = copyImage(p_img2);
  }
  if(p_image->format == pix_grey)
  {
    unsigned char *p_data = (unsigned char *)p_image->data;

    if(p_zwimg->format == pix_grey)
    {
      unsigned char *p_data2 = (unsigned char *)p_zwimg->data;
      for(ii = 0; ii < (int)p_zwimg->height; ii++)
      {
        for(jj = 0; jj < (int)p_zwimg->width; jj++)
        {
          if((!overlay) || 
             (p_data2[ii*p_zwimg->width+jj] != MyDrawGrayval))
                p_data[(ii+y-ystart)*p_image->width+jj+x-xstart] = 
                                  p_data2[ii*p_zwimg->width+jj];
        }
      }
    }
    else fprintf(stderr, "This branch should not be possible ERC1\n");
  }
  else if(p_image->format == pix_rgb24)
  {
    unsigned char *p_data  = (unsigned char *)p_image->data;
    unsigned char *p_data2;
    if(p_zwimg->format == pix_grey) MONO2RGB(p_zwimg);
    if(p_zwimg->format != pix_rgb24) {freeImage(p_zwimg); return(0);}
    p_data2 = (unsigned char *)p_zwimg->data;
    for(ii = 0; ii < (int)p_zwimg->height; ii++)
    {
      for(jj = 0; jj < (int)p_zwimg->width; jj++)
      {
        if((!overlay) || 
         (p_data2[3*(ii*p_zwimg->width+jj)+0] != MyDrawColor[0]) ||
         (p_data2[3*(ii*p_zwimg->width+jj)+1] != MyDrawColor[1]) ||
         (p_data2[3*(ii*p_zwimg->width+jj)+2] != MyDrawColor[2])   )
        {
          p_data[3*((ii+y-ystart)*p_image->width+jj+x-xstart) +0] = 
                              p_data2[3*(ii*p_zwimg->width+jj)+0];
          p_data[3*((ii+y-ystart)*p_image->width+jj+x-xstart) +1] = 
                              p_data2[3*(ii*p_zwimg->width+jj)+1];
          p_data[3*((ii+y-ystart)*p_image->width+jj+x-xstart) +2] = 
                              p_data2[3*(ii*p_zwimg->width+jj)+2];
        }
      }
    }
  }
  else fprintf(stderr, "This branch should not be possible ERC2\n");  
  return(1);
}

/**********************************************************************/

int putImageInImage(Picture *p_image, Picture *p_img, int x, int y)
{
  return(putImageInImageOverlay(p_image, p_img, x, y, 0, 0, 0));
}

/**********************************************************************/
/**********************************************************************/
/**********************************************************************/

Picture *invertImage(Picture *p_image)
{
  unsigned int   ii;            /*Countervariable                     */
  unsigned int  byteno = 1;     /*Number of Bytes per Pixel           */
  unsigned char *p_data;        /*Image-Datapointer                   */
  Picture        *p_img;         /*Returnimage                         */
  
  if(!p_image) return(NULL);
  p_img = copyImage(p_image);
  if((p_image->format != pix_grey) && (p_image->format != pix_rgb24)) 
  {
    fprintf(stderr, "invertImage not implemented for Type %d yet\n",
            p_image->format);
    return(NULL);
  }
  if(!(p_img = copyImage(p_image))) return(NULL);
  if(p_image->format == pix_rgb24) byteno = 3;
  p_data = (unsigned char *)p_img->data;
  for(ii = 0; ii < byteno * p_img->width * p_img->height; ii++)
  {
    *p_data = (unsigned char)(255 - *p_data++);
  }
  return(p_img);
}

/**********************************************************************/

Picture *ReGrayImage(Picture *p_image, int gray)
{
  unsigned int   ii;       /*Countervariabel                          */
  Picture         *p_img;    /*Returned Image                           */
  unsigned char *p_data;   /*Image-Data-Pointer                       */
  if(!p_image)                      return(NULL);
  if(p_image->format != pix_grey)       return(NULL);
  if(!(p_img = copyImage(p_image))) return(NULL);
  p_data = (unsigned char *)p_img->data;
  for(ii = 0; ii < p_img->width * p_img->height; ii++)
    if(p_data[ii]) p_data[ii] = (unsigned char)gray; 
  return(p_img);
}
/**********************************************************************/

Picture *ReColorImage(Picture *p_image , int red, int green, int blue)
{
  unsigned int   ii;       /*Countervariabel                          */
  Picture        *p_img;    /*Returned Image                           */
  unsigned char *p_data;   /*Image-Data-Pointer                       */
  
  if(!(p_image)) return(NULL);
  if((p_image->format != pix_grey)||(p_image->format != pix_rgb24)) return(NULL);
  if(!(p_img = copyImage(p_image))) return(NULL);
  if(p_img->format == pix_grey)  MONO2RGB(p_img);
  /*RGBtoMONO has got no Memory -> return(NULL);*/
  if(p_img->format == pix_grey) {freeImage(p_img); return(NULL);}
  p_data = (unsigned char *)p_img->data;
  for(ii = 0; ii < p_img->width * p_img->height; ii++)
  {
    if(*p_data) 
    {
      *p_data++ = (unsigned char)red;
      *p_data++ = (unsigned char)green;
      *p_data++ = (unsigned char)blue;
    }
  }
  return(p_img);
}

/**********************************************************************/

Picture *Images_to_Colorchannels(
               Picture *p_img1, char color1, int x1, int y1,
               Picture *p_img2, char color2, int x2, int y2,
           Picture *p_img3, char color3, int x3, int y3,
                                             int cut_to_imgsize)
{
  unsigned int   ii, jj;          /*countervariables                  */
  int            xstart   =  0;   /*Left upper corner of new Image    */
  int            ystart   =  0;   /*in Coordinates of p_img1          */
  int            offset1  = -1;   /*Determins the Color 0=R, 1=G, 2=B */
  int            offset2  = -1;   /*the Channel in which Img123 are   */
  int            offset3  = -1;   /* put                              */
  Picture         *p_res    = NULL; /*Resulting Image                   */
  unsigned char *p_data   = NULL; /*ImageData-Pointer Resulting Picture */
  unsigned char *p_idata  = NULL; /*ImageData-Pointer InImage 1 2 or 3*/
  
  if(p_img1) if((p_img1->format != pix_grey)) return(NULL);
  if(p_img2) if((p_img2->format != pix_grey)) return(NULL);
  if(p_img3) if((p_img3->format != pix_grey)) return(NULL); 
  if(p_img1)
  {
    switch(color1)
    {
      case 'R':
      case 'r': offset1 = 0; break;
      case 'G':
      case 'g': offset1 = 1; break;
      case 'B':
      case 'b': offset1 = 2; break;
      default : return(NULL);
    }
  }
  if(p_img2)
  {
    switch(color2)
    {
      case 'R':
      case 'r': offset2 = 0; break;
      case 'G':
      case 'g': offset2 = 1; break;
      case 'B':
      case 'b': offset2 = 2; break;
      default : return(NULL);
    }
  }
  
  if(p_img3)
  {
    switch(color3)
    {
      case 'R':
      case 'r': offset3 = 0; break;
      case 'G':
      case 'g': offset3 = 1; break;
      case 'B':
      case 'b': offset3 = 2; break;
      default : return(NULL);
    }
  }
  /*Compute Image-Dimensions                                  */
  if(!(p_res = newImage())) return(NULL);
  p_res->format = pix_rgb24;
  if(cut_to_imgsize) /*Cut overlays if needed*/
  {
    if(!p_img1) {freeImage(p_res); return(NULL);}
    if(!resizeImage(p_res, p_img1->width, p_img1->height))
    {freeImage(p_res); return(NULL);}
  }
  else /* fit everything into Image*/
  {
    int xend   = 0;
    int yend   = 0;
    if(p_img1)
    {
      if(xstart > x1)                       xstart = x1;
      if(ystart > y1)                       ystart = y1;
      if(xend   < (x1+(int)p_img1->width )) xend   = x1+p_img1->width;
      if(yend   < (y1+(int)p_img1->height)) yend   = y1+p_img1->height;
    }
    if(p_img2)
    {
      if(xstart > x2)                       xstart = x2;
      if(ystart > y2)                       ystart = y2;
      if(xend   < (x2+(int)p_img2->width )) xend   = x2+p_img2->width;
      if(yend   < (y2+(int)p_img2->height)) yend   = y2+p_img2->height;
    } 
    if(p_img3) 
    {
      if(xstart > x3)                       xstart = x3;
      if(ystart > y3)                       ystart = y3;
      if(xend   < (x3+(int)p_img3->width))  xend   = x3+p_img3->width;
      if(yend   < (y3+(int)p_img3->height)) yend   = y3+p_img3->height;
    }
    if((xend <= xstart) || (yend < ystart)) 
      {freeImage(p_res);fprintf(stderr,"Imgsize < 0\n");return(NULL);}
    if(!resizeImage(p_res, xend-xstart, yend-ystart))
      {freeImage(p_res);fprintf(stderr,"Imgsize < 0\n");return(NULL);}
  }
  clearImage(p_res);
  
  if(p_img1)
  {
    p_data  =  (unsigned char *)p_res->data;
    p_idata =  (unsigned char *)p_img1->data;
    for(ii = 0; ii < p_img1->height; ii++)
    {
      for(jj = 0; jj < p_img1->width; jj++)
      {
        int yval = ii + y1 - ystart;
        int xval = jj + x1 - xstart;
        if((xval >= 0) && (xval < (int)p_res->width) && 
           (yval >= 0) && (yval < (int)p_res->height)   )
        {
          p_data[3*(yval * p_res->width + xval) + offset1] = *p_idata++;
        }
        else
        {
          p_idata++;
        }
      }
    }
  }
  if(p_img2)
  {
    p_data   = (unsigned char *)p_res->data;
    p_idata = (unsigned char *)p_img2->data;
    for(ii = 0; ii < p_img2->height; ii++)
    {
      for(jj = 0; jj < p_img2->width; jj++)
      {
        int yval = ii + y2 - ystart;
        int xval = jj + x2 - xstart;
        if((xval >=0) && (xval < (int)p_res->width) && 
                         (yval >= 0) && (yval < (int)p_res->height))
        {
          p_data[3*(yval*p_res->width + xval) + offset2] = *p_idata++;
        }
        else
        {
          p_idata++;
        }
      }
    }
  }
  if(p_img3)
  {
    p_data   = (unsigned char *)p_res->data;
    p_idata = (unsigned char *)p_img3->data;
    for(ii = 0; ii < p_img3->height; ii++)
    {
      for(jj = 0; jj < p_img3->width; jj++)
      {
        int yval = ii + y3 - ystart;
        int xval = jj + x3 - xstart;
        if((xval >=0) && (xval < (int)p_res->width) && 
                         (yval >= 0) && (yval < (int)p_res->height))
        {
          p_data[3*(yval*p_res->width + xval) + offset3] = *p_idata++;
        }
        else
        {
          p_idata++;
        }
      }
    }
  }
  return(p_res);
}

/**********************************************************************/
/**********************************************************************/
/**********************************************************************/


int PutPixelInImage(Picture *p_image, int x, int y)
{
  if(!p_image) return(0);
  if((x >= (int)p_image->width ) || (x < 0)) return(-1);
  if((y >= (int)p_image->height) || (y < 0)) return(-1);
  if(p_image->format == pix_grey)
  {
    unsigned char *p_data = (unsigned char *)p_image->data;
    p_data[y * p_image->width + x] = MyDrawGrayval;
  }
  else if(p_image->format == pix_rgb24)
  {
    unsigned char *p_data = (unsigned char *)p_image->data;
    p_data += 3*(y * p_image->width + x);
    *p_data++ = MyDrawColor[0];
    *p_data++ = MyDrawColor[1];
    *p_data   = MyDrawColor[2];
  }
  else
  {
    fprintf(stderr, "Function PutPixelInImage for Type ");
    fprintf(stderr, "%d not implemented yet\n", p_image->format);
    return(0);
  }
  return(1);
}

/**********************************************************************/

int PutPixelInImageF(Picture *p_image, float x, float y)
{
  return(PutPixelInImage(p_image, NINT(x), NINT(y)));
}

/**********************************************************************/

int PutBigPixelInImage(Picture *p_image, int x, int y, int pointsize)
{
  if(pointsize < 2) PutPixelInImage(p_image, x, y);
  if(pointsize == 3)
  {
    PutPixelInImage(p_image, x-1, y  );
    PutPixelInImage(p_image, x+1, y  );
    PutPixelInImage(p_image, x  , y-1);
    PutPixelInImage(p_image, x  , y+1);
    PutPixelInImage(p_image, x  , y  );
  } 
  if(pointsize == 3)
  {
    PutPixelInImage(p_image, x-2, y  );
    PutPixelInImage(p_image, x-1, y+1);
    PutPixelInImage(p_image, x-1, y  );
    PutPixelInImage(p_image, x-1, y-1);
    PutPixelInImage(p_image, x  , y+2);
    PutPixelInImage(p_image, x  , y+1);
    PutPixelInImage(p_image, x  , y  );
    PutPixelInImage(p_image, x  , y-1);
    PutPixelInImage(p_image, x  , y-2);
    PutPixelInImage(p_image, x+1, y+1);
    PutPixelInImage(p_image, x+1, y  );
    PutPixelInImage(p_image, x+1, y-1);
    PutPixelInImage(p_image, x+2, y  );
  }
  else
  {
    fillCircleInImage(p_image, x, y, pointsize/2+1);
  }
  return(1);
}

/**********************************************************************/
/**********************************************************************/

int drawHorizontalInImage(Picture *p_image, int y, int x1, int x2)
{
  int ii;               /*Countervariable                             */
  if(!p_image) return(0);
  if((y < 0) || (y > (int)p_image->height))  return(-1);
  if(x1 > x2) {ii = x1; x1 = x2; x2 = ii;}
  if((x1 > (int)p_image->width) || (x2 < 0)) return(-1);
  if(x1 < 0)                   x1 = 0;
  if(x2 > (int)p_image->width) x2 = p_image->width;
  if(p_image->format == pix_grey)
  {
    unsigned char *p_data = (unsigned char *)p_image->data;
    p_data += y*p_image->width + x1;
    memset(p_data, MyDrawGrayval, x2-x1);
  }
  else if(p_image->format == pix_rgb24)
  {
    unsigned char *p_data = (unsigned char *)p_image->data;
    p_data += 3*(y*p_image->width + x1);
    for(ii = 0; ii < x2-x1; ii++)
    {
      *p_data++ = MyDrawColor[0];
      *p_data++ = MyDrawColor[1];
      *p_data++ = MyDrawColor[2];
    }
  }
  else
  {
    fprintf(stderr, 
           "drawHorizontalInImage not implemented for Type %d yet\n",
                                                  p_image->format);
  }
  return(1);
}

/**********************************************************************/
/* Bresenham Line, Linewidth = 1                                      */
/**********************************************************************/
int drawLineInImage1(Picture *p_image, int x1, int y1, int x2, int y2)
{
  int deltax, deltay;             /*Distance x1-x2 and y1-y2          */
  int x, y;                       /*Point where a Pixel is put        */
  int d;                          /*Auxiliary Value                   */
  int dinc1, dinc2;               /*Increment                         */
  int xinc1, xinc2, yinc1, yinc2; /*Increment to get to next Point    */
  int ii;                         /*Countervatiable                   */
  int numpixels;                  /*Number of Pixels to be drawn      */
    
  if(!p_image) return(0); 
  
  deltax = abs(x2 - x1);
  deltay = abs(y2 - y1);
  
  if( deltax >= deltay)
  {
    numpixels = deltax + 1;
    d         = (2 * deltay) - deltax;
    dinc1     = 2 * deltay;
    dinc2     = 2 * (deltay - deltax);
    if(x1 > x2) xinc1 = -1;
    else        xinc1 =  1;
    if(x1 > x2) xinc2 = -1;
    else        xinc2 =  1;
    yinc1     = 0;
    if(y1 > y2) yinc2 = -1;
    else        yinc2 =  1;
  }
  else
  {
    numpixels = deltay + 1;
    d         = (2 * deltax) - deltay;
    dinc1     = 2 * deltax;
    dinc2     = 2 * (deltax - deltay);
    xinc1     = 0;
    if(x1 > x2) xinc2 = -1;
    else        xinc2 =  1;
    if(y1 > y2) yinc1 = -1;
    else        yinc1 =  1;
    if(y1 > y2) yinc2 = -1;
    else        yinc2 =  1;
  }
  x = x1;
  y = y1;

  for (ii = 0; ii < numpixels; ii++)  
  {
    PutPixelInImage(p_image, x, y);
    if (d < 0)
    { 
      d = d + dinc1;
      x = x + xinc1;
      y = y + yinc1;
    }
    else
    {
      d = d + dinc2;
      x = x + xinc2;
      y = y + yinc2;
    }    
  }
  return(1);
}

/**********************************************************************/
/*Linewidht > 1 -> Fill Polygon                                       */
/*Compute Startpoints by going 1/2 Linewidth perpendicular to the     */
/*Linedirection on both Ends of the Line in both Directions, thus     */
/*                                  finding the Corners of the Polygon*/
/**********************************************************************/

int drawLineInImage2(Picture *p_image, int x1, int y1, int x2, int y2,
                                                        int linewidth)
{
  int   x[4], y[4];              /*Memory for the cornaerpoints of the*/
                                 /*Polygon (A thick Line is a filled  */
                 /*Polygon)                           */
  float m_new;                   /*negative rciprocal gradient        */
  float xoffset, yoffset;        /*offsets to the Linestart, Endpoint */
  float lwhalf;                  /*Half of the Linewidth              */

  if(!p_image) return(0); 
  lwhalf = linewidth/2.0f;
  /*negative rciprocal value of the gradient*/  
  if(y2-y1) 
  {
    m_new = (float)(x1-x2)/(float)(y2-y1);
    xoffset = (float)sqrt((float)(lwhalf*lwhalf)/(1+m_new*m_new));
    if(x1-x2) yoffset = xoffset * m_new;
    else      yoffset = 0;
  }
  else
  {
    yoffset = lwhalf;
    xoffset = 0;
  }
  x[0] = NINT(x1+xoffset);
  y[0] = NINT(y1+yoffset);
  x[3] = NINT(x1-xoffset);
  y[3] = NINT(y1-yoffset);
  x[1] = NINT(x2+xoffset);
  y[1] = NINT(y2+yoffset);
  x[2] = NINT(x2-xoffset);
  y[2] = NINT(y2-yoffset);

  return(fillPolygon(p_image, 4, x, y));
}

/**********************************************************************/

int drawLineInImage(Picture *p_image, int x1, int y1, int x2, int y2,
                                                       int linewidth)
{
  if(linewidth < 2) return(drawLineInImage1(p_image, x1, y1, x2, y2));
  else   return(drawLineInImage2(p_image, x1, y1, x2, y2, linewidth));
}

/**********************************************************************/

int drawLineInImageF(Picture *p_image, 
                 float x1, float y1, float x2, float y2, int linewidth)
{
  return(drawLineInImage(p_image, NINT(x1), NINT(y1), NINT(x2), 
                                                NINT(y2), linewidth));
}

/**********************************************************************/
/**********************************************************************/

int drawPolygon(Picture *p_image, 
		int N, 
		int *x, int *y, 
		int closed, 
		int linewidth)
{
  int ii;                       /*Countervariable*/
  if(!p_image)     return(0);
  if((!x) || (!y)) return(0);
  
  for(ii = 0; ii < N-1; ii++)
    {
      drawLineInImage(p_image, x[ii], y[ii], x[ii+1], y[ii+1], 
		      linewidth);
    }
  if((closed) && (N > 2))
    {
      drawLineInImage(p_image, x[N-1], y[N-1], x[0], y[0], linewidth);
    }
  
  return(1);
}

/**********************************************************************/

int drawPolygonF(Picture *p_image, int N, float *x, float *y,int closed,
                                                        int linewidth)
{
  int ii;
  if(!p_image)     return(0);
  if((!x) || (!y)) return(0);
  
  for(ii = 0; ii < N-1; ii++)
  {
    drawLineInImage(p_image, NINT(x[ii]), NINT(y[ii]),
                        NINT(x[ii+1]), NINT(y[ii+1]), linewidth);
  }
  if((closed) && (N > 2))
  {
    drawLineInImage(p_image, NINT(x[N-1]), NINT(y[N-1]),
                             NINT(x[0]), NINT(y[0]), linewidth);
  }
  return(1);
}

/**********************************************************************/
/*Condition Function for QSORT in fillPolygon                         */
/**********************************************************************/

int int_is_larger(const void *va, const void *vb)
{
  int a = *((int*)va);
  int b = *((int*)vb);
  if(a > b) return( 1);
  else      return(-1);
}

/**********************************************************************/
/*Fill Polygon by counting the numner of Intersections in one         */
/*horizontal Line. If odd: inside->fill, if even: outside->dont fill  */
/**********************************************************************/

int fillPolygon(Picture *p_image, int N, int *x, int *y)
{
  int   ii, jj;
  int   no_of_intersect;
  int  *p_intersection;
  float zwfloat;
  
  if(!p_image)     return(0);
  if(!(p_intersection = (int *) malloc(N*sizeof(int))))
  {
    fprintf(stderr, "No Memory to Fill Polygon Size %d\n", N);
    return(0);
  }
  for(ii = 0; ii < (int)p_image->height; ii++)
  {
    no_of_intersect = 0;
    /*Find Intersections of row and lines*/
    for(jj = 0; jj < N-1; jj++)
    {
      if     ((y[jj] <= ii) && (y[jj+1] <= ii)) ;/*No Intersection*/
      else if((y[jj] >  ii) && (y[jj+1] >  ii)) ;/*No Intersection*/
      else   
      {
        zwfloat = (float)(x[jj+1]*(ii-y[jj])+x[jj]*(y[jj+1]-ii))
                                    /
                     (y[jj+1]-y[jj]);
        p_intersection[no_of_intersect++] = NINT(zwfloat);
      }
    }
    if     ((y[N-1] <= ii) && (y[0] <= ii)) ;/*No Intersection*/
    else if((y[N-1] >  ii) && (y[0] >  ii)) ;/*No Intersection*/
    else   
    {
      zwfloat = (float)(x[0]*(ii-y[N-1])+x[N-1]*(y[0]-ii))
                                        /
                                (y[0]-y[N-1]);
      p_intersection[no_of_intersect++] = NINT(zwfloat);
    }
    /*Sort the Intersections*/
    qsort(p_intersection, no_of_intersect, sizeof(int), int_is_larger);
    /*Draw Line from Intersection to intersection*/
    for(jj = 0; jj < no_of_intersect; jj++, jj++)
    {
      drawHorizontalInImage(p_image, ii, p_intersection[jj], 
                                           p_intersection[jj+1]);
    }
  }
  drawPolygon(p_image, N, x, y, 1, 1);

  return(1);
}

/**********************************************************************/

int fillPolygonF(Picture *p_image, int N, float *x, float *y)
{
  int ii;         /*Countervariable                                   */
  int retval;     /*Returnvalue (success)                             */
  int *p_fxy;     /*Cornerpoints in Integerformat xxxxxx...yyyyyyy... */
                  /*                              |   N   ||   N    | */
  
  if(!N) return(1);               /*No Points, Draw OK*/
  if(!x || !y || N<0) return(0);  /*Error             */
  if(!(p_fxy = (int *)malloc(2*N*sizeof(int)))) return(0);
  for(ii = 0; ii < N; ii++)
  {
    p_fxy[ii  ] = NINT(x[ii]);
    p_fxy[ii+N] = NINT(y[ii]);
  }
  retval = fillPolygon(p_image, N, p_fxy, p_fxy+N);
  free(p_fxy);
  return(retval);
}

/**********************************************************************/
/**********************************************************************/
/**********************************************************************/
/*Rectangles of Linewidth 1                                           */
/**********************************************************************/

int drawRectInImage1(Picture *p_image, int x1, int y1, int w, int h)
{
  int ii;                 /*countervariable                           */
  int x2 = x1 + w;        /*Right Edge of the Rectangle               */
  int y2 = y1 + h;        /*Lower Edge of the Rectangle               */
  int maxXval , minXval;  /*Min and Max X- and Y-Values of the        */
  int maxYval , minYval;  /*Rectangle that are still in the Image     */

  if(!p_image) return(0);
  /*switch values to x1 <= x2 and y1 <= y2*/
  if(x1 > x2) {int a; a = x1; x1 = x2; x2 = x1;}
  if(y1 > y2) {int a; a = y1; y1 = y2; y2 = y1;}
  /*if Rect not in Image do nothing, return -1*/
  if((x1>(int)p_image->width) || (y1>(int)p_image->height)) return(-1);
  if((x2 < 0                ) || (y2 < 0                 )) return(-1);
  /*if rectangle larger than image adjust values*/
  maxXval = x2;
  if(x2 >= (int)p_image->width) maxXval = p_image->width-1;
  minXval = x1;
  if(x1 < 0) minXval = 0;
  maxYval = y2;
  if(y2 >= (int)p_image->height) maxYval = p_image->height-1;
  minYval = y1;
  if(y1 < 0) minYval = 0;
  
  if(p_image->format == pix_grey)
  {
    unsigned char *p_data = (unsigned char *)p_image->data;
    /*upper Line*/
    if(y1 >= 0)
      memset(p_data+y1*p_image->width+minXval, MyDrawGrayval, 
                                                       maxXval-minXval);
    /*lower Line*/
    if(y2 < (int)p_image->height)
      memset(p_data+y2*p_image->width+minXval, MyDrawGrayval, 
                                                       maxXval-minXval);
    /*left Line*/
    if(x1 >= 0)
      for(ii = minYval; ii <= maxYval; ii++)
        p_data[ii*p_image->width+x1] = MyDrawGrayval;
    /*right Line*/
    if(x2 < (int)p_image->width)
      for(ii = minYval; ii <= maxYval; ii++)
        p_data[ii*p_image->width+x2] = MyDrawGrayval;
  }
  
  else if(p_image->format == pix_rgb24)
  {
    unsigned char *p_data = (unsigned char *)p_image->data;
    /*upper Line*/
    if(y1 >= 0)
      for(ii = minXval; ii <= maxXval; ii++)
      {
        p_data[3*(y1*p_image->width+ii) + 0] = MyDrawColor[0];
        p_data[3*(y1*p_image->width+ii) + 1] = MyDrawColor[1];
        p_data[3*(y1*p_image->width+ii) + 2] = MyDrawColor[2];
      }
    /*lower Line*/
    if(y2 < (int)p_image->height)
      for(ii = minXval; ii <= maxXval; ii++)
      {
        p_data[3*(y2*p_image->width+ii) + 0] = MyDrawColor[0];
        p_data[3*(y2*p_image->width+ii) + 1] = MyDrawColor[1];
        p_data[3*(y2*p_image->width+ii) + 2] = MyDrawColor[2];
      }
    /*left Line*/
    if(x1 >= 0)
      for(ii = minYval; ii <= maxYval; ii++)
      {
        p_data[3*(ii*p_image->width+x1) + 0] = MyDrawColor[0];
        p_data[3*(ii*p_image->width+x1) + 1] = MyDrawColor[1];
        p_data[3*(ii*p_image->width+x1) + 2] = MyDrawColor[2];
      }
    /*right Line*/
    if(x2 < (int)p_image->width)
      for(ii = minYval; ii <= maxYval; ii++)
      {
        p_data[3*(ii*p_image->width+x2) + 0] = MyDrawColor[0];
        p_data[3*(ii*p_image->width+x2) + 1] = MyDrawColor[1];
        p_data[3*(ii*p_image->width+x2) + 2] = MyDrawColor[2];
      }
  }
  else 
  {
    fprintf(stderr, 
      "drawRectInImage not implemented for Imagetype %d yet\n"
                                                , p_image->format);
    return(0);
  }
  return(1);
}

/**********************************************************************/
/*Rectangles with Linewidth > 1                                       */
/**********************************************************************/

int drawRectInImage2(Picture *p_image, int x1, int y1, int w, int h, 
                                                      int linewidth)
{
  int   ii, jj;           /*countervariable                           */
  int   x2 = x1 + w;      /*Right Edge of the Rectangle               */
  int   y2 = y1 + h;      /*Lower Edge of the Rectangle               */
  int   maxXval , minXval;/*Min and Max X- and Y-Values of the        */
  int   maxYval , minYval;/*Rectangle that are still in the Image     */
  int   lwhalf;           /*Half of the Linewidth                     */
  
  /*Only uneven Values for linewidth are possible*/
  if(linewidth < 0) return(-1);
  linewidth = 2*(linewidth/2) + 1;
  lwhalf = linewidth/2;
  if(!p_image) return(0);
  /*switch values to x1 <= x2 and y1 <= y2*/
  if(x1 > x2) {int a; a = x1; x1 = x2; x2 = x1;}
  if(y1 > y2) {int a; a = y1; y1 = y2; y2 = y1;}
  /*if Rect not in Image do nothing, return -1*/
  if((x1>(int)p_image->width) || (y1>(int)p_image->height)) return(-1);
  if((x2 < 0             ) || (y2 < 0              )) return(-1);
  /*if rectangle larger than image adjust values*/
  maxXval = x2;
  if(x2 >= (int)p_image->width) maxXval = p_image->width-1;
  minXval = x1;
  if(x1 < 0) minXval = 0;
  maxYval = y2;
  if(y2 >= (int)p_image->height) maxYval = p_image->height-1;
  minYval = y1;
  if(y1 < 0) minYval = 0;
  /*Fill the Corners produced by the thick Lines*/
  if((minXval - lwhalf) >= 0)            minXval -= lwhalf-1;
  else                                   minXval = 0;
  if((maxXval+lwhalf)<(int)p_image->width) maxXval += lwhalf;
  else                                   maxXval  = (int)p_image->width;

  if(p_image->format == pix_grey)
  {
    unsigned char *p_data = (unsigned char *)p_image->data;
    for(ii = -lwhalf; ii <= lwhalf; ii++)
    {
      /*upper Line*/
      if(((y1+ii) >= 0) && ((y1+ii) < (int)p_image->height))
        memset(p_data+(y1+ii)*p_image->width+minXval, 
                           MyDrawGrayval, maxXval-minXval);
      /*lower Line*/
      if(((y2+ii) >= 0) && ((y2+ii) < (int)p_image->height))
        memset(p_data+(y2+ii)*p_image->width+minXval, 
                        MyDrawGrayval,maxXval-minXval);
      /*left Line*/
      if(((x1+ii) >= 0) && ((x1+ii) < (int)p_image->width))
        for(jj = minYval; jj <= maxYval; jj++)
          p_data[jj*p_image->width+x1+ii] = MyDrawGrayval;
      /*right Line*/
      if(((x1+ii) >= 0) && ((x1+ii) < (int)p_image->width))
        for(jj = minYval; jj <= maxYval; jj++)
          p_data[jj*p_image->width+x2+ii] = MyDrawGrayval;
    }
  }
  else if(p_image->format == pix_rgb24)
  {
    unsigned char *p_data = (unsigned char *)p_image->data;
    for(ii = -lwhalf; ii <= lwhalf; ii++)
    {
      /*upper Line*/
      if(((y1+ii) >= 0) && ((y1+ii) < (int)p_image->height))
      {
        for(jj = minXval; jj <= maxXval; jj++)
        {
          p_data[3*((y1+ii)*p_image->width+jj) + 0] = MyDrawColor[0];
          p_data[3*((y1+ii)*p_image->width+jj) + 1] = MyDrawColor[1];
          p_data[3*((y1+ii)*p_image->width+jj) + 2] = MyDrawColor[2];
        }
      }
      /*lower Line*/
      if(((y2+ii) >= 0) && ((y2+ii) < (int)p_image->height))
      {
        for(jj = minXval; jj <= maxXval; jj++)
        {
          p_data[3*((y2+ii)*p_image->width+jj) + 0] = MyDrawColor[0];
          p_data[3*((y2+ii)*p_image->width+jj) + 1] = MyDrawColor[1];
          p_data[3*((y2+ii)*p_image->width+jj) + 2] = MyDrawColor[2];
        }
      }
      /*left Line*/
      if(((x1+ii) >= 0) && ((x1+ii) < (int)p_image->width))
      {
        for(jj = minYval; jj <= maxYval; jj++)
        {
          p_data[3*(jj*p_image->width+(x1+ii)) + 0] = MyDrawColor[0];
          p_data[3*(jj*p_image->width+(x1+ii)) + 1] = MyDrawColor[1];
          p_data[3*(jj*p_image->width+(x1+ii)) + 2] = MyDrawColor[2];
        }
      }
      /*right Line*/
      if(((x2+ii) >= 0) && ((x2+ii) < (int)p_image->width))
      {
        for(jj = minYval; jj <= maxYval; jj++)
        {
          p_data[3*(jj*p_image->width+(x2+ii)) + 0] = MyDrawColor[0];
          p_data[3*(jj*p_image->width+(x2+ii)) + 1] = MyDrawColor[1];
          p_data[3*(jj*p_image->width+(x2+ii)) + 2] = MyDrawColor[2];
        }
      }
    }
  }
  else 
  {
    fprintf(stderr, 
      "drawRectInImage2 not implemented for Imagetype %d yet\n"
                                                , p_image->format);
    return(0);
  }
  return(1);
}

/**********************************************************************/

int drawRectInImage(Picture *p_image, int x1, int y1, int w, int h, 
                                                      int linewidth)
{
  if(linewidth > 1)
    return(drawRectInImage2(p_image, x1, y1, w, h, linewidth));
  else
    return(drawRectInImage1(p_image, x1, y1, w, h));
}

/**********************************************************************/

int drawRectInImageF(Picture *p_image, float x1, float y1,  
                                     float w, float h, int linewidth)
{
  if(NINT(x1+w) > (NINT(x1)+NINT(w)))
  { 
    if((x1-(int)(x1)) > (w-(int)(w))) x1 += 1;
    else                              w  += 1;
  }
  else if(NINT(x1+w) < (NINT(x1)+NINT(w)))
  {
    if((x1-(int)(x1)) > (w-(int)(w))) w  -= 1;
    else                              x1 -= 1;
  }
  if(NINT(y1+h) > (NINT(y1)+NINT(h)))
  { 
    if((y1-(int)(y1)) > (h-(int)(h))) y1 += 1;
    else                              h  += 1;
  }
  else if(NINT(y1+h) < (NINT(y1)+ NINT(h)))
  {
    if((y1-(int)(y1)) > (h-(int)(h))) h  -= 1;
    else                              y1 -= 1;
  }
  return(drawRectInImage(p_image, NINT(x1), NINT(y1),  
                                     NINT(w), NINT(h), linewidth));
}

/**********************************************************************/

int fillRectInImage(Picture *p_image, int x1, int y1, int w, int h)
{
  int ii, jj;           /*countervariable                           */
  int x2 = x1 + w;      /*Right Edge of the Rectangle               */
  int y2 = y1 + h;      /*Lower Edge of the Rectangle               */
  int maxXval , minXval;/*Min and Max X- and Y-Values of the        */
  int maxYval , minYval;/*Rectangle that are still in the Image     */
  
  if(!p_image) return(0);
  /*switch values to x1 <= x2 and y1 <= y2*/
  if(x1 > x2) {int a; a = x1; x1 = x2; x2 = x1;}
  if(y1 > y2) {int a; a = y1; y1 = y2; y2 = y1;}
  /*if Rect not in Image do nothing, return -1*/
  if((x1>(int)p_image->width) || (y1>(int)p_image->height)) return(-1);
  if((x2 < 0             ) || (y2 < 0              )) return(-1);
  /*if rectangle larger than image adjust values*/
  maxXval = x2;
  if(x2 >= (int)p_image->width) maxXval = p_image->width-1;
  minXval = x1;
  if(x1 < 0) minXval = 0;
  maxYval = y2;
  if(y2 >= (int)p_image->height) maxYval = p_image->height-1;
  minYval = y1;
  if(y1 < 0) minYval = 0;
  
  if(p_image->format == pix_grey)
  {
    unsigned char *p_data = (unsigned char *)p_image->data;
    for(ii = minYval; ii <= maxYval; ii++)
    {
      memset(p_data+ii*p_image->width+minXval, MyDrawGrayval, 
                                                       maxXval-minXval);
    } 
  }
  
  else if(p_image->format == pix_rgb24)
  {
    unsigned char *p_data = (unsigned char *)p_image->data;
    for(ii = minYval; ii <= maxYval; ii++)
    {
      for(jj = minXval; jj <= maxXval; jj++)
      {
        p_data[3*(ii*p_image->width+jj) + 0] = MyDrawColor[0];
        p_data[3*(ii*p_image->width+jj) + 1] = MyDrawColor[1];
        p_data[3*(ii*p_image->width+jj) + 2] = MyDrawColor[2];
      }
    } 
  }
  else 
  {
    fprintf(stderr, 
      "fillRectInImage not implemented for Imagetype %d yet\n"
                                                , p_image->format);
    return(0);
  }
  return(1);
}

/**********************************************************************/

int fillRectInImageF(Picture *p_image, float x, float y, float w, float h)
{
  if(NINT(x+w) > (NINT(x)+NINT(w)))
  { 
    if((x-(int)(x)) > (w-(int)(w))) x += 1;
    else                            w += 1;
  }
  else if(NINT(x+w) < (NINT(x)+NINT(w)))
  {
    if((x-(int)(x)) > (w-(int)(w))) w  -= 1;
    else                            x -= 1;
  }
  if(NINT(y+h) > (NINT(y)+NINT(h)))
  { 
    if((y-(int)(y)) > (h-(int)(h))) y += 1;
    else                            h  += 1;
  }
  else if(NINT(y+h) < (NINT(y)+ NINT(h)))
  {
    if((y-(int)(y)) > (h-(int)(h))) h  -= 1;
    else                            y -= 1;
  }
  return(fillRectInImage(p_image, NINT(x), NINT(y),  
                                     NINT(w), NINT(h)));
}

/**********************************************************************/
/**********************************************************************/

int drawCircleInImage(Picture *p_image, int cx, int cy, int R, 
                                                         int linewidth)
{
  int d;     /*Auxiliary                                              */
  int x, y;  /*Edgepoint of the Circle arround (0/0)                  */
  
  if(!p_image) return(0);
  
  if(linewidth < 2) linewidth = 0;
  
  d = 3 - (2 * R);
  x = 0;
  y = R;
  for(x = 0; x < R; x++)
  { 
    if(!linewidth)
    {
      PutPixelInImage(p_image, cx + x, cy + y);
      PutPixelInImage(p_image, cx + x, cy - y);
      PutPixelInImage(p_image, cx - x, cy + y);
      PutPixelInImage(p_image, cx - x, cy - y);
      PutPixelInImage(p_image, cx + y, cy + x);
      PutPixelInImage(p_image, cx + y, cy - x);
      PutPixelInImage(p_image, cx - y, cy + x);
      PutPixelInImage(p_image, cx - y, cy - x);
    }
    else
    {
      PutBigPixelInImage(p_image, cx + x, cy + y, linewidth);
      PutBigPixelInImage(p_image, cx + x, cy - y, linewidth);
      PutBigPixelInImage(p_image, cx - x, cy + y, linewidth);
      PutBigPixelInImage(p_image, cx - x, cy - y, linewidth);
      PutBigPixelInImage(p_image, cx + y, cy + x, linewidth);
      PutBigPixelInImage(p_image, cx + y, cy - x, linewidth);
      PutBigPixelInImage(p_image, cx - y, cy + x, linewidth);
      PutBigPixelInImage(p_image, cx - y, cy - x, linewidth);
    }
    if (d < 0)
    {
      d += (4 * x) + 6;
    }
    else
    {
      d += 4 * (x - y) + 10;
      y  = y - 1;
    }
    if(x >= y) break;
  }
  return(1);
}

/**********************************************************************/

int fillCircleInImage(Picture *p_image, int cx, int cy, int R)
{
  int d;     /*Auxiliary                                              */
  int x, y;  /*Edgepoint of the Circle arround (0/0)                  */

  if(!p_image) return(0);
  
  d = 3 - (2 * R);
  x = 0;
  y = R;
  for(x = 0; x < R; x++)
  { 
    drawHorizontalInImage(p_image, cy + y, cx - x, cx + x + 1);
    drawHorizontalInImage(p_image, cy - y, cx - x, cx + x + 1);
    drawHorizontalInImage(p_image, cy + x, cx - y, cx + y + 1);
    drawHorizontalInImage(p_image, cy - x, cx - y, cx + y + 1);

    if (d < 0)
    {
      d += (4 * x) + 6;
    }
    else
    {
      d += 4 * (x - y) + 10;
      y  = y - 1;
    }
    if(x >= y) break;
  }
  return(1);
}

/**********************************************************************/

int drawEllipseInImage(Picture *p_image, int cx, int cy, 
                                 int R1, int R2, int linewidth)
{
  int   x, y;     /*Edgepoint of the Ellipse arround (0/0)            */
  float turnpoint;/*Point from where on the gradient is > PI/4        */
  
  if(linewidth < 2) linewidth = 0;
  if(!p_image) return(0);

  /*Point d/dx = d/dy is x = sqrt(R1^4 / (R2^2 + R1^2))*/
  /*                     y = sqrt(R1^4 / (R2^2 + R1^2))*/
  turnpoint = (float)sqrt((float)(R1*R1*R1*R1)/(R1*R1+R2*R2));
  for(x = 0; (float)x < turnpoint; x++)
  { 
    y = NINT(R2/(float)(R1) * sqrt(R1 * R1 - x * x));
    if(!linewidth)
    {
      PutPixelInImage(p_image, cx + x, cy + y);
      PutPixelInImage(p_image, cx + x, cy - y);
      PutPixelInImage(p_image, cx - x, cy + y);
      PutPixelInImage(p_image, cx - x, cy - y);
    }
    else
    {
      PutBigPixelInImage(p_image, cx + x, cy + y, linewidth);
      PutBigPixelInImage(p_image, cx + x, cy - y, linewidth);
      PutBigPixelInImage(p_image, cx - x, cy + y, linewidth);
      PutBigPixelInImage(p_image, cx - x, cy - y, linewidth);
    }
  }
  turnpoint = (float)sqrt((float)(R2*R2*R2*R2)/(R1*R1+R2*R2));
  for(y = 0; (float)y < turnpoint; y++)
  { 
    x = NINT(R1/(float)(R2) * sqrt(R2 * R2 - y * y));
    if(!linewidth)
    {
      PutPixelInImage(p_image, cx + x, cy + y);
      PutPixelInImage(p_image, cx + x, cy - y);
      PutPixelInImage(p_image, cx - x, cy + y);
      PutPixelInImage(p_image, cx - x, cy - y);
    }
    else
    {
      PutBigPixelInImage(p_image, cx + x, cy + y, linewidth);
      PutBigPixelInImage(p_image, cx + x, cy - y, linewidth);
      PutBigPixelInImage(p_image, cx - x, cy + y, linewidth);
      PutBigPixelInImage(p_image, cx - x, cy - y, linewidth);
    }
  }
  return(1);
}

/**********************************************************************/

int fillEllipseInImage(Picture *p_image, int cx, int cy, int R1, int R2)
{
  int   x, y;     /*Edgepoint of the Ellipse arround (0/0)            */
  float turnpoint;/*Point from where on the gradient is > PI/4        */

  if(!p_image) return(0);

  /*Point d/dx = d/dy is x = sqrt(R1^4 / (R2^2 + R1^2))*/
  /*                     y = sqrt(R1^4 / (R2^2 + R1^2))*/
  turnpoint = (float)sqrt((float)(R1*R1*R1*R1)/(R1*R1+R2*R2));
  for(x = 0; (float)x < turnpoint; x++)
  { 
    y = NINT(R2/(float)(R1) * sqrt(R1 * R1 - x * x));
    drawHorizontalInImage(p_image, cy + y, cx - x, cx + x + 1);
    drawHorizontalInImage(p_image, cy - y, cx - x, cx + x + 1);
  }
  turnpoint = (float)sqrt((float)(R2*R2*R2*R2)/(R1*R1+R2*R2));
  for(y = 0; (float)y < turnpoint; y++)
  { 
    x = NINT(R1/(float)(R2) * sqrt(R2 * R2 - y * y));
    drawHorizontalInImage(p_image, cy + y, cx - x, cx + x + 1);
    drawHorizontalInImage(p_image, cy - y, cx - x, cx + x + 1);
  }
  return(1);
}


/**********************************************************************/
/**********************************************************************/
/**********************************************************************/


int drawStringInImage(Picture *p_image, int x,int y, const char *p_string,
                       MyFont *p_font, int red, int green, int blue,
                 int spacing, int resizeimg, unsigned char bgnd)
{
  int    ii;            /*Countervariable                             */
  int    length;        /*Number of characters in the String          */
  int    w = 0;         /*Width of the String in the Image            */
  int    r, g, b, gray; /*Memory for the standard-Drawdolors, Grayval */
  Picture *p_char;        /*Image of one Letter to be set               */
  
  r    = MyDrawColor[0];
  g    = MyDrawColor[1];
  b    = MyDrawColor[2];
  gray = MyDrawGrayval;

  if(!p_image || !p_string || !p_font) return(0);
  length = strlen(p_string);
  setDrawColorImageR(0);
  setDrawColorImageG(0);
  setDrawColorImageB(0);
  setDrawGValImage(0);

  for(ii = 0; ii < length; ii++)  
  {
    if(p_image->format == pix_grey)
    {
      if((red+green+blue/3) == 0) /*Black Font*/
      {
        p_char = invertImage(getCharImage(p_font,p_string[ii]));
        setDrawGValImage(0);
      }
      else
      {
        p_char = ReGrayImage(getCharImage(p_font,p_string[ii]),
                                           red+green+blue/3);
      }
    }
    else if(p_image->format == pix_rgb24)
    {
      if((red == 0) || (green == 0) || (blue == 0))/*Black Font*/
      {
    p_char =  invertImage(getCharImage(p_font,p_string[ii]));
        setDrawColorImageR(255);
        setDrawColorImageG(255);
        setDrawColorImageB(255);
      }
      else
      {
        p_char = ReColorImage(getCharImage(p_font,p_string[ii]),
                                           red, green, blue);
      }
    }
    else
    {
      fprintf(stderr, 
        "drawString not implemented for Type %d yet\n",p_image->format); 
      return(0);
    }
    if(p_char)
    {
      if(resizeimg)
      {  
        putImageInImageOverlay(p_image,p_char,x+w, y, 1, 0, bgnd);
      }
      else
      {
        putImageInImageOverlay(p_image,p_char,x+w, y, 1, 0, 128);
      }
    }
    w += getFontCharWidth(p_font, p_string[ii]) + spacing;
    if(p_char) freeImage(p_char);
  }
  MyDrawColor[0] = (unsigned char)r;
  MyDrawColor[1] = (unsigned char)g;
  MyDrawColor[2] = (unsigned char)b;
  MyDrawGrayval  = (unsigned char)gray;
  return(w);
}

/**********************************************************************/

int drawStringInImageF(Picture *p_image, float x,float y, 
                  const char *p_string, MyFont *p_font, 
          int red, int green, int blue,
          int spacing, int resizeimg, unsigned char bgnd)
{
  return(drawStringInImage(p_image, NINT(x), NINT(y), p_string, p_font,
                  red, green, blue, spacing, resizeimg, bgnd));
}


/**********************************************************************/



