/*
Copyright (c) 2004-2010, Dirk Krause
All rights reserved.

Redistribution and use in source and binary forms,
with or without modification, are permitted provided
that the following conditions are met:

* Redistributions of source code must retain the above
  copyright notice, this list of conditions and the
  following disclaimer.
* Redistributions in binary form must reproduce the above 
  opyright notice, this list of conditions and the following
  disclaimer in the documentation and/or other materials
  provided with the distribution.
* Neither the name of the Dirk Krause nor the names of
  contributors may be used to endorse or promote
  products derived from this software without specific
  prior written permission.

THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND
CONTRIBUTORS "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES,
INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF
MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
DISCLAIMED.
IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE
LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE
OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH
DAMAGE.
*/



/**	@file	dkfigmp.c	MP output driver module.
*/



/**	Inside the dkfigmp module.
*/
#define DKFIGMP_C 1



#include "dkfig.h"




#line 55 "dkfigmp.ctr"




/**	Restrict digits after decimal dot for double value.
*/
#define drd(v,o,w) dkfig_tool2_drd(v,o,w)




#line 66 "dkfigmp.ctr"



#if TRACE_DEBUG

/**	Issue debugging output about a Bezier point.
	@param	bp	Bezier point structure.
*/
static void
trace_bezier_point DK_P1(dk_fig_bezier_point *,bp)
{
  FILE *f;
  f = dktrace_file();
  if(f) {
    fprintf(f, "value:    x=%lg y=%lg\n", (bp->value).x, (bp->value).y);
    fprintf(f, "lcontrol: x=%lg y=%lg\n", (bp->lcontrol).x, (bp->lcontrol).y);
    fprintf(f, "rcontrol: x=%lg y=%lg\n", (bp->rcontrol).x, (bp->rcontrol).y);
  }
}

#endif



#ifndef TR_PTR
/** Trace output macro for pointer. */
#define TR_PTR(x) ((x) ? "PTR" : "(NULL)")
#endif



/**	Flag: Linewidth known.
*/
#define HAVE_LINEWIDTH		 1

/**	Flag: Linecap known.
*/
#define HAVE_LINECAP		 2

/**	Flag: Linejoin known.
*/
#define HAVE_LINEJOIN		 4

/**	Flag: Arrowhead length known.
*/
#define HAVE_AHLENGTH		 8

/**	Flag: Arrowhead angle known.
*/
#define HAVE_AHANGLE		16




/**	Pointer to characters.
*/
typedef char *PCHAR;



/**	Keywords for MetaPost output. */
static char *keywords[] = {
  /*  0 */ "\n",
  /*  1 */ " ",
  /*  2 */ "(",
  /*  3 */ ")",
  /*  4 */ ";",
  /*  5 */ ",",
  /*  6 */ "--",
  /*  7 */ "..",
  /*  8 */ "+",
  /*  9 */ "-",
  /* 10 */ "0",
  /* 11 */ "1",
  /* 12 */ "=",
  /* 13 */ "prologues",
  /* 14 */ ":",
  /* 15 */ "verbatimtex",
  /* 16 */ "%&latex",
  /* 17 */ "&tex",
  /* 18 */ "etex",
  /* 19 */ "%",
  /* 20 */ "line",
  /* 21 */ "\"",
  /* 22 */ "beginfig",
  /* 23 */ "endfig;",
  /* 24 */ "end",
  /* 25 */ "path",
  /* 26 */ "picture",
  /* 27 */ "p",
  /* 28 */ "q",
  /* 29 */ "btex",
  /* 30 */ "{",
  /* 31 */ "}",
  /* 32 */ "\\mbox",
  /* 33 */ "label",
  /* 34 */ ".",
  /* 35 */ "top",
  /* 36 */ "ulft",
  /* 37 */ "urt",
  /* 38 */ "rotated",
  /* 39 */ "r",
  /* 40 */ "*",
  /* 41 */ "10**",
  /* 42 */ "llcorner",
  /* 43 */ "withcolor",
  /* 44 */ "pair",
  /* 45 */ "s",
  /* 46 */ "xpart",
  /* 47 */ "lrcorner",
  /* 48 */ "infont",
  /* 49 */ "scaled",
  /* 50 */ "pt",
  /* 51 */ "/",
  /* 52 */ "fontsize",
  /* 53 */ "defaultfont",
  /* 54 */ "\\n",
  /* 55 */ "\\\"",
  /* 56 */ "yscaled",
  /* 57 */ "shifted",
  /* 58 */ "fullcircle",
  /* 59 */ "cycle",
  /* 60 */ "down",
  /* 61 */ "right",
  /* 62 */ "up",
  /* 63 */ "left",
  /* 64 */ "controls",
  /* 65 */ "and",
  /* 66 */ "cutafter",
  /* 67 */ "fill",
  /* 68 */ "color",
  /* 69 */ "c",
  /* 70 */ "draw",
  /* 71 */ "pickup",
  /* 72 */ "pencircle",
  /* 73 */ "bp",
  /* 74 */ "linecap",
  /* 75 */ ":=",
  /* 76 */ "2",
  /* 77 */ "linejoin",
  /* 78 */ "a",
  /* 79 */ "arrowhead",
  /* 80 */ "reverse",
  /* 81 */ "white",
  /* 82 */ "ahlength",
  /* 83 */ "ahangle",
  /* 84 */ "nullpicture",
  /* 85 */ "clip",
  /* 86 */ "to",
  /* 87 */ "addto",
  /* 88 */ "currentpicture",
  /* 89 */ "also",
  /* 90 */ "dashed",
  /* 91 */ "dashpattern",
  /* 92 */ "on",
  /* 93 */ "off",
  /* 94 */ "doublepath",
  /* 95 */ "withpen",
  /* 96 */ "o",
  /* 97 */ "pen",
  /* 98 */ "(0,0)",
  /* 99 */ "produced by fig2vect\0, see http://dktools.sourceforge.net/fig2vect.html",
 /* 100 */ "labeloffset:=0;bbmargin:=0;",
 /* 101 */ ".0",
 /* 102 */ "mp",
 /* 103 */ "% fill bounding box",
 /* 104 */ "% background rectangle removed",
 /* 105 */ "black",
 /* 106 */ "withgreyscale",

  NULL
};

/**	Number of keywods in the array (including final NULL pointer).
*/
static size_t number_of_keywords = sizeof(keywords)/sizeof(PCHAR);



/**	Write one keyword to output stream.
	@param	strm	Destination stream.
	@param	index	Keyword index.
*/
static void
kw_to_stream DK_P2(dk_stream_t *,strm, size_t,index)
{
  if(index < number_of_keywords) {
    dkstream_puts(strm, keywords[index]);
  }
}



/**	Write double value to stream, convert for
	MetaPost representation if neccesary.
	(i.e. 3.5e8 -> (3.5*(10**8)) )
	@param	s	Output stream.
	@param	d	Double value to write.
	@param	iscoord	Flag: Is coordinate.
	@param	c	Conversion job structure.
*/
static void
stream_puts_double DK_P4(dk_stream_t *,s, double,d, int, iscoord, dk_fig_conversion *,c)
{
  char buffer[32], *eptr, *dotptr;
#if DK_HAVE_SNPRINTF
  snprintf(buffer, sizeof(buffer), "%lg", drd(d, c, iscoord));
  buffer[sizeof(buffer)-1] = '\0';
#else
  sprintf(buffer, "%lg", drd(d, c, iscoord));
#endif
  eptr = strchr(buffer, 'e');
  if(!eptr) { eptr = strchr(buffer, 'E'); }
  if(eptr) {
    dotptr = strchr(buffer, '.');
    *(eptr++) = '\0';
    kw_to_stream(s, 2);
    dkstream_puts(s, buffer);
    if(iscoord) {
      if(!dotptr) {
        kw_to_stream(s, 101);
      }
    }
    kw_to_stream(s, 40);
    kw_to_stream(s, 2);
    kw_to_stream(s, 41);
    if(*eptr == '-') {
      kw_to_stream(s, 2);
    }
    dkstream_puts(s, eptr);
    if(*eptr == '-') {
      kw_to_stream(s, 3);
    }
    kw_to_stream(s, 3);
    kw_to_stream(s, 3);
  } else {
    dotptr = strchr(buffer, '.');
    dkstream_puts(s, buffer);
    if(iscoord) {
      if(!dotptr) {
        kw_to_stream(s, 101);
      }
    }
  }
}



/**	Convert coordinate x (double value) from fig to MP.
	@param	c	Conversion job structure.
	@param	x	Value to convert.
	@return	Converted x value.
*/
static double
ccd_x DK_P2(dk_fig_conversion *,c, double,x)
{
  double back = 0.0;
  dk_fig_output_mp *mpo;
  
  mpo = (dk_fig_output_mp *)(c->outds);
  if(mpo) {
    back = mpo->mx * x + mpo->nx;
  } else {
    back = 0.06 * x;
  } 
  return back;
}



/**	Convert coordinate y (double value) from fig to MP.
	@param	c	Conversion job structure.
	@param	y	Value to convert.
	@return	Converted y value.
*/
static double 
ccd_y DK_P2(dk_fig_conversion *,c, double,y)
{
  double back = 0.0;
  dk_fig_output_mp *mpo;
  
  mpo = (dk_fig_output_mp *)(c->outds);
  if(mpo) {
    back = mpo->my * y + mpo->ny;
  } else {
    back = -0.06 * y;
  } 
  return back;
}



/**	Convert coordinate x (long value) from fig to MP.
	@param	c	Conversion job structure.
	@param	x	Value to convert.
	@return	Converted x value.
*/
static double
cc_x DK_P2(dk_fig_conversion *,c, long,x)
{
  double back = 0.0;
  dk_fig_output_mp *mpo;
  
  mpo = (dk_fig_output_mp *)(c->outds);
  if(mpo) {
    back = mpo->mx * dkma_l_to_double(x) + mpo->nx;
  } else {
    back = 0.06 * dkma_l_to_double(x);
  } 
  return back;
}



/**	Convert coordinate y (long value) from fig to MP.
	@param	c	Conversion job structure.
	@param	y	Value to convert.
	@return	Converted y value.
*/
static double 
cc_y DK_P2(dk_fig_conversion *,c, long,y)
{
  double back = 0.0;
  dk_fig_output_mp *mpo;
  
  mpo = (dk_fig_output_mp *)(c->outds);
  if(mpo) {
    back = mpo->my * dkma_l_to_double(y) + mpo->ny;
  } else {
    back = -0.06 * dkma_l_to_double(y);
  } 
  return back;
}



/**	Convert a distance (long value) from Fig to MetaPost.
	@param	c	Conversion job structure.
	@param	x	Distance to convert.
	@return	Converted distance value.
*/
static double
cc_radius DK_P2(dk_fig_conversion *,c, long,x)
{
  double back = 0.0;
  dk_fig_output_mp *mpo;
  
  mpo = (dk_fig_output_mp *)(c->outds);
  if(mpo) {
    back = mpo->mx * dkma_l_to_double(x);
  } else {
    back = 0.06 * dkma_l_to_double(x);
  } 
  return back;
}



/**	Convert a distance/radius (double value) from Fig to MetaPost.
	@param	c	Conversion job structure.
	@param	r	Radius to convert.
	@return	Converted radius/distance.
*/
static double
ccd_radius DK_P2(dk_fig_conversion *,c, double,r)
{
  double back = 0.0;
  dk_fig_output_mp *mpo;
  mpo = (dk_fig_output_mp *)(c->outds);
  if(mpo) {
    back = mpo->mx * r;
  } else {
    back = 0.06 * r;
  }
  return back;
}



/**	Convert a bounding box from Fig to MetaPost.
	@param	c	Conversion job structure.
	@param	dst	Destination bounding box structure.
	@param	src	Source bounding box structure.
*/
static void
cc_bb DK_P3(dk_fig_conversion *,c, dk_fig_bb *,dst, dk_fig_bb *,src)
{
  
  dkfig_tool_bb_reset(dst);
  dkfig_tool_bb_add_x(dst, ccd_x(c, src->xmin));
  dkfig_tool_bb_add_x(dst, ccd_x(c, src->xmax));
  dkfig_tool_bb_add_y(dst, ccd_y(c, src->ymin));
  dkfig_tool_bb_add_y(dst, ccd_y(c, src->ymax));
  
}



/**	Convert line width from Fig to MetaPost, ignore
	"lighten look" option.
	@param	c	Conversion job structure.
	@param	l	Linewidth in Fig linewidth units.
	@return	Linewidth converted to MetaPost.
*/
static double 
cc_noenl_linewidth DK_P2(dk_fig_conversion *,c, long,l)
{
  double back = 0.0;
  
  back = dkma_l_to_double(l);
  /* back = (back / 10.0) * 9.0 */
  back = 0.9 * back;
  
  return back;
}



/**	Write point given in MetaPost co-ordinates to output stream.
	@param	oi	MetaPost output instruction structure.
	@param	x	X coordinate.
	@param	y	y coordinate.
	@param	w	Number of digits after decimal dot.
*/
static void
write_noconv_double_point DK_P4(dkfig_mp_output_instruction *,oi, double,x, double,y, int,w)
{
  
  kw_to_stream(oi->s, 2);
  stream_puts_double(oi->s, x, w, oi->c);
  kw_to_stream(oi->s, 5);
  stream_puts_double(oi->s, y, w, oi->c);
  kw_to_stream(oi->s, 3);
  
}



/**	Write point data given in Fig coordinates (long values).
	@param	oi	MetaPost output instruction structure.
	@param	x	x coordinate.
	@param	y	y coordinate.
*/
static void
write_long_point DK_P3(dkfig_mp_output_instruction *,oi, long,x, long,y)
{
  
  write_noconv_double_point(oi, cc_x(oi->c, x), cc_y(oi->c, y), 1);
  
}



/**	Write point data given in Fig coordinates (double values).
	@param	oi	MetaPost output instruction structure.
	@param	x	x coordinate.
	@param	y	y coordinate.
	@param	w	Number of digits after decimal dot.
*/
static void
write_double_point DK_P4(dkfig_mp_output_instruction *,oi, double,x, double,y, int,w)
{
  
  write_noconv_double_point(oi, ccd_x(oi->c, x), ccd_y(oi->c, y), w);
  
}



/**	Check whether to use colored or grayscaled output.
	@param	c	Conversion job structure.
	@return	1 for colored output, 0 for grayscaled output.
*/
static
int
can_use_color DK_P1(dk_fig_conversion *,c) {
  int back = 1;
  if(c) {
    if(!((c->opt2) & DKFIG_OPT_COLOR)) {
      back = 0;
    }
  }
  return back;
}


/**	Write color cell RGB-triple to output stream.
	@param	os	Output stream.
	@param	dcc	Color cell.
	@param	c	Conversion job structure.

*/
static void
write_dcc_data DK_P3(dk_stream_t *,os, dk_fig_dcc *,dcc, dk_fig_conversion *,c)
{
  double g;
  if(can_use_color(c)) {
    kw_to_stream(os, 2);
    stream_puts_double(os, drd(dcc->red, c, 0), 0, c);
    kw_to_stream(os, 5);
    stream_puts_double(os, drd(dcc->green, c, 0), 0, c);
    kw_to_stream(os, 5);
    stream_puts_double(os, drd(dcc->blue, c, 0), 0, c);
    kw_to_stream(os, 3);
  } else {
    g = 0.3 * dcc->red + 0.59 * dcc->green + 0.11 * dcc->blue;
    g = drd(g, c, 0);
    if(g > 0.0) {
      if(g >= 1.0) {
        kw_to_stream(os, 81);
      } else {
        kw_to_stream(os, 2);
        stream_puts_double(os, g, 0, c);
        kw_to_stream(os, 40);
        kw_to_stream(os, 81);
        kw_to_stream(os, 3);
      }
    } else {
      kw_to_stream(os, 105);
    }
  }
}



/**	Write gray value for color cell to output stream.
	@param	os	Output stream.
	@param	dcc	Color cell.
	@param	c	Conversion job structure.
*/
static
void
write_dcc_gray DK_P3(dk_stream_t *,os, dk_fig_dcc *,dcc, dk_fig_conversion *,c) {
  double g;
  g = 0.3 * dcc->red + 0.59 * dcc->green + 0.11 * dcc->blue;
  g = drd(g, c, 0);
  stream_puts_double(os, g, 0, c);
}



/**	Output UTF-8 encoded text encoded for mp.
	@param	c	Conversion job structure.
	@param	os	Output stream.
	@param	t	Text to print.

*/
static void
encode_utf8_to_mp DK_P3(dk_fig_conversion *,c, dk_stream_t *,os, char *,t)
{
  dk_udword ucb;
  unsigned char uc;
  int cc;
  char buffer[2];
  size_t max, used, avail, step;
  cc = 1; max = strlen(t); used = 0; avail = max;
  while(cc) {
    cc = 0;
    if(avail > 0) {
      step = 0;
      cc = dkenc_utf82uc(&ucb, (unsigned char *)(&(t[used])), avail, &step);
      if(cc) {
        used = used + step;
	if(avail > step) {
	  avail = avail - step;
	} else {
	  avail = 0;
	}
        if(ucb < 256UL) {
	  uc = (unsigned char)ucb;
	  if(uc == '\n') {
	    kw_to_stream(os, 54);
	  } else {
	    if(uc == '"') {
	      kw_to_stream(os, 55);
	    } else {
	      buffer[0] = uc; buffer[1] = '\0';
	      dkstream_puts(os, buffer);
	    }
	  }
	} else {
	  
	  /* ERROR: Character out of range, use LaTeX text handling */
	  dkfig_tool2_msg1(c, DK_LOG_LEVEL_ERROR, 119);
	}
      }
    }
  }
  /*
  char buffer[16];
  char *ptr = NULL;
  ptr = t; buffer[1] = '\0';
  while(*ptr) {
    switch(*ptr) {
      case '\n': {
        kw_to_stream(os, 54);
      } break;
      case '"': {
        kw_to_stream(os, 55);
      } break;
      default: {
        buffer[0] = *ptr;
	dkstream_puts(os, buffer);
      } break;
    }
    ptr++;
  }
  */
}



/**	Output text encoded for mp.
	@param	os	Output stream.
	@param	t	Text to print.

*/
static void
encode_text_to_mp DK_P2(dk_stream_t *,os, char *,t)
{
  char buffer[16];
  char *ptr = NULL;
  ptr = t; buffer[1] = '\0';
  while(*ptr) {
    switch(*ptr) {
      case '\n': {
        kw_to_stream(os, 54);
      } break;
      case '"': {
        kw_to_stream(os, 55);
      } break;
      default: {
        buffer[0] = *ptr;
	dkstream_puts(os, buffer);
      } break;
    }
    ptr++;
  }
}



/** 	Handle text object.
	@param	oi	MetaPost output instruction structure.
	@return	1 on success, 0 on error.
*/
static int
print_text_object DK_P1(dkfig_mp_output_instruction *,oi)
{
  int back = 1;
  int rotation = 0;
  int th;
  dk_fig_text *t;
  dk_fig_dcc dcc;
  dk_fig_fonth_t *fhptr = NULL;
  char *ptr;
  double dv;
  
  t = (dk_fig_text *)((oi->o)->data);
  if((t) && (!(((oi->c)->opt2) & DKFIG_OPT_SKIP_ALL_TEXTS))) {
    th = (((t->font_flags) & 2) ? ((oi->c)->special_text) : ((oi->c)->normal_text));
    fhptr = t->font_handling;
    if(fhptr) {
      if(fabs(t->angle) > DKFIG_EPSILON) { rotation = 1; }
      dkfig_tool_fill_dcc(oi->d, &dcc, ((oi->o)->fpd).pc);
      /* path q; path r; numeric s; */
      kw_to_stream(oi->s, 26); kw_to_stream(oi->s, 1);
      kw_to_stream(oi->s, 28); kw_to_stream(oi->s, 4);
      if(rotation) {
        kw_to_stream(oi->s, 1);
        kw_to_stream(oi->s, 26); kw_to_stream(oi->s, 1);
        kw_to_stream(oi->s, 39); kw_to_stream(oi->s, 4);
	switch(((oi->o)->fpd).st) {
	  case 1:
	  case 2: {
	    kw_to_stream(oi->s, 1);
	    kw_to_stream(oi->s, 44);
	    kw_to_stream(oi->s, 1);
	    kw_to_stream(oi->s, 45);
	    kw_to_stream(oi->s, 4);
	  } break;
	}
      }
      kw_to_stream(oi->s, 0);
      kw_to_stream(oi->s, 28); kw_to_stream(oi->s, 1);
      kw_to_stream(oi->s, 12); 
      switch(fhptr->handling) {
        case 2: case 3: case 4: case 5: {
	  /*
	    text handling by TeX/LaTeX
	  */
	  kw_to_stream(oi->s, 0);
	  kw_to_stream(oi->s, 29); kw_to_stream(oi->s, 1);
	  if(th & DKFIG_TH_MBOX) {
	    kw_to_stream(oi->s, 32);
	  }
	  kw_to_stream(oi->s, 30);
          if(fhptr->handling != 2) {
            dkfig_dt_write_fontname(oi->s, oi->d, fhptr);
	    kw_to_stream(oi->s, 1);
          }
          if((t->font_flags) & 2) {		/* Special text */
            dkstream_puts(oi->s, t->text);
          } else {				/* Non-special text */
	    if(((oi->c)->opt2) & DKFIG_OPT_UTF_8) {
	      /*
	        Handle UTF-8 encoded text
	      */
	      dkfig_tool2_utf8_to_latex(oi->s, oi->c, t->text);
	    } else {
	      /*
	        Handle normal text
	      */
              ptr = t->text;
              while(*ptr) {
                dkstream_puts(oi->s, dk_l2l_encoding(*ptr));
                ptr++;
              }
	    }
          }
	  kw_to_stream(oi->s, 31);
          kw_to_stream(oi->s, 1); kw_to_stream(oi->s, 18);
	} break;
	default: {
	  /*
	    Text handling by MetaPost itself
	  */
	  kw_to_stream(oi->s, 1);
	  kw_to_stream(oi->s, 21);
	  if(((oi->c)->opt2) & DKFIG_OPT_UTF_8) {
	    /*
	      Handle UTF-8 encoded text
	    */
            encode_utf8_to_mp(oi->c, oi->s, t->text);
	  } else {
	    /*
	      Handle normal text
	    */
	    encode_text_to_mp(oi->s, t->text); 
	  }
	  kw_to_stream(oi->s, 21),
	  kw_to_stream(oi->s, 0);
	  kw_to_stream(oi->s, 48);
	  kw_to_stream(oi->s, 1);
	  kw_to_stream(oi->s, 21);
          dkstream_puts(
            oi->s,
	    (
	      (fhptr->handling == 1)
	      ? dkfont_get_ps_name((size_t)(fhptr->fontno))
	      : dkfont_get_tex_name((size_t)(fhptr->fontno))
	    )
          );
	  kw_to_stream(oi->s, 21);
	  kw_to_stream(oi->s, 1);
	  kw_to_stream(oi->s, 49);
	  kw_to_stream(oi->s, 1);
	  kw_to_stream(oi->s, 2);
          stream_puts_double(
	    oi->s,
	    dkma_mul_double_ok(fhptr->fontsize,(oi->c)->fsf,&(oi->me)),
	    1
	  , oi->c);
	  kw_to_stream(oi->s, 50);
	  kw_to_stream(oi->s, 51);
	  kw_to_stream(oi->s, 52);
	  kw_to_stream(oi->s, 1);
	  kw_to_stream(oi->s, 53);
	  kw_to_stream(oi->s, 3);
	} break;
      }
      kw_to_stream(oi->s, 4); kw_to_stream(oi->s, 0);
      if(rotation) {
        kw_to_stream(oi->s, 39); kw_to_stream(oi->s, 1);
	kw_to_stream(oi->s, 12); kw_to_stream(oi->s, 1);
        kw_to_stream(oi->s, 28); kw_to_stream(oi->s, 1);
        kw_to_stream(oi->s, 38); kw_to_stream(oi->s, 1);
        dv = (180.0 * t->angle) / M_PI;
	dv = drd(dv, oi->c, 1);
	stream_puts_double(oi->s, dv, 2, oi->c);
	kw_to_stream(oi->s, 4); kw_to_stream(oi->s, 0);
	switch(((oi->o)->fpd).st) {
	  case 1:
	  case 2: {
	    kw_to_stream(oi->s, 45);
	    kw_to_stream(oi->s, 1);
	    kw_to_stream(oi->s, 12);
	    kw_to_stream(oi->s, 1);
	    kw_to_stream(oi->s, 2);
	    kw_to_stream(oi->s, 46);
	    kw_to_stream(oi->s, 2);
	    kw_to_stream(oi->s, 2);
            kw_to_stream(oi->s, 47);
	    kw_to_stream(oi->s, 1);
	    kw_to_stream(oi->s, 28);
	    kw_to_stream(oi->s, 3);
	    kw_to_stream(oi->s, 9);
	    kw_to_stream(oi->s, 2);
	    kw_to_stream(oi->s, 42);
	    kw_to_stream(oi->s, 1);
	    kw_to_stream(oi->s, 28);
	    kw_to_stream(oi->s, 3);
	    kw_to_stream(oi->s, 3);
	    kw_to_stream(oi->s, 3);
	    kw_to_stream(oi->s, 40);
	    kw_to_stream(oi->s, 2);
	    dv = cos(t->angle);
	    if(((oi->o)->fpd).st == 1) { dv = 0.5 * dv; }
	    /* dv = dkma_double_restrict_digits(dv, 5); */
	    if(fabs(dv) < 1.4693e-5) { dv = 0.0; }
	    stream_puts_double(oi->s, dv, 2, oi->c);
	    kw_to_stream(oi->s, 5);
	    dv = sin(t->angle);
	    if(((oi->o)->fpd).st == 1) { dv = 0.5 * dv; }
	    /* dv = dkma_double_restrict_digits(dv, 5); */
	    if(fabs(dv) < 1.4693e-5) { dv = 0.0; }
	    stream_puts_double(oi->s, dv, 2, oi->c);
	    kw_to_stream(oi->s, 3);
	    kw_to_stream(oi->s, 4);
	    kw_to_stream(oi->s, 0);
	  } break;
	}
      }
      kw_to_stream(oi->s, 33);
      kw_to_stream(oi->s, 34);
      if(rotation) {
        kw_to_stream(oi->s, 37);
      } else {
        switch(((oi->o)->fpd).st) {
	  case 1: {
	    kw_to_stream(oi->s, 35);
	  } break;
	  case 2: {
	    kw_to_stream(oi->s, 36);
	  } break;
	  default: {
	    kw_to_stream(oi->s, 37);
	  } break;
	}
      }
      kw_to_stream(oi->s, 2);
      kw_to_stream(oi->s, (rotation ? 39 : 28));
      kw_to_stream(oi->s, 5);
      kw_to_stream(oi->s, 2);
      write_long_point(oi, t->x, t->y);
      kw_to_stream(oi->s, 8);
      kw_to_stream(oi->s, 2);
      kw_to_stream(oi->s, 42);
      kw_to_stream(oi->s, 1);
      kw_to_stream(oi->s, (rotation ? 39 : 28));
      kw_to_stream(oi->s, 3);
      if(rotation) {
        switch(((oi->o)->fpd).st) {
	  case 1: case 2: {
	    kw_to_stream(oi->s, 9);
	    kw_to_stream(oi->s, 45);
	  } break;
	}
      }
      kw_to_stream(oi->s, 3);
      kw_to_stream(oi->s, 3);
      kw_to_stream(oi->s, 1);
      if(can_use_color(oi->c)) {
        kw_to_stream(oi->s, 43);
        kw_to_stream(oi->s, 1);
        write_dcc_data(oi->s, &dcc, oi->c);
      } else {
	kw_to_stream(oi->s, 106);
	kw_to_stream(oi->s, 1);
	write_dcc_gray(oi->s, &dcc, oi->c);
      }
      kw_to_stream(oi->s, 4);
      kw_to_stream(oi->s, 0);
    }
  }
  
  return back;
}



/**	Check whether we have an ellipse or a circle.
	@param	ellipse_sub_type	Ellipse sub type.
	@return	1 for real ellipse, 0 for circle.
*/
static int
is_ellipse DK_P1(int, ellipse_sub_type)
{
  int back = 0;
  if((ellipse_sub_type < 3) || (ellipse_sub_type > 4)) {
    back = 1;
  }
  return back;
}



/**	Write path for an ellipse.
	@param	oi	MetaPost output instruction structure.
	@return	1 on success, 0 on error.
*/
static int
path_ellipse DK_P1(dkfig_mp_output_instruction *,oi)
{
  int back = 0;
  int me = 0;
  dk_fig_ellipse *e = NULL;
  int iselli, rotation;
  
  e = (dk_fig_ellipse *)((oi->o)->data);
  if(e) {	
    iselli = rotation = 0;
    back = 1;
    iselli = is_ellipse(((oi->o)->fpd).st);
    if(iselli) {
      if(fabs(e->angle) > DKFIG_EPSILON) { rotation = 1; }
    }
    if(iselli) {
      if(rotation) {
        kw_to_stream(oi->s, 2);
      }
      kw_to_stream(oi->s, 2);
    }	
    /* (fullcircle scaled ...) */
    kw_to_stream(oi->s, 2);
    kw_to_stream(oi->s, 58);
    kw_to_stream(oi->s, 1);
    kw_to_stream(oi->s, 49);
    kw_to_stream(oi->s, 1);
    stream_puts_double(
      oi->s,
      dkma_mul_double_ok(2.0, fabs(cc_radius(oi->c, e->radiusx)), &me),
      1
    , oi->c);
    kw_to_stream(oi->s, 3);
    if(iselli) {
      kw_to_stream(oi->s, 1);
      kw_to_stream(oi->s, 56);
      kw_to_stream(oi->s, 1);
      stream_puts_double(
        oi->s,
	dkma_div_double_ok(
	  fabs(dkma_l_to_double(e->radiusy)),
	  fabs(dkma_l_to_double(e->radiusx)),
	  &me
	),
	1
      , oi->c);
      kw_to_stream(oi->s, 3);
      if(rotation) {
        kw_to_stream(oi->s, 1);
	kw_to_stream(oi->s, 38);
	kw_to_stream(oi->s, 1);
	stream_puts_double(
	  oi->s,
	  drd(dkma_mul_double_ok(
	    180.0,
	    dkma_div_double_ok(e->angle, M_PI, &me),
	    &me
	  ), oi->c, 1),
	  1
	, oi->c);
        kw_to_stream(oi->s, 3);
      }
    }
    /* shifted (...,...) */
    kw_to_stream(oi->s, 1);
    if(rotation) {
      kw_to_stream(oi->s, 0);
    }
    kw_to_stream(oi->s, 57);
    kw_to_stream(oi->s, 1);
    write_long_point(oi, e->centerx, e->centery);
  }
  if(me) { back = 0; oi->me = me; }
  
  return back;
}



/**	Write path for a polyline.
	@param	oi	MetaPost output instruction structure.
	@return	1 on success, 0 on error.
*/
static int
path_polyline DK_P1(dkfig_mp_output_instruction *,oi)
{
  int back = 0;
  int me = 0;
  dk_fig_polyline *p;
  dk_fig_bb bbdest;
  long *xptr, *yptr; size_t i;
  double deltax, deltay, radius;
  
  p = (dk_fig_polyline *)((oi->o)->data);
  if(p) {
    back = 1;
    switch(((oi->o)->fpd).st) {
      case 5: {		
        /* WARNING: Skipping included image */
	dkfig_tool2_msg1(oi->c, DK_LOG_LEVEL_WARNING, 53);
      } /* no break, fall-through wanted to draw empty frame */
      case 2: case 4: {	
	dkfig_tool_bb_reset(&bbdest);
	xptr = p->xvalues; yptr = p->yvalues;
	for(i = 0; i < p->npoints; i++) {
          dkfig_tool_bb_add_x(&bbdest, cc_x(oi->c, *xptr));
	  dkfig_tool_bb_add_y(&bbdest, cc_y(oi->c, *yptr));
	  xptr++; yptr++;
	}
	if(((oi->o)->fpd).st == 4) {
          deltax = dkma_sub_double_ok(bbdest.xmax, bbdest.xmin, &me);
	  deltay = dkma_sub_double_ok(bbdest.ymax, bbdest.ymin, &me);
          radius = 0.9 * dkma_l_to_double(p->radius);
	  if(radius > (0.5 * deltax)) { radius = 0.5 * deltax; }
	  if(radius > (0.5 * deltay)) { radius = 0.5 * deltay; }
	  write_noconv_double_point(oi, bbdest.xmin, (bbdest.ymin + radius), 1);
          kw_to_stream(oi->s, 30);
	  kw_to_stream(oi->s, 60);
	  kw_to_stream(oi->s, 31);
          kw_to_stream(oi->s, 0);
          kw_to_stream(oi->s, 7);
          kw_to_stream(oi->s, 30);
	  kw_to_stream(oi->s, 61);
	  kw_to_stream(oi->s, 31);
	  write_noconv_double_point(oi, (bbdest.xmin + radius), bbdest.ymin, 1);
	  kw_to_stream(oi->s, 0);
	  kw_to_stream(oi->s, 6);
	  write_noconv_double_point(oi, (bbdest.xmax - radius), bbdest.ymin, 1);
	  kw_to_stream(oi->s, 30);
	  kw_to_stream(oi->s, 61);
	  kw_to_stream(oi->s, 31);
	  kw_to_stream(oi->s, 0);
	  kw_to_stream(oi->s, 7);
	  kw_to_stream(oi->s, 30);
	  kw_to_stream(oi->s, 62);
	  kw_to_stream(oi->s, 31);
	  write_noconv_double_point(oi, bbdest.xmax, (bbdest.ymin + radius), 1);
	  kw_to_stream(oi->s, 0);
	  kw_to_stream(oi->s, 6);
	  write_noconv_double_point(oi, bbdest.xmax, (bbdest.ymax - radius), 1);
	  kw_to_stream(oi->s, 30);
	  kw_to_stream(oi->s, 62);
	  kw_to_stream(oi->s, 31);
	  kw_to_stream(oi->s, 0);
	  kw_to_stream(oi->s, 7);
	  kw_to_stream(oi->s, 30);
	  kw_to_stream(oi->s, 63);
	  kw_to_stream(oi->s, 31);
	  write_noconv_double_point(oi, (bbdest.xmax - radius), bbdest.ymax, 1);
	  kw_to_stream(oi->s, 0);
	  kw_to_stream(oi->s, 6);
	  write_noconv_double_point(oi, (bbdest.xmin + radius), bbdest.ymax, 1);
	  kw_to_stream(oi->s, 30);
	  kw_to_stream(oi->s, 63);
	  kw_to_stream(oi->s, 31);
	  kw_to_stream(oi->s, 0);
	  kw_to_stream(oi->s, 7);
	  kw_to_stream(oi->s, 30);
	  kw_to_stream(oi->s, 60);
	  kw_to_stream(oi->s, 31);
	  write_noconv_double_point(oi, bbdest.xmin, (bbdest.ymax - radius), 1);
          kw_to_stream(oi->s, 0);
	  kw_to_stream(oi->s, 6);
	  kw_to_stream(oi->s, 59);
	} else {
	  write_noconv_double_point(oi, bbdest.xmin, bbdest.ymin, 1);
	  kw_to_stream(oi->s, 0);
          kw_to_stream(oi->s, 6);
	  write_noconv_double_point(oi, bbdest.xmax, bbdest.ymin, 1);
	  kw_to_stream(oi->s, 0);
	  kw_to_stream(oi->s, 6);
	  write_noconv_double_point(oi, bbdest.xmax, bbdest.ymax, 1);
	  kw_to_stream(oi->s, 0);
	  kw_to_stream(oi->s, 6);
	  write_noconv_double_point(oi, bbdest.xmin, bbdest.ymax, 1);
	  kw_to_stream(oi->s, 0);
	  kw_to_stream(oi->s, 6);
	  kw_to_stream(oi->s, 59);
	}
      } break;
      default: {	
	xptr = p->xvalues; yptr = p->yvalues;
	if((!(((oi->o)->fpd).cl)) && (((oi->o)->fpd).ar & 2)) {
	  
	  write_double_point(oi, (p->pa).x, (p->pa).y, 2);
	  
	  
	} else {
	  
	  write_long_point(oi, *xptr, *yptr);
	}
	xptr++; yptr++;
	for(i = 1; i < p->npoints; i++) {
	  kw_to_stream(oi->s, 0);
	  kw_to_stream(oi->s, 6);
	  if(i == (p->npoints - 1)) {
	    
	    if(((oi->o)->fpd).cl) {
	      
	      kw_to_stream(oi->s, 59);
	    } else {
	      
	      if(((oi->o)->fpd).ar & 1) {
	        
	        write_double_point(oi, (p->pe).x, (p->pe).y, 2);
		
		
	      } else {
	        
	        write_long_point(oi, *xptr, *yptr);
	      }
	    }
	  } else {
	    
	    write_long_point(oi, *xptr, *yptr);
	  }
	  xptr++; yptr++;
	}
      } break;
    }
  }
  if(me) { back = 0; oi->me = me; }
  
  return back;
}



/**	Write path for a spline.
	@param	oi	MetaPost output instruction structure.
	@return	1 on success, 0 on error.
*/
static int
path_spline DK_P1(dkfig_mp_output_instruction *,oi)
{
  int back = 0;
  int me = 0;
  dk_fig_spline *s;
  size_t nsegs, li, ri, maxli;
  dk_fig_bezier_point *bpptr;
  
  s = (dk_fig_spline *)((oi->o)->data);
  if(s) {
    back = 1;
    nsegs = s->nbpoints - 1;
    if(((oi->o)->fpd).cl) {
      nsegs = s->nbpoints;
    }
    bpptr = s->bpoints;
    if((!(((oi->o)->fpd).cl)) && (((oi->o)->fpd).ar & 2)) {
      /* pa....pa2 */
      
      
#line 1221 "dkfigmp.ctr"
      
      
#line 1223 "dkfigmp.ctr"
      write_double_point(oi, (s->pa).value.x, (s->pa).value.y, 2);
      kw_to_stream(oi->s, 0);
      kw_to_stream(oi->s, 7);
      kw_to_stream(oi->s, 64);
      write_double_point(oi, (s->pa).rcontrol.x, (s->pa).rcontrol.y, 2);
      kw_to_stream(oi->s, 1);
      kw_to_stream(oi->s, 65);
      write_double_point(oi, (s->pa2).lcontrol.x, (s->pa2).lcontrol.y, 2);
      kw_to_stream(oi->s, 0);
      kw_to_stream(oi->s, 7);
      write_double_point(oi, (s->pa2).value.x, (s->pa2).value.y, 2);
      li = s->normals;
    } else {
       write_double_point(oi, bpptr[0].value.x, bpptr[0].value.y, 2);
       li = 0;
    }
    if((s->normale > 0) || (((oi->o)->fpd).cl) || (!((((oi->o)->fpd).ar) & 1))) {
      maxli = s->nbpoints - 2;
      if(((oi->o)->fpd).cl) { maxli = s->nbpoints - 1; }
      if((!(((oi->o)->fpd).cl)) && (((oi->o)->fpd).ar & 1)) {
        maxli = s->normale - 1;
      }
      while(li <= maxli) {
        ri = li + 1;
        if(ri >= s->nbpoints) {
          ri = 0;
        }
	
	
#line 1252 "dkfigmp.ctr"
	
	
#line 1254 "dkfigmp.ctr"
        kw_to_stream(oi->s, 0);
        kw_to_stream(oi->s, 7);
        kw_to_stream(oi->s, 64);
        write_double_point(oi, bpptr[li].rcontrol.x, bpptr[li].rcontrol.y, 2);
        kw_to_stream(oi->s, 1);
        kw_to_stream(oi->s, 65);
        write_double_point(oi, bpptr[ri].lcontrol.x, bpptr[ri].lcontrol.y, 2);
        kw_to_stream(oi->s, 0);
        kw_to_stream(oi->s, 7);
	if(ri == 0) {
	  kw_to_stream(oi->s, 59);
	} else {
          write_double_point(oi, bpptr[ri].value.x, bpptr[ri].value.y, 2);
	}
        li++;
      }
    }
    if((!(((oi->o)->fpd).cl)) && (((oi->o)->fpd).ar & 1)) {
      
      
#line 1274 "dkfigmp.ctr"
      
      
#line 1276 "dkfigmp.ctr"
      kw_to_stream(oi->s, 0);
      kw_to_stream(oi->s, 7);
      kw_to_stream(oi->s, 64);
      write_double_point(oi, (s->pe2).rcontrol.x, (s->pe2).rcontrol.y, 2);
      kw_to_stream(oi->s, 1);
      kw_to_stream(oi->s, 65);
      write_double_point(oi, (s->pe).lcontrol.x, (s->pe).lcontrol.y, 2);
      kw_to_stream(oi->s, 0);
      kw_to_stream(oi->s, 7);
      write_double_point(oi, (s->pe).value.x, (s->pe).value.y, 2);
    }
  }
  if(me) { back = 0; oi->me = me; }
  
  return back;
}



/**	Write path for an arc.
	@param	oi	MetaPost output instruction structure.
	@return	1 on success, 0 on error.
*/
static int
path_arc DK_P1(dkfig_mp_output_instruction *,oi)
{
  int back = 0;
  int me = 0;
  double ahlgt, rl;
  dk_fig_arc *a;
  
  a = (dk_fig_arc *)((oi->o)->data);
  if(a) {
    back = 1;
    ahlgt = 0.0;
    if((!(((oi->o)->fpd).cl)) && ((((oi->o)->fpd).ar) & 1)) {
      /* ahlgt = a->lba; */
      ahlgt = a->rba;
    }
    if((!(((oi->o)->fpd).cl)) && ((((oi->o)->fpd).ar) & 2)) {
      /* ahlgt = dkma_add_double_ok(ahlgt, a->rba, &me); */
      ahlgt = dkma_add_double_ok(ahlgt, a->lba, &me);
    } 
    if(ahlgt <= (a->calc).alength) {
      back = 1;
      rl = dkma_sub_double_ok((a->calc).alength, ahlgt, &me);
      
      if(((oi->o)->fpd).st == 2) {
        kw_to_stream(oi->s, 2);
      }
      kw_to_stream(oi->s, 2);
      kw_to_stream(oi->s, 2);
      kw_to_stream(oi->s, 2);
      kw_to_stream(oi->s, 58);
      kw_to_stream(oi->s, 1);
      kw_to_stream(oi->s, 66);
      kw_to_stream(oi->s, 1);
      kw_to_stream(oi->s, 2);
      write_noconv_double_point(oi, 0.0, 0.0, 1);
      kw_to_stream(oi->s, 6);
      write_noconv_double_point(
        oi,
	(1.1 * cos(rl)),
	(1.1 * sin(rl))
      , 2);
      kw_to_stream(oi->s, 3);
      kw_to_stream(oi->s, 3);
      kw_to_stream(oi->s, 1);
      kw_to_stream(oi->s, 38);
      kw_to_stream(oi->s, 1);
      rl = (a->calc).astart;
      if((!(((oi->o)->fpd).cl)) && ((((oi->o)->fpd).ar) & 2)) {
        rl = dkma_add_double_ok(rl, a->lba, &me);
      }
      rl = dkma_mul_double_ok(
        180.0,
	dkma_div_double_ok(rl, M_PI, &me),
        &me
      );
      rl = drd(rl, oi->c, 2);
      stream_puts_double(oi->s, rl, 2, oi->c);
      kw_to_stream(oi->s, 3);
      kw_to_stream(oi->s, 0);
      kw_to_stream(oi->s, 49);
      kw_to_stream(oi->s, 1);
      stream_puts_double(
        oi->s, ccd_radius(oi->c, dkma_mul_double_ok(2.0, (a->calc).ra, &me) ), 1
      , oi->c);
      kw_to_stream(oi->s, 3);
      kw_to_stream(oi->s, 1);
      kw_to_stream(oi->s, 57);
      kw_to_stream(oi->s, 1);
      write_double_point(oi, (a->calc).xm, (a->calc).ym, 1);
      if(((oi->o)->fpd).st == 2) {
        kw_to_stream(oi->s, 3);
	kw_to_stream(oi->s, 0);
	kw_to_stream(oi->s, 6);
        write_double_point(oi, (a->calc).xm, (a->calc).ym, 1);
	kw_to_stream(oi->s, 6);
	kw_to_stream(oi->s, 59);
      }
    } else {	
    }
  }
  if(me) { back = 0; oi->me = me; }
  
  return back;
}



/**	Write a color cell.
	@param	oi	MetaPost output instruction structure.
	@param	dcc	Color cell structure.
*/
static void
write_color_c DK_P2(dkfig_mp_output_instruction *,oi, dk_fig_dcc *,dcc)
{
  if(can_use_color(oi->c)) {
    kw_to_stream(oi->s, 68);
    kw_to_stream(oi->s, 1);
    kw_to_stream(oi->s, 69);
    kw_to_stream(oi->s, 4);
    kw_to_stream(oi->s, 0);
    kw_to_stream(oi->s, 69);
    kw_to_stream(oi->s, 1);
    kw_to_stream(oi->s, 12);
    kw_to_stream(oi->s, 1);
    write_dcc_data(oi->s, dcc, oi->c);
    kw_to_stream(oi->s, 4);
    kw_to_stream(oi->s, 0);
  }
}



/**	Set new line join (if it differs from the current line join).
	@param	oi	MetaPost output instruction structure.
	@param	js	Line join.
*/
static void
set_line_join DK_P2(dkfig_mp_output_instruction *,oi, int,js)
{
  int must_do_it = 1;
  if(((oi->m)->haveflags) & HAVE_LINEJOIN) {
    if((oi->m)->linejoin == js) {
      must_do_it = 0;
    }
  }
  if(must_do_it) {
    (oi->m)->haveflags = (oi->m)->haveflags | HAVE_LINEJOIN;
    (oi->m)->linejoin = js;
    kw_to_stream(oi->s, 77);
    kw_to_stream(oi->s, 75);
    switch(js) {
      case 1:  kw_to_stream(oi->s, 11); break;
      case 2:  kw_to_stream(oi->s, 76); break;
      default: kw_to_stream(oi->s, 10); break;
    }
    kw_to_stream(oi->s, 4);
    kw_to_stream(oi->s, 0);
  }
}



/**	Set new arrowhead length (only if it differs from
  	the current arrowhead length).
	@param	oi	MetaPost output instruction structure.
	@param	h	New arrowhead length.
*/
static void
set_ahlength DK_P2(dkfig_mp_output_instruction *,oi, double,h)
{
  double newv, d, m;
  int me = 0;
  int must_do_it = 1;
  newv = dkma_mul_double_ok(
    72.0,
    dkma_div_double_ok(fabs(h), (oi->d)->fres, &me),
    &me
  );
  if(((oi->m)->haveflags) & HAVE_AHLENGTH) {
    d = fabs(newv - (oi->m)->ahlength);
    if(newv < (oi->m)->ahlength) {
      m = newv;
    } else {
      m = (oi->m)->ahlength;
    }
    if((d < DKFIG_EPSILON) && (d < m)) {
      must_do_it = 0;
    }
  }
  if(must_do_it && (!me)) {
    kw_to_stream(oi->s, 82);
    kw_to_stream(oi->s, 75);
    stream_puts_double(oi->s, newv, 1, oi->c);
    kw_to_stream(oi->s, 4);
    kw_to_stream(oi->s, 0);
    (oi->m)->haveflags = (oi->m)->haveflags | HAVE_AHLENGTH;
    (oi->m)->ahlength = newv;
  }
}



/**	Set a new arrowhead angle (only if it differs from the
	current arrowhead angle).
	@param	oi	MetaPost output instruction structure.
	@param	w	Arrowhead width.
	@param	h	Arrowhead height.

*/
static void
set_ahangle DK_P3(dkfig_mp_output_instruction *,oi, double,w, double,h)
{
  double newv, d, m;
  int must_do_it = 1;
  newv = dkma_atan2((0.5*w), h);
  newv = 360.0 * newv / M_PI;
  newv = drd(newv, oi->c, 1);
  if(((oi->m)->haveflags) & HAVE_AHANGLE) {
    d = fabs(newv - (oi->m)->ahangle);
    if(fabs((oi->m)->ahangle) < fabs(newv)) {
      m = DKFIG_EPSILON * fabs((oi->m)->ahangle);
    } else {
      m = DKFIG_EPSILON * fabs(newv);
    }
    if((d < DKFIG_EPSILON) && (d < m)) {
      must_do_it = 0;
    }
  }
  if(must_do_it) {
    kw_to_stream(oi->s, 83);
    kw_to_stream(oi->s, 75);
    stream_puts_double(oi->s, newv, 1, oi->c);
    kw_to_stream(oi->s, 4);
    kw_to_stream(oi->s, 0);
    (oi->m)->haveflags = (oi->m)->haveflags | HAVE_AHANGLE;
    (oi->m)->ahangle = newv;
  }
}



/**	Set a new line cap (only if it differs from
	the current line cap).
	@param	oi	MetaPost output instruction structure.
	@param	cs	Linecap style.
*/
static void
set_line_cap DK_P2(dkfig_mp_output_instruction *,oi, int,cs)
{
  int must_do_it = 1;
  if(((oi->m)->haveflags) & HAVE_LINECAP) {
    if((oi->m)->linecap == cs) {
      must_do_it = 0;
    }
  }
  if(must_do_it) {
    (oi->m)->haveflags = (oi->m)->haveflags | HAVE_LINECAP;
    (oi->m)->linecap = cs;
    kw_to_stream(oi->s, 74);
    kw_to_stream(oi->s, 75);
    switch(cs) {
      case 1:  kw_to_stream(oi->s, 11); break;
      case 2:  kw_to_stream(oi->s, 76); break;
      default: kw_to_stream(oi->s, 10); break;
    }
    kw_to_stream(oi->s, 4);
    kw_to_stream(oi->s, 0);
  }
}



/**	Set a new line width (only if the new line width
	differs from the current line width.
	@param	oi	MetaPost output instruction structure.
	@param	lt	Line width.
*/
static void
set_line_width DK_P2(dkfig_mp_output_instruction *,oi, long,lt)
{
  int me = 0;
  int must_do_it = 1;
  double newlw;
  double d, m;
  newlw = 0.9 * dkma_l_to_double(lt);
  if(((oi->c)->opt1) & DKFIG_OPT_ENLIGHTEN_LOOK) {
    newlw = 0.5 * newlw;
  }
  if(((oi->m)->haveflags) & HAVE_LINEWIDTH) {
    d = fabs((oi->m)->linewidth - newlw);
    if(fabs(newlw) < fabs((oi->m)->linewidth)) {
      m = DKFIG_EPSILON * fabs(newlw);
    } else {
      m = DKFIG_EPSILON * fabs((oi->m)->linewidth);
    }
    if((d < m) && (d < DKFIG_EPSILON)) {
      must_do_it = 0;
    }
  }
  if(must_do_it && (!me)) {
    kw_to_stream(oi->s, 71);
    kw_to_stream(oi->s, 1);
    kw_to_stream(oi->s, 72);
    kw_to_stream(oi->s, 1);
    kw_to_stream(oi->s, 49);
    kw_to_stream(oi->s, 1);
    stream_puts_double(oi->s, newlw, 1, oi->c);
    /* kw_to_stream(oi->s, 73); */
    kw_to_stream(oi->s, 4);
    kw_to_stream(oi->s, 0);
    (oi->m)->haveflags = (oi->m)->haveflags | HAVE_LINEWIDTH;
    (oi->m)->linewidth = newlw;
  }
}



/**	Write path for arrowhead.
	@param	oi	MetaPost output instruction structure.
	@param	rev	Flag: Arrowhead reverse.
*/
static void
arrowhead_path DK_P2(dkfig_mp_output_instruction *,oi, int,rev)
{
  kw_to_stream(oi->s, 25);
  kw_to_stream(oi->s, 1);
  kw_to_stream(oi->s, 78);
  kw_to_stream(oi->s, 4);
  kw_to_stream(oi->s, 0);
  if(((oi->c)->opt1) & DKFIG_OPT_METAPOST_ARROWHEADS) {
    set_ahangle(oi, (oi->a)->w, (oi->a)->h);
    set_ahlength(oi, (oi->a)->h);
    kw_to_stream(oi->s, 78); kw_to_stream(oi->s, 1);
    kw_to_stream(oi->s, 12); kw_to_stream(oi->s, 1);
    kw_to_stream(oi->s, 79); kw_to_stream(oi->s, 1);
    if(rev) {
      kw_to_stream(oi->s, 2);
      kw_to_stream(oi->s, 80);
      kw_to_stream(oi->s, 1);
    }
    kw_to_stream(oi->s, 27);
    if(rev) {
      kw_to_stream(oi->s, 3);
    }
    kw_to_stream(oi->s, 4); kw_to_stream(oi->s, 0);
  } else {
    kw_to_stream(oi->s, 78); kw_to_stream(oi->s, 1);
    kw_to_stream(oi->s, 12); kw_to_stream(oi->s, 1);
    write_double_point(oi, ((oi->a)->p1).x, ((oi->a)->p1).y, 1);
    kw_to_stream(oi->s, 6);
    write_double_point(oi, ((oi->a)->p2).x, ((oi->a)->p2).y, 1);
    kw_to_stream(oi->s, 6);
    write_double_point(oi, ((oi->a)->p3).x, ((oi->a)->p3).y, 1);
    kw_to_stream(oi->s, 0);
    if((oi->a)->type > 0) {
      if((oi->a)->type > 1) {
        kw_to_stream(oi->s, 6);
	write_double_point(oi, ((oi->a)->p4).x, ((oi->a)->p4).y, 1);
      }
      kw_to_stream(oi->s, 6);
      kw_to_stream(oi->s, 59);
    }
    kw_to_stream(oi->s, 4); kw_to_stream(oi->s, 0);
  }
}



/**	Write instructions to draw arrowhead.
	@param	oi	MetaPost output instruction structure.
	@param	dcc	Color cell structure.
	@param	hc	Flag: Color stored in variable c.
*/
static void
arrowhead_fd DK_P3(dkfig_mp_output_instruction *,oi, dk_fig_dcc *,dcc, int,hc)
{
  set_line_join(oi, (oi->d)->ahlj);
  if((oi->a)->type > 0) {
    kw_to_stream(oi->s, 67); kw_to_stream(oi->s, 1);
    kw_to_stream(oi->s, 78); kw_to_stream(oi->s, 1);
    if(can_use_color(oi->c)) {
      kw_to_stream(oi->s, 43); kw_to_stream(oi->s, 1);
      if((oi->a)->style > 0) {
        if(hc) {
          kw_to_stream(oi->s, 69);
        } else {
          write_dcc_data(oi->s, dcc, oi->c);
        }
      } else {
        kw_to_stream(oi->s, 81);
      }
    } else {
      kw_to_stream(oi->s, 106); kw_to_stream(oi->s, 1);
      if((oi->a)->style > 0) {
        write_dcc_gray(oi->s, dcc, oi->c);
      } else {
        kw_to_stream(oi->s, 11);
      }
    }
    kw_to_stream(oi->s, 4); kw_to_stream(oi->s, 0);
  }
  kw_to_stream(oi->s, 70); kw_to_stream(oi->s, 1);
  kw_to_stream(oi->s, 78); kw_to_stream(oi->s, 1);
  if(can_use_color(oi->c)) {
    kw_to_stream(oi->s, 43); kw_to_stream(oi->s, 1);
    if(hc) {
      kw_to_stream(oi->s, 69);
    } else {
      write_dcc_data(oi->s, dcc, oi->c);
    }
  } else {
    kw_to_stream(oi->s, 106); kw_to_stream(oi->s, 1);
    write_dcc_gray(oi->s, dcc, oi->c);
  }
  kw_to_stream(oi->s, 4); kw_to_stream(oi->s, 0);
}



/**	Write start of addto ... instruction.
	@param	oi	MetaPost output instruction structure.
*/
static void
start_addto DK_P1(dkfig_mp_output_instruction *,oi)
{
  kw_to_stream(oi->s, 87);
  kw_to_stream(oi->s, 1);
  kw_to_stream(oi->s, 28);
  kw_to_stream(oi->s, 1);
  kw_to_stream(oi->s, 94);
  kw_to_stream(oi->s, 1);
  kw_to_stream(oi->s, 2);
  kw_to_stream(oi->s, 0);
}



/**	Write end of addto instruction.
	@param	oi	MetaPost output instruction structure.
	@param	dcc	Color cell structure.
*/
static void
end_addto DK_P2(dkfig_mp_output_instruction *,oi, dk_fig_dcc *,dcc)
{
  kw_to_stream(oi->s, 0);
  kw_to_stream(oi->s, 3);
  kw_to_stream(oi->s, 1);
  if(can_use_color(oi->c)) {
    kw_to_stream(oi->s, 43);
    kw_to_stream(oi->s, 1);
    kw_to_stream(oi->s, 69);
  } else {
    kw_to_stream(oi->s, 106); kw_to_stream(oi->s, 1);
    write_dcc_gray(oi->s, dcc, oi->c);
  }
  kw_to_stream(oi->s, 1);
  kw_to_stream(oi->s, 95);
  kw_to_stream(oi->s, 1);
  kw_to_stream(oi->s, 96);
  kw_to_stream(oi->s, 4);
  kw_to_stream(oi->s, 0);
}



/**	Fill pattern: 30 degree lines to the left.
	@param	oi	MetaPost output instruction structure.
	@param	dcc	Color cell structure.
	@return	1 on success, 0 on error.
*/
static int
diagonal_left_30 DK_P2(dkfig_mp_output_instruction *,oi, dk_fig_dcc *,dcc)
{
  int back = 1;
  int me = 0;
  double xstart, xend, ystart, yend, y0, y1, deltay, y;
  ystart = (oi->obb).ymin; yend = (oi->obb).ymax;
  xstart = (oi->obb).xmin; xend = (oi->obb).xmax;
  deltay = fabs(oi->patrp);
  deltay = dkma_div_double_ok(deltay, sqrt(0.75), &me);
  if(((oi->c)->opt1) & DKFIG_OPT_FILL_CONTIGOUS) {
    y0 = dkma_add_double_ok(
      ystart,
      dkma_mul_double_ok(0.5, xstart, &me),
      &me
    );
    y0 = dkma_div_double_ok(y0, deltay, &me);
    y1 = floor(y0);
    y0 = dkma_sub_double_ok(y0, y1, &me);
    y0 = dkma_mul_double_ok(y0, deltay, &me);
    ystart = dkma_sub_double_ok(ystart, y0, &me);
  }
  y1 = dkma_sub_double_ok(xend, xstart, &me);
  y1 = dkma_mul_double_ok(0.5, y1, &me);
  yend = dkma_add_double_ok(yend, y1, &me);
  y = ystart;
  while(y <= yend) {
    start_addto(oi);
    write_noconv_double_point(oi, xstart, y, 2);
    kw_to_stream(oi->s, 6);
    write_noconv_double_point(oi, xend, dkma_sub_double_ok(y,y1,&me), 2);
    end_addto(oi, dcc);
    y = dkma_add_double_ok(y, deltay, &me);
  }
  if(me) { oi->me = me; back = 0; }
  return back;
}



/**	Fill pattern: 30 degree lines to the right.
	@param	oi	MetaPost output instruction structure.
	@param	dcc	Color cell structure.
	@return	1 on success, 0 on error.
*/
static int
diagonal_right_30 DK_P2(dkfig_mp_output_instruction *,oi, dk_fig_dcc *,dcc)
{
  int back = 1;
  int me = 0;
  double xstart, xend, ystart, yend, y0, y1, deltay, y;
  ystart = (oi->obb).ymin; yend = (oi->obb).ymax;
  xstart = (oi->obb).xmin; xend = (oi->obb).xmax;
  deltay = fabs(oi->patrp);
  deltay = dkma_div_double_ok(deltay, sqrt(0.75), &me);
  y1 = dkma_sub_double_ok(xend, xstart, &me);
  y1 = dkma_mul_double_ok(0.5, y1, &me);
  ystart = dkma_sub_double_ok(ystart, y1, &me);
  if(((oi->c)->opt1) & DKFIG_OPT_FILL_CONTIGOUS) {
    y0 = dkma_sub_double_ok(
      ystart,
      dkma_mul_double_ok(0.5, xstart, &me),
      &me
    );
    y0 = dkma_div_double_ok(y0, deltay, &me);
    y1 = floor(y0);
    y0 = dkma_sub_double_ok(y0, y1, &me);
    y0 = dkma_mul_double_ok(y0, deltay, &me);
    ystart = dkma_sub_double_ok(ystart, y0, &me);
  }
  y1 = dkma_sub_double_ok(xend, xstart, &me);
  y1 = dkma_mul_double_ok(0.5, y1, &me);
  y = ystart;
  while(y <= yend) {
    start_addto(oi);
    write_noconv_double_point(oi, xstart, y, 2);
    kw_to_stream(oi->s, 6);
    write_noconv_double_point(oi, xend, dkma_add_double_ok(y,y1,&me), 2);
    end_addto(oi, dcc);
    y = dkma_add_double_ok(y, deltay, &me);
  }
  if(me) { oi->me = me; back = 0; }
  return back;
}



/**	Fill pattern: 30 degree crosshatch.
	@param	oi	MetaPost output instruction structure.
	@param	dcc	Color cell structure.
	@return	1 on success, 0 on error.
*/
static int
crosshatch_30 DK_P2(dkfig_mp_output_instruction *,oi, dk_fig_dcc *,dcc)
{
  int back = 1;
  if(!diagonal_left_30(oi, dcc)) { back = 0; }
  if(!diagonal_right_30(oi, dcc)) { back = 0; }
  return back;
}



/**	Fill pattern: 45 degree lines to the left.
	@param	oi	MetaPost output instruction structure.
	@param	dcc	Color cell structure.
	@return	1 on success, 0 on error.
*/
static int
diagonal_left_45 DK_P2(dkfig_mp_output_instruction *,oi, dk_fig_dcc *,dcc)
{
  int back = 1;
  int me = 0;
  double xstart, xend, ystart, yend, y0, y1, deltay, y;
  ystart = (oi->obb).ymin; yend = (oi->obb).ymax;
  xstart = (oi->obb).xmin; xend = (oi->obb).xmax;
  deltay = fabs(oi->patrp);
  deltay = dkma_div_double_ok(deltay, sqrt(0.5), &me);
  if(((oi->c)->opt1) & DKFIG_OPT_FILL_CONTIGOUS) {
    y0 = dkma_add_double_ok(
      ystart,
      xstart,
      &me
    );
    y0 = dkma_div_double_ok(y0, deltay, &me);
    y1 = floor(y0);
    y0 = dkma_sub_double_ok(y0, y1, &me);
    y0 = dkma_mul_double_ok(y0, deltay, &me);
    ystart = dkma_sub_double_ok(ystart, y0, &me);
  }
  y1 = dkma_sub_double_ok(xend, xstart, &me);
  /* y1 = dkma_mul_double_ok(sqrt(0.5), y1, &me); */
  yend = dkma_add_double_ok(yend, y1, &me);
  y = ystart;
  while(y <= yend) {
    start_addto(oi);
    write_noconv_double_point(oi, xstart, y, 2);
    kw_to_stream(oi->s, 6);
    write_noconv_double_point(oi, xend, dkma_sub_double_ok(y,y1,&me), 2);
    end_addto(oi, dcc);
    y = dkma_add_double_ok(y, deltay, &me);
  }
  if(me) { oi->me = me; back = 0; }
  return back;
}



/**	Fill pattern: 45 degree lines to the right.
	@param	oi	MetaPost output instruction structure.
	@param	dcc	Color cell structure.
	@return	1 on success, 0 on error.
*/
static int
diagonal_right_45 DK_P2(dkfig_mp_output_instruction *,oi, dk_fig_dcc *,dcc)
{
  int back = 1;
  int me = 0;
  double xstart, xend, ystart, yend, y0, y1, deltay, y;
  ystart = (oi->obb).ymin; yend = (oi->obb).ymax;
  xstart = (oi->obb).xmin; xend = (oi->obb).xmax;
  deltay = fabs(oi->patrp);
  deltay = dkma_div_double_ok(deltay, sqrt(0.5), &me);
  y1 = dkma_sub_double_ok(xend, xstart, &me);
  /* y1 = dkma_mul_double_ok(0.5, y1, &me); */
  ystart = dkma_sub_double_ok(ystart, y1, &me);
  if(((oi->c)->opt1) & DKFIG_OPT_FILL_CONTIGOUS) {
    y0 = dkma_sub_double_ok(
      ystart,
      xstart,
      &me
    );
    y0 = dkma_div_double_ok(y0, deltay, &me);
    y1 = floor(y0);
    y0 = dkma_sub_double_ok(y0, y1, &me);
    y0 = dkma_mul_double_ok(y0, deltay, &me);
    ystart = dkma_sub_double_ok(ystart, y0, &me);
  }
  y1 = dkma_sub_double_ok(xend, xstart, &me);
  /* y1 = dkma_mul_double_ok(sqrt(0.5), y1, &me); */
  y = ystart;
  while(y <= yend) {
    start_addto(oi);
    write_noconv_double_point(oi, xstart, y, 2);
    kw_to_stream(oi->s, 6);
    write_noconv_double_point(oi, xend, dkma_add_double_ok(y,y1,&me), 2);
    end_addto(oi, dcc);
    y = dkma_add_double_ok(y, deltay, &me);
  }
  if(me) { oi->me = me; back = 0; }
  return back;
}



/**	Fill pattern: 45 degree crosshatch.
	@param	oi	MetaPost output instruction structure.
	@param	dcc	Color cell structure.
	@return	1 on success, 0 on error.
*/
static int
crosshatch_45 DK_P2(dkfig_mp_output_instruction *,oi, dk_fig_dcc *,dcc)
{
  int back = 1;
  if(!diagonal_left_45(oi, dcc)) { back = 0; }
  if(!diagonal_right_45(oi, dcc)) { back = 0; }
  return back;
}



/**	Fill pattern: horizontal bricks.
	@param	oi	MetaPost output instruction structure.
	@param	dcc	Color cell structure.
	@return	1 on success, 0 on error.
*/
static int
horizontal_bricks DK_P2(dkfig_mp_output_instruction *,oi, dk_fig_dcc *,dcc)
{
  int back = 1;
  int me = 0;
  int inslevel = 0;
  double xstart, ystart, xend, yend, deltay, y, x;
  ystart = (oi->obb).ymin; yend = (oi->obb).ymax;
  xstart = (oi->obb).xmin; xend = (oi->obb).xmax;
  deltay = fabs(oi->patrp);
  deltay = dkma_mul_double_ok(2.0, deltay, &me);
  if(((oi->c)->opt1) & DKFIG_OPT_FILL_CONTIGOUS) {
    ystart = floor(dkma_div_double_ok(ystart, deltay, &me));
    if((dkma_double_to_l(ystart)) % 2L) {
      inslevel = 1;
    }
    ystart = dkma_mul_double_ok(deltay, ystart, &me);
    xstart = dkma_sub_double_ok(xstart, deltay, &me);
    xstart = floor(dkma_div_double_ok(xstart,dkma_mul_double_ok(2.0,deltay,&me),&me));
    xstart = dkma_mul_double_ok(xstart,dkma_mul_double_ok(2.0,deltay,&me),&me);
  }
  y = ystart;
  while(y <= yend) {
    start_addto(oi);
    write_noconv_double_point(oi, xstart, y, 1);
    kw_to_stream(oi->s, 6);
    write_noconv_double_point(oi, xend, y, 1);
    end_addto(oi, dcc);
    x = xstart;
    if(inslevel) { x = dkma_add_double_ok(x, deltay, &me); }
    while(x <= xend) {
      start_addto(oi);
      write_noconv_double_point(oi, x, y, 1);
      kw_to_stream(oi->s, 6);
      write_noconv_double_point(oi, x, dkma_add_double_ok(y, deltay, &me), 1);
      end_addto(oi, dcc);
      x = dkma_add_double_ok(x,dkma_mul_double_ok(2.0,deltay,&me),&me);
    }
    y = dkma_add_double_ok(y, deltay, &me);
    inslevel = (inslevel ? 0: 1);
  }
  if(me) { oi->me = me; back = 0; }
  return back;
}



/**	Fill pattern: vertical bricks.
	@param	oi	MetaPost output instruction structure.
	@param	dcc	Color cell structure.
	@return	1 on success, 0 on error.
*/
static int
vertical_bricks DK_P2(dkfig_mp_output_instruction *,oi, dk_fig_dcc *,dcc)
{
  int back = 1;
  int me = 0;
  int inslevel = 0;
  double xstart, ystart, xend, yend, deltax, x, y;
  ystart = (oi->obb).ymin; yend = (oi->obb).ymax;
  xstart = (oi->obb).xmin; xend = (oi->obb).xmax;
  deltax = fabs(dkma_mul_double_ok(2.0,oi->patrp,&me));
  if(((oi->c)->opt1) & DKFIG_OPT_FILL_CONTIGOUS) {
    xstart = floor(dkma_div_double_ok(xstart, deltax, &me));
    if(dkma_double_to_l(xstart) % 2L) {
      inslevel = 1;
    }
    xstart = dkma_mul_double_ok(deltax, xstart, &me);
    ystart = dkma_sub_double_ok(ystart, deltax, &me);
    ystart = floor(dkma_div_double_ok(ystart,dkma_mul_double_ok(2.0,deltax,&me),&me));
    ystart = dkma_mul_double_ok(ystart,dkma_mul_double_ok(2.0,deltax,&me),&me);
  }
  x = xstart;
  while(x <= xend) {
    start_addto(oi);
    write_noconv_double_point(oi, x, ystart, 1);
    kw_to_stream(oi->s, 6);
    write_noconv_double_point(oi, x, yend, 1);
    end_addto(oi, dcc);
    y = ystart;
    if(inslevel) { y = dkma_add_double_ok(y,deltax,&me); }
    while(y <= yend) {
      start_addto(oi);
      write_noconv_double_point(oi, x, y, 1);
      kw_to_stream(oi->s, 6);
      write_noconv_double_point(oi, dkma_add_double_ok(x,deltax,&me), y, 1);
      end_addto(oi, dcc);
      y = dkma_add_double_ok(y,dkma_mul_double_ok(2.0,deltax,&me),&me);
    }
    x = dkma_add_double_ok(x, deltax, &me);
    inslevel = (inslevel ? 0 : 1);
  }
  if(me) { oi->me = me; back = 0; }
  return back;
}



/**	Fill pattern: Horizontal lines.
	@param	oi	MetaPost output instruction structure.
	@param	dcc	Color cell structure.
	@return	1 on success, 0 on error.
*/
static int
horizontal_lines DK_P2(dkfig_mp_output_instruction *,oi, dk_fig_dcc *,dcc)
{
  int back = 1;
  int me = 0;
  double xstart, ystart, xend, yend, deltay, y;
  ystart = (oi->obb).ymin; yend = (oi->obb).ymax;
  xstart = (oi->obb).xmin; xend = (oi->obb).xmax;
  deltay = fabs(oi->patrp);
  if(((oi->c)->opt1) & DKFIG_OPT_FILL_CONTIGOUS) {
    ystart = dkma_mul_double_ok(
      deltay,
      floor(dkma_div_double_ok(ystart, deltay, &me)),
      &me
    );
  }
  y = ystart;
  while(y <= yend) {
    start_addto(oi);
    write_noconv_double_point(oi, xstart, y, 1);
    kw_to_stream(oi->s, 6);
    write_noconv_double_point(oi, xend, y, 1);
    end_addto(oi, dcc);
    y = dkma_add_double_ok(y, deltay, &me);
  }
  if(me) { oi->me = me; back = 0; }
  return back;
}



/**	Fill pattern: Vertical lines.
	@param	oi	MetaPost output instruction structure.
	@param	dcc	Color cell structure.
	@return	1 on success, 0 on error.
*/
static int
vertical_lines DK_P2(dkfig_mp_output_instruction *,oi, dk_fig_dcc *,dcc)
{
  int back = 1;
  int me = 0;
  double xstart, ystart, xend, yend, deltax, x;
  ystart = (oi->obb).ymin; yend = (oi->obb).ymax;
  xstart = (oi->obb).xmin; xend = (oi->obb).xmax;
  deltax = fabs(oi->patrp);
  if(((oi->c)->opt1) & DKFIG_OPT_FILL_CONTIGOUS) {
    xstart = dkma_mul_double_ok(
      deltax,
      floor(dkma_div_double_ok(xstart, deltax, &me)),
      &me
    );
  }
  x = xstart;
  while(x <= xend) {
    start_addto(oi);
    write_noconv_double_point(oi, x, ystart, 1);
    kw_to_stream(oi->s, 6);
    write_noconv_double_point(oi, x, yend, 1);
    end_addto(oi, dcc);
    x = dkma_add_double_ok(x, deltax, &me);
  }
  if(me) { oi->me = me; back = 0; }
  return back;
}



/**	Fill pattern: Crosshatch.
	@param	oi	MetaPost output instruction structure.
	@param	dcc	Color cell structure.
	@return	1 on success, 0 on error.
*/
static int
crosshatch DK_P2(dkfig_mp_output_instruction *,oi, dk_fig_dcc *,dcc)
{
  int back = 1;
  if(!horizontal_lines(oi, dcc)) { back = 0; }
  if(!vertical_lines(oi, dcc)) { back = 0; }
  return back;
}



/**	Fill pattern: Horizontal shingles skewed to the right.
	@param	oi	MetaPost output instruction structure.
	@param	dcc	Color cell structure.
	@return	1 on success, 0 on error.
*/
static int
horiz_shingles_right DK_P2(dkfig_mp_output_instruction *,oi, dk_fig_dcc *,dcc)
{
  int back = 1;
  int me = 0;
  int inslevel = 0;
  double xstart, ystart, xend, yend, deltay, y, x, deltax;
  ystart = (oi->obb).ymin; yend = (oi->obb).ymax;
  xstart = (oi->obb).xmin; xend = (oi->obb).xmax;
  deltax = deltay = fabs(oi->patrp);
  deltay = dkma_mul_double_ok(2.0, deltay, &me);
  if(((oi->c)->opt1) & DKFIG_OPT_FILL_CONTIGOUS) {
    ystart = floor(dkma_div_double_ok(ystart,deltay,&me));
    inslevel = (int)(dkma_double_to_l(ystart) % 4L);
    ystart = dkma_mul_double_ok(deltay,ystart,&me);
    xstart = dkma_sub_double_ok(xstart, deltay, &me);
    xstart = floor(dkma_div_double_ok(xstart,dkma_mul_double_ok(2.0,deltay,&me),&me));
    xstart = dkma_mul_double_ok(xstart,dkma_mul_double_ok(2.0,deltay,&me),&me);
  }
  y = ystart;
  while(y <= yend) {
    start_addto(oi);
    write_noconv_double_point(oi, xstart, y, 1);
    kw_to_stream(oi->s, 6);
    write_noconv_double_point(oi, xend, y, 1);
    end_addto(oi, dcc);
    /*
    x = xstart;
    if(inslevel) { x = dkma_add_double_ok(x, deltay, &me); }
    */
    switch(inslevel) {
      case 3: {
        x = dkma_add_double_ok(xstart,deltax,&me);
      } break;
      case 2: {
        x = dkma_add_double_ok(xstart,deltay,&me);
      } break;
      case 1: {
        x = dkma_add_double_ok(xstart,dkma_mul_double_ok(1.5,deltay,&me),&me);
      } break;
      default: {
        x = xstart;
      } break;
    }
    while(x <= xend) {
      start_addto(oi);
      write_noconv_double_point(oi, x, y, 1);
      kw_to_stream(oi->s, 6);
      write_noconv_double_point(oi, dkma_add_double_ok(x,deltax,&me), dkma_add_double_ok(y, deltay, &me), 1);
      end_addto(oi, dcc);
      x = dkma_add_double_ok(x,dkma_mul_double_ok(2.0,deltay,&me),&me);
    }
    y = dkma_add_double_ok(y, deltay, &me);
    inslevel++;
    if(inslevel >= 4) { inslevel = 0; }
  }
  if(me) { oi->me = me; back = 0; }
  return back;
}



/**	Fill pattern: Horizontal shingles skewed to the left.
	@param	oi	MetaPost output instruction structure.
	@param	dcc	Color cell structure.
	@return	1 on success, 0 on error.
*/
static int
horiz_shingles_left DK_P2(dkfig_mp_output_instruction *,oi, dk_fig_dcc *,dcc)
{
  int back = 1;
  int me = 0;
  int inslevel = 0;
  double xstart, ystart, xend, yend, deltay, y, x, deltax;
  ystart = (oi->obb).ymin; yend = (oi->obb).ymax;
  xstart = (oi->obb).xmin; xend = (oi->obb).xmax;
  deltax = deltay = fabs(oi->patrp);
  deltay = dkma_mul_double_ok(2.0, deltay, &me);
  if(((oi->c)->opt1) & DKFIG_OPT_FILL_CONTIGOUS) {
    ystart = floor(dkma_div_double_ok(ystart,deltay,&me));
    inslevel = (int)(dkma_double_to_l(ystart) % 4L);
    ystart = dkma_mul_double_ok(deltay,ystart,&me);
    xstart = dkma_sub_double_ok(xstart, deltay, &me);
    xstart = floor(dkma_div_double_ok(xstart,dkma_mul_double_ok(2.0,deltay,&me),&me));
    xstart = dkma_mul_double_ok(xstart,dkma_mul_double_ok(2.0,deltay,&me),&me);
  }
  y = ystart;
  while(y <= yend) {
    start_addto(oi);
    write_noconv_double_point(oi, xstart, y, 1);
    kw_to_stream(oi->s, 6);
    write_noconv_double_point(oi, xend, y, 1);
    end_addto(oi, dcc);
    /*
    x = xstart;
    if(inslevel) { x = dkma_add_double_ok(x, deltay, &me); }
    */
    switch(inslevel) {
      case 3: {
        x = dkma_add_double_ok(xstart,dkma_add_double_ok(deltax,deltay,&me),&me);
      } break;
      case 2: {
        x = dkma_add_double_ok(xstart,deltay,&me);
      } break;
      case 1: {
        x = dkma_add_double_ok(xstart,deltax,&me);
      } break;
      default: {
        x = xstart;
      } break;
    }
    while(x <= xend) {
      start_addto(oi);
      write_noconv_double_point(oi, dkma_add_double_ok(x,deltax,&me), y, 1);
      kw_to_stream(oi->s, 6);
      write_noconv_double_point(oi, x, dkma_add_double_ok(y, deltay, &me), 1);
      end_addto(oi, dcc);
      x = dkma_add_double_ok(x,dkma_mul_double_ok(2.0,deltay,&me),&me);
    }
    y = dkma_add_double_ok(y, deltay, &me);
    inslevel++;
    if(inslevel >= 4) { inslevel = 0; }
  }
  if(me) { oi->me = me; back = 0; }
  return back;
}



/**	Fill pattern: Vertical shingles 1.
	@param	oi	MetaPost output instruction structure.
	@param	dcc	Color cell structure.
	@return	1 on success, 0 on error.
*/
static int
vert_shingles_one DK_P2(dkfig_mp_output_instruction *,oi, dk_fig_dcc *,dcc)
{
  int back = 1;
  int me = 0;
  int inslevel = 0;
  double xstart, ystart, xend, yend, deltay, deltax, x, y;
  ystart = (oi->obb).ymin; yend = (oi->obb).ymax;
  xstart = (oi->obb).xmin; xend = (oi->obb).xmax;
  deltay = deltax = fabs(oi->patrp);
  deltax = dkma_mul_double_ok(2.0, deltax, &me);
  if(((oi->c)->opt1) & DKFIG_OPT_FILL_CONTIGOUS) {
    xstart = floor(dkma_div_double_ok(xstart, deltax, &me));
    inslevel = (int)(dkma_double_to_l(xstart) % 4L);
    xstart = dkma_mul_double_ok(deltax, xstart, &me);
    ystart = floor(dkma_div_double_ok(ystart,dkma_mul_double_ok(2.0,deltax,&me),&me));
    ystart = dkma_mul_double_ok(ystart,dkma_mul_double_ok(2.0,deltax,&me),&me);
  }
  x = xstart;
  while(x <= xend) {
    start_addto(oi);
    write_noconv_double_point(oi, x, ystart, 1);
    kw_to_stream(oi->s, 6);
    write_noconv_double_point(oi, x, yend, 1);
    end_addto(oi, dcc);
    switch(inslevel) {
      case 3: {
        y = dkma_add_double_ok(ystart,dkma_add_double_ok(deltax,deltay,&me),&me);
      } break;
      case 2: {
        y = dkma_add_double_ok(ystart,deltax,&me);
      } break;
      case 1: {
        y = dkma_add_double_ok(ystart,deltay,&me);
      } break;
      default: {
        y = ystart;
      } break;
    }
    while(y <= yend) {
      start_addto(oi);
      write_noconv_double_point(oi, x, dkma_add_double_ok(y,deltay,&me), 1);
      kw_to_stream(oi->s, 6);
      write_noconv_double_point(oi, dkma_add_double_ok(x,deltax,&me), y, 1);
      end_addto(oi, dcc);
      y = dkma_add_double_ok(y,dkma_mul_double_ok(2.0,deltax,&me),&me);
    }
    x = dkma_add_double_ok(x, deltax, &me); inslevel++;
    if(inslevel >= 4) { inslevel = 0; }
  }
  if(me) { oi->me = me; back = 0; }
  return back;
}



/**	Fill pattern: Vertical shingles 2.
	@param	oi	MetaPost output instruction structure.
	@param	dcc	Color cell structure.
	@return	1 on success, 0 on error.
*/
static int
vert_shingles_two DK_P2(dkfig_mp_output_instruction *,oi, dk_fig_dcc *,dcc)
{
  int back = 1;
  int me = 0;
  int inslevel = 0;
  double xstart, ystart, xend, yend, deltay, deltax, x, y;
  ystart = (oi->obb).ymin; yend = (oi->obb).ymax;
  xstart = (oi->obb).xmin; xend = (oi->obb).xmax;
  deltay = deltax = fabs(oi->patrp);
  deltax = dkma_mul_double_ok(2.0, deltax, &me);
  if(((oi->c)->opt1) & DKFIG_OPT_FILL_CONTIGOUS) {
    xstart = floor(dkma_div_double_ok(xstart, deltax, &me));
    inslevel = (int)(dkma_double_to_l(xstart) % 4L);
    xstart = dkma_mul_double_ok(deltax, xstart, &me);
    ystart = floor(dkma_div_double_ok(ystart,dkma_mul_double_ok(2.0,deltax,&me),&me));
    ystart = dkma_mul_double_ok(ystart,dkma_mul_double_ok(2.0,deltax,&me),&me);
  }
  x = xstart;
  while(x <= xend) {
    start_addto(oi);
    write_noconv_double_point(oi, x, ystart, 1);
    kw_to_stream(oi->s, 6);
    write_noconv_double_point(oi, x, yend, 1);
    end_addto(oi, dcc);
    switch(inslevel) {
      case 3: {
        y = dkma_add_double_ok(ystart,deltay,&me);
      } break;
      case 2: {
        y = dkma_add_double_ok(ystart,deltax,&me);
      } break;
      case 1: {
        y = dkma_add_double_ok(ystart,dkma_add_double_ok(deltax,deltay,&me),&me);
      } break;
      default: {
        y = ystart;
      } break;
    }
    while(y <= yend) {
      start_addto(oi);
      write_noconv_double_point(oi, x, y, 1);
      kw_to_stream(oi->s, 6);
      write_noconv_double_point(
        oi,
	dkma_add_double_ok(x,deltax,&me),
	dkma_add_double_ok(y,deltay,&me)
      , 1);
      end_addto(oi, dcc);
      y = dkma_add_double_ok(y,dkma_mul_double_ok(2.0,deltax,&me),&me);
    }
    x = dkma_add_double_ok(x, deltax, &me); inslevel++;
    if(inslevel >= 4) { inslevel = 0; }
  }
  if(me) { oi->me = me; back = 0; }
  return back;
}



/** Fill pattern: Fish scales.
	@param	oi	MetaPost output instruction structure.
	@param	ar	Arc start angle.
	@param	phi	Arc width angle.
	@param	dcc	Color cell structure.
	@return	1 on success, 0 on error.
*/
static int
do_fish_scales DK_P4(dkfig_mp_output_instruction *,oi, double,ar, double,phi, dk_fig_dcc *,dcc)
{
  int back = 1;
  int me = 0;
  int inslevel = 0;
  double radius, xstart, ystart, xend, yend, deltax, dxh, deltay;
  double x, y, xm, ym;
  double cutx, cuty, rot, cuts;
  ystart = (oi->obb).ymin; yend = (oi->obb).ymax;
  xstart = (oi->obb).xmin; xend = (oi->obb).xmax;
  radius = dkma_mul_double_ok(2.0, fabs(oi->patrp), &me);
  radius = dkma_mul_double_ok(ar, radius, &me);
  deltax = dkma_mul_double_ok(2.0, dkma_mul_double_ok(radius, sin(phi/2.0), &me), &me);
  deltax = drd(deltax, oi->c, 2);
  dxh = 0.5 * deltax;
  deltay = dkma_mul_double_ok(radius,dkma_sub_double_ok(1.0,cos(phi/2.0),&me),&me);
  deltay = drd(deltay, oi->c, 2);
  rot = 1.5 * M_PI - 0.5 * phi;
  rot = dkma_sub_double_ok(
    dkma_mul_double_ok(1.5, M_PI, &me),
    dkma_mul_double_ok(0.5, phi, &me),
    &me
  );
  rot = dkma_div_double_ok(
    dkma_mul_double_ok(180.0, rot, &me),
    M_PI,
    &me
  );
  rot = drd(rot, oi->c, 2);
  xstart = dkma_sub_double_ok(xstart, dxh, &me);
  if(((oi->c)->opt1) & DKFIG_OPT_FILL_CONTIGOUS) {
    xstart = floor(dkma_div_double_ok(xstart, deltax, &me));
    if(dkma_double_to_l(xstart) % 2L) {
      inslevel = 1;
    }
    xstart = dkma_mul_double_ok(deltax, xstart, &me);
    ystart = floor(dkma_div_double_ok(ystart, deltay, &me));
    ystart = dkma_mul_double_ok(deltay, ystart, &me);
  }
  cutx = 1.25 * cos(phi);
  cuty = 1.25 * sin(phi);
  cuts = dkma_mul_double_ok(2.0, radius, &me);
  y = ystart;
  while(y <= yend) {
    ym = dkma_add_double_ok(y, radius, &me);
    x = xstart;
    if(inslevel) {
      x = dkma_add_double_ok(x, dxh, &me);
    }
    while(x <= xend) {
      xm = dkma_add_double_ok(x, dxh, &me);
      start_addto(oi);
      kw_to_stream(oi->s, 2);
      kw_to_stream(oi->s, 2);
      kw_to_stream(oi->s, 2);
      kw_to_stream(oi->s, 58);	/* fullcircle */
      kw_to_stream(oi->s, 1);
      kw_to_stream(oi->s, 66);	/* cutafter */
      kw_to_stream(oi->s, 2);
      kw_to_stream(oi->s, 98);
      kw_to_stream(oi->s, 6);
      write_noconv_double_point(oi, cutx, cuty, 2);
      kw_to_stream(oi->s, 3);
      kw_to_stream(oi->s, 3);
      kw_to_stream(oi->s, 0);
      kw_to_stream(oi->s, 38);
      kw_to_stream(oi->s, 1);
      stream_puts_double(oi->s, rot, 2, oi->c);
      kw_to_stream(oi->s, 3);
      kw_to_stream(oi->s, 1);
      kw_to_stream(oi->s, 49);
      kw_to_stream(oi->s, 1);
      stream_puts_double(oi->s, cuts, 2, oi->c);
      kw_to_stream(oi->s, 3);
      kw_to_stream(oi->s, 1);
      kw_to_stream(oi->s, 57);
      kw_to_stream(oi->s, 1);
      write_noconv_double_point(oi, xm, ym, 2);
      end_addto(oi, dcc);
      x = dkma_add_double_ok(x, deltax, &me);
    }
    y = dkma_add_double_ok(y, deltay, &me);
    inslevel = (inslevel ? 0 : 1);
  }
  if(me) { oi->me = me; back = 0; }
  return back;
}



/**	Fill pattern: Large fish scales.
	@param	oi	MetaPost output instruction structure.
	@param	dcc	Color cell structure.
	@return	1 on success, 0 on error.
*/
static int
large_fish_scales DK_P2(dkfig_mp_output_instruction *,oi, dk_fig_dcc *,dcc)
{
  int back = 1;
  back = do_fish_scales(oi, 1.25, 1.881618, dcc);
  return back;
}



/**	Fill pattern: Small fish scales.
	@param	oi	MetaPost output instruction structure.
	@param	dcc	Color cell structure.
	@return	1 on success, 0 on error.
*/
static int
small_fish_scales DK_P2(dkfig_mp_output_instruction *,oi, dk_fig_dcc *,dcc)
{
  int back = 1;
  back = do_fish_scales(oi, 0.5, M_PI, dcc);
  return back;
}



/**	Fill pattern: Circles.
	@param	oi	MetaPost output instruction structure.
	@param	dcc	Color cell structure,
	@return	1 on success, 0 on error.
*/
static int
circles DK_P2(dkfig_mp_output_instruction *,oi, dk_fig_dcc *,dcc)
{
  int back = 1;
  int me = 0;
  double xstart, ystart, xend, yend, deltay, deltax, x, y, r, xm;
  ystart = (oi->obb).ymin; yend = (oi->obb).ymax;
  xstart = (oi->obb).xmin; xend = (oi->obb).xmax;
  r = dkma_mul_double_ok(2.0, fabs(oi->patrp), &me);
  deltay = deltax = dkma_mul_double_ok(2.0, r, &me);
  if(((oi->c)->opt1) & DKFIG_OPT_FILL_CONTIGOUS) {
    xstart = floor(dkma_div_double_ok(xstart, deltax, &me));
    xstart = dkma_mul_double_ok(deltax, xstart, &me);
    ystart = floor(dkma_div_double_ok(ystart, deltay, &me));
    ystart = dkma_mul_double_ok(deltay, ystart, &me);
  }
  x = xstart;
  while(x <= xend) {
    y = ystart;
    xm = dkma_add_double_ok(x, r, &me);
    while(y <= yend) {
      start_addto(oi);
      kw_to_stream(oi->s, 2);
      kw_to_stream(oi->s, 58);	/* fullcircle */
      kw_to_stream(oi->s, 1);
      kw_to_stream(oi->s, 49);	/* scaled */
      kw_to_stream(oi->s, 1);
      stream_puts_double(oi->s, deltay, 1, oi->c);
      kw_to_stream(oi->s, 73);	/* bp */
      kw_to_stream(oi->s, 3);
      kw_to_stream(oi->s, 1);
      kw_to_stream(oi->s, 57);
      kw_to_stream(oi->s, 1);
      write_noconv_double_point(
        oi,
	xm,
	dkma_add_double_ok(y, r, &me)
      , 1);
      end_addto(oi, dcc);
      y = dkma_add_double_ok(y, deltay, &me);
    }
    x = dkma_add_double_ok(x, deltax, &me);
  }
  if(me) { oi->me = me; back = 0; }
  return back;
}



/**	Fill pattern: Hexagons.
	@param	oi	MetaPost output instruction structure.
	@param	dcc	Color cell structure.
	@return	1 on success, 0 on error.
*/
static int
hexagons DK_P2(dkfig_mp_output_instruction *,oi, dk_fig_dcc *,dcc)
{
  int back = 1;
  int me = 0;
  double xstart, ystart, xend, yend, deltay, deltax, x, y, r;
  double x1, x2, x3, x4, y1, y2;
  ystart = (oi->obb).ymin; yend = (oi->obb).ymax;
  xstart = (oi->obb).xmin; xend = (oi->obb).xmax;
  r = dkma_mul_double_ok(2.0, fabs(oi->patrp), &me);
  deltay = deltax = dkma_mul_double_ok(2.0, r, &me);
  r = dkma_div_double_ok(deltay, sqrt(3.0), &me);
  deltax = dkma_mul_double_ok(3.0, r, &me);
  if(((oi->c)->opt1) & DKFIG_OPT_FILL_CONTIGOUS) {
    xstart = floor(dkma_div_double_ok(xstart, deltax, &me));
    xstart = dkma_mul_double_ok(deltax, xstart, &me);
    ystart = floor(dkma_div_double_ok(ystart, deltay, &me));
    ystart = dkma_mul_double_ok(deltay, ystart, &me);
  }
  x = xstart;
  while(x <= xend) {
    x1 = dkma_add_double_ok(x, dkma_mul_double_ok(0.5, r, &me), &me);
    x2 = dkma_add_double_ok(x, dkma_mul_double_ok(1.5, r, &me), &me);
    x3 = dkma_add_double_ok(x, dkma_mul_double_ok(2.0, r, &me), &me);
    x4 = dkma_add_double_ok(x, dkma_mul_double_ok(3.0, r, &me), &me);
    y = ystart;
    while(y <= yend) {
      y1 = dkma_add_double_ok(y, dkma_mul_double_ok(0.5, deltay, &me), &me);
      y2 = dkma_add_double_ok(y, deltay, &me);
      start_addto(oi);
      write_noconv_double_point(oi, x, y1, 2);
      kw_to_stream(oi->s, 6);
      write_noconv_double_point(oi, x1, y, 2);
      kw_to_stream(oi->s, 6);
      write_noconv_double_point(oi, x2, y, 2);
      kw_to_stream(oi->s, 6);
      write_noconv_double_point(oi, x3, y1, 2);
      kw_to_stream(oi->s, 6);
      write_noconv_double_point(oi, x2, y2, 2);
      kw_to_stream(oi->s, 6);
      write_noconv_double_point(oi, x1, y2, 2);
      kw_to_stream(oi->s, 6);
      kw_to_stream(oi->s, 59);
      end_addto(oi, dcc);
      start_addto(oi);
      write_noconv_double_point(oi, x3, y1, 2);
      kw_to_stream(oi->s, 6);
      write_noconv_double_point(oi, x4, y1, 2);
      end_addto(oi, dcc);
      y  = y2;
    }
    x = dkma_add_double_ok(x, deltax, &me);
  }
  if(me) { oi->me = me; back = 0; }
  return back;
}



/**	Fill pattern: Octagons.
	@param	oi	MetaPost output instruction structure.
	@param	dcc	Color cell structure.
	@return	1 on success, 0 on error.
*/
static int
octagons DK_P2(dkfig_mp_output_instruction *,oi, dk_fig_dcc *,dcc)
{
  int back = 1;
  int me = 0;
  double xstart, ystart, xend, yend, deltay, deltax, x, y, r;
  double x1, x2, x3, y1, y2, y3;
  ystart = (oi->obb).ymin; yend = (oi->obb).ymax;
  xstart = (oi->obb).xmin; xend = (oi->obb).xmax;
  r = dkma_mul_double_ok(2.0, fabs(oi->patrp), &me);
  deltay = deltax = dkma_mul_double_ok(2.0, r, &me);
  r = dkma_div_double_ok(
    deltay, dkma_add_double_ok(2.0,sqrt(2.0),&me), &me
  ); r = drd(r, oi->c, 1);
  if(((oi->c)->opt1) & DKFIG_OPT_FILL_CONTIGOUS) {
    xstart = floor(dkma_div_double_ok(xstart, deltax, &me));
    xstart = dkma_mul_double_ok(deltax, xstart, &me);
    ystart = floor(dkma_div_double_ok(ystart, deltay, &me));
    ystart = dkma_mul_double_ok(deltay, ystart, &me);
  }
  x = xstart;
  while(x <= xend) {
    y = ystart;
    x1 = dkma_add_double_ok(x, r, &me);
    x3 = dkma_add_double_ok(x, deltax, &me);
    x2 = dkma_sub_double_ok(x3, r, &me);
    while(y <= yend) {
      y1 = dkma_add_double_ok(y, r, &me);
      y3 = dkma_add_double_ok(y, deltay, &me);
      y2 = dkma_sub_double_ok(y3, r, &me);
      start_addto(oi);
      write_noconv_double_point(oi, x1, y, 1);
      kw_to_stream(oi->s, 6);
      write_noconv_double_point(oi, x2, y, 1);
      kw_to_stream(oi->s, 6);
      write_noconv_double_point(oi, x3, y1, 1);
      kw_to_stream(oi->s, 6);
      write_noconv_double_point(oi, x3, y2, 1);
      kw_to_stream(oi->s, 0);
      kw_to_stream(oi->s, 6);
      write_noconv_double_point(oi, x2, y3, 1);
      kw_to_stream(oi->s, 6);
      write_noconv_double_point(oi, x1, y3, 1);
      kw_to_stream(oi->s, 6);
      write_noconv_double_point(oi, x, y2, 1);
      kw_to_stream(oi->s, 6);
      write_noconv_double_point(oi, x, y1, 1);
      kw_to_stream(oi->s, 6);
      kw_to_stream(oi->s, 59);
      end_addto(oi, dcc);
      y = dkma_add_double_ok(y, deltay, &me);
    }
    x = dkma_add_double_ok(x, deltax, &me);
  }
  if(me) { oi->me = me; back = 0; }
  return back;
}



/**	Fill pattern: Horizontal tires.
	@param	oi	MetaPost output instruction structure.
	@param	dcc	Color cell structure.
	@return	1 on success, 0 on error.
*/
static int
horiz_tires DK_P2(dkfig_mp_output_instruction *,oi, dk_fig_dcc *,dcc)
{
  int back = 1;
  int me = 0;
  double xstart, ystart, xend, yend, deltax, deltay, x, y, y1;
  ystart = (oi->obb).ymin; yend = (oi->obb).ymax;
  xstart = (oi->obb).xmin; xend = (oi->obb).xmax;
  deltax =  fabs(oi->patrp);
  deltay = dkma_mul_double_ok(2.0, deltax, &me);
  if(((oi->c)->opt1) & DKFIG_OPT_FILL_CONTIGOUS) {
    ystart = dkma_mul_double_ok(
      deltay,
      floor(dkma_div_double_ok(ystart, deltay, &me)),
      &me
    );
    xstart = dkma_mul_double_ok(
      deltay,
      floor(dkma_div_double_ok(xstart, deltay, &me)),
      &me
    );
  }
  y = ystart;
  while(y <= yend) {
    y1 = dkma_add_double_ok(y, deltax, &me);
    start_addto(oi);
    x = xstart;
    write_noconv_double_point(oi,x,y, 1);
    while(x <= xend) {
      kw_to_stream(oi->s, 0);
      kw_to_stream(oi->s, 6);
      x = dkma_add_double_ok(x, deltax, &me);
      write_noconv_double_point(oi,x,y1, 1);
      kw_to_stream(oi->s, 6);
      x = dkma_add_double_ok(x, deltax, &me);
      write_noconv_double_point(oi,x,y, 1);
    }
    end_addto(oi, dcc);
    y = dkma_add_double_ok(y, deltay, &me);
  }
  if(me) { oi->me = me; back = 0; }
  return back;
}



/**	Fill pattern: Vertical tires.
	@param	oi	MetaPost output instruction structure.
	@param	dcc	Color cell structure.
	@return	1 on success, 0 on error.
*/
static int
vert_tires DK_P2(dkfig_mp_output_instruction *,oi, dk_fig_dcc *,dcc)
{
  int back = 1;
  int me = 0;
  double xstart, ystart, xend, yend, deltax, deltay, x, y, x1;
  ystart = (oi->obb).ymin; yend = (oi->obb).ymax;
  xstart = (oi->obb).xmin; xend = (oi->obb).xmax;
  deltay =  fabs(oi->patrp);
  deltax = dkma_mul_double_ok(2.0, deltay, &me);
  if(((oi->c)->opt1) & DKFIG_OPT_FILL_CONTIGOUS) {
    ystart = dkma_mul_double_ok(
      deltax,
      floor(dkma_div_double_ok(ystart, deltax, &me)),
      &me
    );
    xstart = dkma_mul_double_ok(
      deltax,
      floor(dkma_div_double_ok(xstart, deltax, &me)),
      &me
    );
  }
  x = xstart;
  while(x <= xend) {
    x1 = dkma_add_double_ok(x, deltay, &me);
    y = ystart;
    start_addto(oi);
    write_noconv_double_point(oi,x,y, 1);
    while(y <= yend) {
      y = dkma_add_double_ok(y, deltay, &me);
      kw_to_stream(oi->s, 0);
      kw_to_stream(oi->s, 6);
      write_noconv_double_point(oi,x1,y, 1);
      y = dkma_add_double_ok(y, deltay, &me);
      kw_to_stream(oi->s, 6);
      write_noconv_double_point(oi,x,y, 1);
    }
    end_addto(oi, dcc);
    x = dkma_add_double_ok(x, deltax, &me);
  }
  return back;
}



/**	Write dash pattern for dashed lines.
	@param	oi	MetaPost output instruction structure.
	@return	1 on success, 0 on error.
*/
static int
add_dash_pattern DK_P1(dkfig_mp_output_instruction *,oi)
{
  int back = 1;
  double x;
  int i;
  if(((oi->o)->fpd).sv > DKFIG_EPSILON) {
    x = 0.9 * ((oi->o)->fpd).sv;
  } else {
    x = 0.9;
  }
  kw_to_stream(oi->s, 0);
  kw_to_stream(oi->s, 90);
  kw_to_stream(oi->s, 1);
  kw_to_stream(oi->s, 91);
  kw_to_stream(oi->s, 2);
  switch(((oi->o)->fpd).ls) {
    case 1: case 3: case 4: case 5: {	/* dashed or dash-x-dotted */
      kw_to_stream(oi->s, 92);
      kw_to_stream(oi->s, 1);
      stream_puts_double(oi->s, (0.5*x), 1, oi->c);
      kw_to_stream(oi->s, 73);
      kw_to_stream(oi->s, 1);
      kw_to_stream(oi->s, 93);
      kw_to_stream(oi->s, 1);
      stream_puts_double(oi->s, x, 1, oi->c);
      kw_to_stream(oi->s, 73);
      kw_to_stream(oi->s, 1);
      if(((oi->o)->fpd).ls > 1) {
        i = ((oi->o)->fpd).ls - 2;
	while(i-- > 0) {
          kw_to_stream(oi->s, 92);
          kw_to_stream(oi->s, 1);
	  if(((oi->c)->opt1) & DKFIG_OPT_DP_DOT_LW) {
	    dkstream_puts_double(oi->s, (oi->m)->linewidth);
	  } else {
            dkstream_puts_long(oi->s, 0L);
	  }
          kw_to_stream(oi->s, 73);
          kw_to_stream(oi->s, 1);
          kw_to_stream(oi->s, 93);
          kw_to_stream(oi->s, 1);
          stream_puts_double(oi->s, x, 1, oi->c);
          kw_to_stream(oi->s, 73);
          kw_to_stream(oi->s, 0);
	}
      }
      kw_to_stream(oi->s, 92);
      kw_to_stream(oi->s, 1);
      stream_puts_double(oi->s, (0.5*x), 1, oi->c);
      kw_to_stream(oi->s, 73);
    } break;
    case 2: {	/* dotted */
      kw_to_stream(oi->s, 92);
      kw_to_stream(oi->s, 1);
      if(((oi->c)->opt1) & DKFIG_OPT_DP_DOT_LW) {
        dkstream_puts_double(oi->s, (oi->m)->linewidth);
      } else {
        dkstream_puts_long(oi->s, 0L);
      }
      kw_to_stream(oi->s, 73);
      kw_to_stream(oi->s, 1);
      kw_to_stream(oi->s, 93);
      kw_to_stream(oi->s, 1);
      stream_puts_double(oi->s, x, 1, oi->c);
      kw_to_stream(oi->s, 73);
    } break;
  }
  kw_to_stream(oi->s, 3);
  return back;
}



/**	Print one non-text object.
	@param	oi	MetaPost output instruction structure.
	@return	1 on success, 0 on error.
*/
static int
print_path_object DK_P1(dkfig_mp_output_instruction *,oi)
{
  int back = 0;
  int have_color_c = 0;
  dk_fig_dcc dcc;
  int must_draw = 1;
  
  oi->me = 0;
  /* path p */
  kw_to_stream(oi->s, 25);
  kw_to_stream(oi->s, 1);
  kw_to_stream(oi->s, 27);
  kw_to_stream(oi->s, 4);
  kw_to_stream(oi->s, 0);
  /* p = */
  kw_to_stream(oi->s, 27);
  kw_to_stream(oi->s, 1);
  kw_to_stream(oi->s, 12);
  kw_to_stream(oi->s, 1);
  /* create path variable contents */
  switch((oi->o)->objtype) {
    case DK_FIG_OBJ_ELLIPSE: {
      back = path_ellipse(oi);
    } break;
    case DK_FIG_OBJ_POLYLINE: {
      back = path_polyline(oi);
    } break;
    case DK_FIG_OBJ_SPLINE: {
      back = path_spline(oi);
    } break;
    case DK_FIG_OBJ_ARC: {
      back = path_arc(oi);
    } break;
  }
  kw_to_stream(oi->s, 4);
  kw_to_stream(oi->s, 0);
  if(((oi->o)->fpd).cl) {
    /* fill */
    if(dkfig_tool_must_fill(((oi->o)->fpd).af, (oi->c)->opt1)
       || dkfig_tool_must_pattern(((oi->o)->fpd).af, (oi->c)->opt1))
    {
      must_draw = 1;
      if((oi->o)->objtype == DK_FIG_OBJ_POLYLINE) {
        if((oi->o)->subtype == 5) {
	  if(!(((oi->c)->opt1) & DKFIG_OPT_FILL_BITMAP_AREA)) {
	    must_draw = 0;
	  }
        }
      }
      if(must_draw) {
        if(((oi->o)->fpd).fc != (oi->d)->transparent) {
          dkfig_tool_fill_dcc(oi->d, &dcc, ((oi->o)->fpd).fc);
          dkfig_tool_correct_dcc(&dcc, ((oi->o)->fpd).fc, ((oi->o)->fpd).af);
          kw_to_stream(oi->s, 67);
          kw_to_stream(oi->s, 1);
          kw_to_stream(oi->s, 27);
          kw_to_stream(oi->s, 1);
	  if(can_use_color(oi->c)) {
            kw_to_stream(oi->s, 43);
            kw_to_stream(oi->s, 1);
            write_dcc_data(oi->s, &dcc, oi->c);
	  } else {
	    kw_to_stream(oi->s, 106); kw_to_stream(oi->s, 1);
	    write_dcc_gray(oi->s, &dcc, oi->c);
	  }
          kw_to_stream(oi->s, 4);
          kw_to_stream(oi->s, 0);
        }
        /* add pattern */
        if(dkfig_tool_must_pattern(((oi->o)->fpd).af, (oi->c)->opt1)) {
          if(((oi->o)->fpd).pc != (oi->d)->transparent) {
            /* set_line_width(oi, ((((oi->o)->fpd).lt) ? ((oi->o)->fpd).lt : 1L)); */
            cc_bb(oi->c, &(oi->obb), &((oi->o)->dbb));
            oi->patrp  = cc_noenl_linewidth(
  	      oi->c, (((oi->c)->patrp) ? ((oi->c)->patrp) : 4L)
  	    );
  	    set_line_width(oi, 1L);
  	    kw_to_stream(oi->s, 97);
  	    kw_to_stream(oi->s, 1);
  	    kw_to_stream(oi->s, 96);
  	    kw_to_stream(oi->s, 4);
  	    kw_to_stream(oi->s, 0);
  	    kw_to_stream(oi->s, 96);
  	    kw_to_stream(oi->s, 1);
  	    kw_to_stream(oi->s, 12);
  	    kw_to_stream(oi->s, 1);
  	    kw_to_stream(oi->s, 72);
  	    kw_to_stream(oi->s, 1);
  	    kw_to_stream(oi->s, 49);
  	    kw_to_stream(oi->s, 1);
            if(((oi->c)->opt1) & DKFIG_OPT_ENLIGHTEN_LOOK) {
  	      stream_puts_double(oi->s, 0.45, 1, oi->c);
            } else {
              stream_puts_double(oi->s, 0.9, 1, oi->c);
  	    }
  	    kw_to_stream(oi->s, 73);
  	    kw_to_stream(oi->s, 4);
  	    kw_to_stream(oi->s, 0);
            set_line_cap(oi, 0);
  	    set_line_join(oi, 0);
            dkfig_tool_fill_dcc(oi->d, &dcc, ((oi->o)->fpd).pc);
            write_color_c(oi, &dcc);
            have_color_c = 1;
  	    kw_to_stream(oi->s, 26);
  	    kw_to_stream(oi->s, 1);
  	    kw_to_stream(oi->s, 28);
  	    kw_to_stream(oi->s, 4);
  	    kw_to_stream(oi->s, 0);
            kw_to_stream(oi->s, 28);
            kw_to_stream(oi->s, 75);
            kw_to_stream(oi->s, 84);
            kw_to_stream(oi->s, 4);
            kw_to_stream(oi->s, 0);
  	    switch(((oi->o)->fpd).af) {
  	      case 41: { if(!diagonal_left_30(oi, &dcc)) back = 0; } break;
  	      case 42: { if(!diagonal_right_30(oi, &dcc)) back = 0; } break;
  	      case 43: { if(!crosshatch_30(oi, &dcc)) back = 0; } break;
  	      case 44: { if(!diagonal_left_45(oi, &dcc)) back = 0;} break;
  	      case 45: { if(!diagonal_right_45(oi, &dcc)) back = 0; } break;
  	      case 46: { if(!crosshatch_45(oi, &dcc)) back = 0; } break;
  	      case 47: { if(!horizontal_bricks(oi, &dcc)) back = 0; } break;
  	      case 48: { if(!vertical_bricks(oi, &dcc)) back = 0; } break;
  	      case 49: { if(!horizontal_lines(oi, &dcc)) back = 0; } break;
  	      case 50: { if(!vertical_lines(oi, &dcc)) back = 0; } break;
  	      case 51: { if(!crosshatch(oi, &dcc)) back = 0; } break;
  	      case 52: { if(!horiz_shingles_right(oi, &dcc)) back = 0; } break;
  	      case 53: { if(!horiz_shingles_left(oi, &dcc)) back = 0; } break;
  	      case 54: { if(!vert_shingles_one(oi, &dcc)) back = 0; } break;
  	      case 55: { if(!vert_shingles_two(oi, &dcc)) back = 0; } break;
  	      case 56: { if(!large_fish_scales(oi, &dcc)) back = 0; } break;
  	      case 57: { if(!small_fish_scales(oi, &dcc)) back = 0; } break;
  	      case 58: { if(!circles(oi, &dcc)) back = 0; } break;
  	      case 59: { if(!hexagons(oi, &dcc)) back = 0; } break;
  	      case 60: { if(!octagons(oi, &dcc)) back = 0; } break;
  	      case 61: { if(!horiz_tires(oi, &dcc)) back = 0; } break;
  	      case 62: { if(!vert_tires(oi, &dcc)) back = 0; } break;
  	    }
  	    /* wieder einfuegen, nur zu Testzwecken draussen */
            kw_to_stream(oi->s, 85);
            kw_to_stream(oi->s, 1);
            kw_to_stream(oi->s, 28);
            kw_to_stream(oi->s, 1);
            kw_to_stream(oi->s, 86);
            kw_to_stream(oi->s, 1);
            kw_to_stream(oi->s, 27);
            kw_to_stream(oi->s, 4);
            kw_to_stream(oi->s, 0);
  	    /* bis hierher zu Testzwecken geloescht */
            kw_to_stream(oi->s, 87);
            kw_to_stream(oi->s, 1);
            kw_to_stream(oi->s, 88);
            kw_to_stream(oi->s, 1);
            kw_to_stream(oi->s, 89);
            kw_to_stream(oi->s, 1);
            kw_to_stream(oi->s, 28);
            kw_to_stream(oi->s, 4);
            kw_to_stream(oi->s, 0);
          }
        }
      }
    }
  }
  /* add stroke */
  must_draw = 1;
  if((oi->o)->objtype == DK_FIG_OBJ_POLYLINE) {
    if((oi->o)->subtype == 5) {
      if(((oi->c)->opt1) & DKFIG_OPT_REMOVE_BITMAP_BORDER) {
        must_draw = 0;
      }
    }
  }
  if(((oi->c)->opt1) & DKFIG_OPT_REMOVE_THIN_BORDERS) {
    if(((oi->o)->fpd).lt == 0L) {
      if(((oi->o)->fpd).cl) {
        if(dkfig_tool_must_fill(((oi->o)->fpd).af, (oi->c)->opt1)) {
	  must_draw = 0;
	}
	if(dkfig_tool_must_pattern(((oi->o)->fpd).af, (oi->c)->opt1)) {
	  must_draw = 0;
	}
	if((oi->o)->objtype == DK_FIG_OBJ_POLYLINE) {
	  if((oi->o)->subtype == 5) {
	    must_draw = 0;
	  }
	}
      }
    }
  }
  if(((oi->o)->fpd).pc == (oi->d)->transparent) {
    must_draw = 0;
  }
  if(must_draw) {
    dkfig_tool_fill_dcc(oi->d, &dcc, ((oi->o)->fpd).pc);
    if(!(((oi->o)->fpd).cl)) {
      if((((oi->o)->fpd).ar) & 3) {
        if(!have_color_c) {
	  write_color_c(oi, &dcc);
	  have_color_c = 1;
	}
      }
    }
    set_line_cap(oi, ((oi->o)->fpd).cs);
    set_line_join(oi, ((oi->o)->fpd).js);
    set_line_width(oi, ((oi->o)->fpd).lt);
    kw_to_stream(oi->s, 70);
    kw_to_stream(oi->s, 1);
    kw_to_stream(oi->s, 27);
    kw_to_stream(oi->s, 1);
    if(can_use_color(oi->c)) {
      kw_to_stream(oi->s, 43);
      kw_to_stream(oi->s, 1);
      if(have_color_c) {
        kw_to_stream(oi->s, 69);
      } else {
        write_dcc_data(oi->s, &dcc, oi->c);
      }
    } else {
      kw_to_stream(oi->s, 106); kw_to_stream(oi->s, 1);
      write_dcc_gray(oi->s, &dcc, oi->c);
    }
    if(((oi->o)->fpd).ls > 0) {
      add_dash_pattern(oi);
    }
    kw_to_stream(oi->s, 4);
    kw_to_stream(oi->s, 0);
    /* add arrowheads */
    if((((oi->o)->fpd).ar) & 1) {
      oi->a = &(((oi->o)->fpd).ahf);
      arrowhead_path(oi, 0);
      arrowhead_fd(oi, &dcc, have_color_c);
    }
    if((((oi->o)->fpd).ar) & 2) {
      oi->a = &(((oi->o)->fpd).ahb);
      arrowhead_path(oi, 1);
      arrowhead_fd(oi, &dcc, have_color_c);
    }
  }
  if(oi->me) {
    /* WARNING: math problem in object */
    dkfig_tool2_msg1(oi->c, DK_LOG_LEVEL_ERROR, 13);
    back = 0;
  }
  
  return back;
}



/**	Draw one object. Use the functions above to do the real work.
	@param	oi	MetaPost output instruction structure.
	@return	1 on success, 0 on error.
*/
static int
print_object DK_P1(dkfig_mp_output_instruction *,oi)
{
  int back = 0;
  int must_draw = 1;
  int wbgr = 0;
  
  if(((oi->c)->opt1) & DKFIG_OPT_VERBOSE_OUTPUT) {
    kw_to_stream(oi->s, 19); kw_to_stream(oi->s, 1);
    dkstream_puts_ul(oi->s, (oi->o)->lineno);
    kw_to_stream(oi->s, 0);
  }
  
  switch((oi->o)->objtype) {
    case DK_FIG_OBJ_TEXT: {
      back = print_text_object(oi);
    } break;
    case DK_FIG_OBJ_ELLIPSE:
    case DK_FIG_OBJ_POLYLINE:
    case DK_FIG_OBJ_SPLINE:
    case DK_FIG_OBJ_ARC: {
      if(((oi->c)->opt1) & DKFIG_OPT_REMOVE_BG_RECTANGLE) {
        
        if(((oi->c)->opt2) & DKFIG_OPT_WHITE_BGRECT) {
          wbgr = 1; 
        }
        if(dkfig_tool2_obj_is_bg_rect(oi->o, wbgr)) {
          must_draw = 0;
          
        }
      }
      if(must_draw) {
        back = print_path_object(oi);
      } else {
        if(((oi->c)->opt1) & DKFIG_OPT_VERBOSE_OUTPUT) {
          kw_to_stream(oi->s, 104); kw_to_stream(oi->s, 0);
	}
        back = 1;
      }
    } break;
    default: {		
    } break;
  }
  
  return back;
}



/**	Write the MetaPost preamble (which includes the LaTeX preamble).
	@param	oi	MetaPost output instruction structure.
	@return	1 on success, 0 on error.
*/
static int
do_preamble DK_P1(dkfig_mp_output_instruction *,oi)
{
  int back = 1;
  int need_latex = 0;
  
  need_latex = dkfig_dt_need_tex_file(oi->c);
  kw_to_stream(oi->s, 19);
  kw_to_stream(oi->s,  1);
  kw_to_stream(oi->s, 99);
  kw_to_stream(oi->s,  0);
  if(!(((oi->c)->opt2) & DKFIG_OPT_SKIP_ALL_TEXTS)) {
    kw_to_stream(oi->s, 13);
    kw_to_stream(oi->s, 14);
    kw_to_stream(oi->s, 12);
    kw_to_stream(oi->s, ((((oi->c)->opt1) & DKFIG_OPT_NO_EMBEDDED_FONTS) ? 10 : 11));
    kw_to_stream(oi->s,  4);
    kw_to_stream(oi->s,  0);
  }
  kw_to_stream(oi->s, 100); kw_to_stream(oi->s, 0);
  if(need_latex && (!(((oi->c)->opt2) & DKFIG_OPT_SKIP_ALL_TEXTS))) {
    kw_to_stream(oi->s, 15); kw_to_stream(oi->s, 0);
    if(((oi->c)->opt1) & DKFIG_OPT_WR_TEX_COMMAND) {
      kw_to_stream(oi->s, ((((oi->c)->opt1) & DKFIG_OPT_OLD_TEX) ? 17 : 16));
      kw_to_stream(oi->s, 0);
    }
    /* LaTeX preamble */
    if(!dkfig_dt_tex_preamble(oi->c, oi->s)) {
      back = 0;
    }
    /* begin document */
    dkfig_dt_begin_document(oi->c, oi->s);
    /* font setup */
    if(!dkfig_dt_font_defs(oi->c, oi->s)) {
      back = 0;
    }
    kw_to_stream(oi->s, 18); kw_to_stream(oi->s, 0);
  }
  
  return back;
}



/**	End mp output by writing the "end" line.
	@param	os	Output stream.
*/
static void
end_file DK_P1(dk_stream_t *,os)
{
  kw_to_stream(os, 24); kw_to_stream(os, 0);
}



/**	End the current image.
	@param	os	Output stream.
*/
static
void
end_image DK_P1(dk_stream_t *,os)
{
  kw_to_stream(os, 23); kw_to_stream(os, 0);
}



/**	Set all settings empty at beginning of an image.
	@param	mpo	MetaPost output structure.
*/
static void
do_not_have_anything DK_P1(dk_fig_output_mp *,mpo)
{
  mpo->haveflags = 0 ;
  mpo->linewidth = 0L;
  mpo->linecap   = 0 ;
  mpo->linejoin  = 0 ;
}



/**	Begin a new image.
	Write the beginfig line and increase the image number.
	@param	c	Conversion job structure.
	@param	os	Output stream.
	@param	mpo	MetaPost output structure.
*/
static
void
begin_image DK_P3(dk_fig_conversion *,c,dk_stream_t *,os,dk_fig_output_mp *,mpo)
{
  kw_to_stream(os, 22);
  kw_to_stream(os,  2);
  dkstream_puts_ul(os, mpo->currentimage);
  kw_to_stream(os,  3);
  kw_to_stream(os,  0);
  mpo->currentimage += 1UL;
  do_not_have_anything(mpo);
  if((c->opt2) & DKFIG_OPT_FILL_BOUNDING_BOX) {
    if((c->opt1) & DKFIG_OPT_VERBOSE_OUTPUT) {
      kw_to_stream(os, 103); kw_to_stream(os, 0);
    }
    kw_to_stream(os, 67);
    kw_to_stream(os, 1);
    kw_to_stream(os, 2);
    kw_to_stream(os, 10);
    kw_to_stream(os, 5);
    kw_to_stream(os, 10);
    kw_to_stream(os, 3);
    kw_to_stream(os, 6);
    kw_to_stream(os, 2);
    dkstream_puts_double(os, mpo->bbx);
    kw_to_stream(os, 5);
    kw_to_stream(os, 10);
    kw_to_stream(os, 3);
    kw_to_stream(os, 6);
    kw_to_stream(os, 2);
    dkstream_puts_double(os, mpo->bbx);
    kw_to_stream(os, 5);
    dkstream_puts_double(os, mpo->bby);
    kw_to_stream(os, 3);
    kw_to_stream(os, 6);
    kw_to_stream(os, 2);
    kw_to_stream(os, 10);
    kw_to_stream(os, 5);
    dkstream_puts_double(os, mpo->bby);
    kw_to_stream(os, 3);
    kw_to_stream(os, 6);
    kw_to_stream(os, 59);
    kw_to_stream(os, 1);
    if(can_use_color(c)) {
      kw_to_stream(os, 43);
      kw_to_stream(os, 2);
      kw_to_stream(os, 11);
      kw_to_stream(os, 5);
      kw_to_stream(os, 11);
      kw_to_stream(os, 5);
      kw_to_stream(os, 11);
      kw_to_stream(os, 3);
    } else {
      kw_to_stream(os, 106); kw_to_stream(os, 1);
      kw_to_stream(os, 11);
    }
    kw_to_stream(os, 4);
    kw_to_stream(os, 0);
  }
}



/**	For the mmp driver: End the current image and start a new one.
	@param	c	Conversion job structure.
	@param	os	Output stream.
	@param	mpo	MetaPost output structure.
*/
static
void
next_image DK_P3(dk_fig_conversion *,c,dk_stream_t *,os, dk_fig_output_mp *,mpo)
{
  end_image(os);
  begin_image(c, os, mpo);
}



/**	Handle special comments for an object.
	@param	oi	MetaPost output instruction structure.
	@param	o	Fig object structure.
*/
static void
handle_special_comments DK_P2(dkfig_mp_output_instruction *,oi, dk_fig_object *,o)
{
    int i;
    if((o->osc) && (o->osci)) {
      dk_fig_opt *speccom;
      
      dksto_it_reset(o->osci);
      while((speccom = (dk_fig_opt *)dksto_it_next(o->osci)) != NULL) {
        
        i = dkfig_opt_process_special_comment(
	  oi->c, speccom->name, keywords[102], 0
	);
	dkfig_tool2_report_special_comment(oi->c, speccom, i);
      }
    }
}



/**	Output pass.
	@param	c	Conversion job structure.
	@return	1 on success, 0 on error.
*/
static
int
output_pass DK_P1(dk_fig_conversion *,c)
{
  int back = 0;
  int must_restart;
  dkfig_mp_output_instruction oi;
  dk_fig_object      *o;
  int error_type;		/* 0=internal, 1=handled */
  unsigned long backupopt1;
  unsigned long backupopt2;
  int backupia;
  
  oi.c = c; error_type = 0;
  o = (dk_fig_object *)(c->drwng);
  if(c->app) { dkapp_set_source_lineno(c->app, 0UL); }
  if(o) {
    oi.d = (dk_fig_drawing *)(o->data);
    if(oi.d) {
      oi.m = (dk_fig_output_mp *)(c->outds);
      if(oi.m) {
        oi.o = NULL;
	oi.s = c->ostrm;
	if(oi.s) {
          dkstream_set_double_no_exponent(oi.s, 1);
	  error_type = back = 1;
	  if(!do_preamble(&oi)) {
	    back = 0; /* message handled in do_pramble() */
	  }
	  if(c->app) { dkapp_set_source_lineno(c->app, 0UL); }
          (oi.m)->currentdepth = 0L; (oi.m)->havecd = 0;
          begin_image(c, oi.s, oi.m);
          dksto_it_reset((oi.m)->it);
          while((o = (dk_fig_object *)dksto_it_next((oi.m)->it)) != NULL) {
	    backupopt1 = c->opt1;
	    backupopt2 = c->opt2;
	    backupia = c->image_align;
            handle_special_comments(&oi,o);
	    if(c->app) { dkapp_set_source_lineno(c->app, o->lineno); }
	    oi.o = o;
	    must_restart = 0;
            if((oi.m)->multi) {
              if((oi.m)->havecd) {
                if(o->layer < ((oi.m)->currentdepth - 1L)) {
	          must_restart = 1;
	        }
              }
            }
	    if(must_restart) {
              /* DEBUG: Start of next output figure */
	      dkfig_tool2_msg1(oi.c, DK_LOG_LEVEL_DEBUG, 54);
              (oi.m)->currentdepth = o->layer;
              (oi.m)->havecd = 1;
              dksto_it_reset((oi.m)->it);
              next_image(c, oi.s, oi.m);
	    } else {
	      /*
	        save current layer only if there is no layer saved yet
	        or the current layer is smaller than the saved one
	      */
	      if((oi.m)->havecd) {
	        if(o->layer < (oi.m)->currentdepth) {
		  (oi.m)->currentdepth = o->layer;
		}
	      } else {
	        (oi.m)->currentdepth = o->layer;
	      }
	      (oi.m)->havecd = 1;
	      /*
	        print the object
	      */
	      if(!print_object(&oi)) {
	        back = 0; /* message handled in print_object */
	      }
	    }
	    c->opt1 = backupopt1;
	    c->opt2 = backupopt2;
	    c->image_align = backupia;
	  }
          end_image(oi.s);
          end_file(oi.s);
	}
      }
    }
  }
  if(!back) {
    switch(error_type) {
      case 0: {
        /* ERROR: internal setup error */
	dkfig_tool2_msg1(oi.c, DK_LOG_LEVEL_ERROR, 44);
      } break;
    }
  }
  
  return back;
}



/**	Initialize output data structure.
	@param	o	MetaPost output structure.
*/
static
void
null_outds DK_P1(dk_fig_output_mp *,o)
{
  o->multi = 0;
  o->flatlist = NULL;
  o->it = NULL;
  o->currentimage = 0UL;
  o->sf = o->mx = 3.0 / 50.0;
  o->my = 0.0 - o->mx;
  o->nx = o->ny = 0.0;
  o->ahlength = 0.0;
  o->ahangle  = 0.0;
  do_not_have_anything(o);
}



/**	Cleaning up is necessary in all cases.
	@param	c	Conversion job structure.
*/
static
void
cleanup_pass DK_P1(dk_fig_conversion *,c)
{
  dk_fig_output_mp *outds;
  
  if(c->outds) {
    outds = (dk_fig_output_mp *)(c->outds);
    if(outds->it) { dksto_it_close(outds->it); }
    if(outds->flatlist) { dksto_close(outds->flatlist); }
    null_outds(outds);
    dk_delete(outds);
    c->outds = NULL;
  }
  
}



/**	Set up co-ordinates transformation according to the bounding box.
	@param	mpo	MetaPost output structure.
	@param	o	Fig object.
	@return	1 on success, 0 on error.
*/
static int
outds_coord_transform DK_P2(dk_fig_output_mp *,mpo, dk_fig_object *,o)
{
  int back = 0, matherr = 0;
  dk_fig_drawing *d;
  double min, max, omin, omax;
  
  if(mpo && o) {
    d = (dk_fig_drawing *)(o->data);
    if(d) {
      if(d->fres > DKFIG_EPSILON) {
        if(dkfig_tool_invert_y(d)) {
          mpo->sf = dkma_div_double_ok(72.0, d->fres, &matherr);
	  mpo->mx = mpo->sf;
	  mpo->my = 0.0 - mpo->mx;
	  mpo->nx = mpo->ny = 0.0;
	  if( (d->dbb).flags & 0x01 ) {
	    omin = dkma_mul_double_ok(mpo->mx, (d->dbb).xmin, &matherr);
	    omax = dkma_mul_double_ok(mpo->mx, (d->dbb).xmax, &matherr);
	    mpo->nx = 0.0 - omin;
	    omax = dkma_sub_double_ok(omax, omin, &matherr);
	    min  = 0.0;
	    max  = ceil(omax);
	    mpo->bbx = max;	
	    mpo->nx = dkma_add_double_ok(
	      mpo->nx,
	      dkma_div_double_ok(
	        dkma_sub_double_ok(max, omax, &matherr),
	        2.0,
	        &matherr
	      ),
	      &matherr
	    );
	  }
	  if( (d->dbb).flags & 0x02 ) {
	    omin = dkma_mul_double_ok(mpo->my, (d->dbb).ymax, &matherr);
	    omax = dkma_mul_double_ok(mpo->my, (d->dbb).ymin, &matherr);
	    mpo->ny = 0.0 - omin;
	    omax = dkma_sub_double_ok(omax, omin, &matherr);
	    min = 0.0;
	    max = ceil(omax);
	    mpo->bby = max;	
	    mpo->ny = dkma_add_double_ok(
	      mpo->ny,
	      dkma_div_double_ok(
	        dkma_sub_double_ok(max, omax, &matherr),
	        2.0,
	        &matherr
	      ),
	      &matherr
	    );
	  }
	  if(!matherr) {
	    back = 1;
	  }
	} else {	
          mpo->sf = dkma_div_double_ok(72.0, d->fres, &matherr);
	  mpo->mx = mpo->sf;
	  mpo->my = mpo->mx;
	  mpo->nx = mpo->ny = 0.0;
	  if( (d->dbb).flags & 0x01 ) {
	    omin = dkma_mul_double_ok(mpo->mx, (d->dbb).xmin, &matherr);
	    omax = dkma_mul_double_ok(mpo->mx, (d->dbb).xmax, &matherr);
	    mpo->nx = 0.0 - omin;
	    omax = dkma_sub_double_ok(omax, omin, &matherr);
	    min  = 0.0;
	    max  = ceil(omax);
	    mpo->bbx = max;	
	    mpo->nx = dkma_add_double_ok(
	      mpo->nx,
	      dkma_div_double_ok(
	        dkma_sub_double_ok(max, omax, &matherr),
	        2.0,
	        &matherr
	      ),
	      &matherr
	    );
	  }
	  if( (d->dbb).flags & 0x02 ) {
	    omin = dkma_mul_double_ok(mpo->my, (d->dbb).ymin, &matherr);
	    omax = dkma_mul_double_ok(mpo->my, (d->dbb).ymax, &matherr);
	    mpo->ny = 0.0 - omin;
	    omax = dkma_sub_double_ok(omax, omin, &matherr);
	    min = 0.0;
	    max = ceil(omax);
	    mpo->bby = max;	
	    mpo->ny = dkma_add_double_ok(
	      mpo->ny,
	      dkma_div_double_ok(
	        dkma_sub_double_ok(max, omax, &matherr),
	        2.0,
	        &matherr
	      ),
	      &matherr
	    );
	  }
	  if(!matherr) {
	    back = 1;
	  }
	}
      }
    }
    
    
    
  } 
  return back;
}



/**	Prepare before writing.
	@param	c	Conversion job structure.
	@return	1 on success, 0 on error.
*/
static
int
preparation_pass DK_P1(dk_fig_conversion *,c)
{
  int back = 0;
  dk_fig_output_mp *outds;
  
  if(c->app) {
    dkapp_set_source_lineno(c->app, 0UL);
  }
  outds = (dk_fig_output_mp *)dk_new(dk_fig_output_mp,1);
  if(outds) {
    c->outds = (void *)outds;
    null_outds(outds);
    outds_coord_transform(outds, c->drwng);
    outds->flatlist = dkfig_flat_list(c, c->drwng);
    if(outds->flatlist) {
      outds->it = dksto_it_open(outds->flatlist);
      if(outds->it) {
        back = 1;
      } else {
        if(c->app) {
          dkapp_err_memory(c->app, sizeof(dk_storage_iterator_t), 1);
	}
      }
    }
  } else {
    if(c->app) {
      dkapp_err_memory(c->app, sizeof(dk_fig_output_mp), 1);
    }
  }
  dkfig_tool2_report_unused_options(c);
  
  return back;
}



/**	MMP (Multi-MetaPost) output driver function.
	@param	c	Conversion job structure.
	@return	1 on success, 0 on error.
*/
int
dkfig_output_mmp DK_P1(dk_fig_conversion *,c)
{
  int back = 0;
  
  if(c) {
    /* PROGRESS: Gathering font information */
    dkfig_tool2_msg1(c, DK_LOG_LEVEL_PROGRESS, 55);
    if(preparation_pass(c)) {
      ((dk_fig_output_mp *)(c->outds))->multi = 1;	/* enable mmp */
      /* PROGRESS: Starting output */
      dkfig_tool2_msg1(c, DK_LOG_LEVEL_PROGRESS, 56);
      back = output_pass(c);
      /* PROGRESS: Output finished */
      dkfig_tool2_msg1(c, DK_LOG_LEVEL_PROGRESS, 57);
    }
    cleanup_pass(c);
  }
  
  return back;
}



/**	MetaPost output driver function.
	@param	c	Conversion job structure.
	@return	1 on success, 0 on error.
*/
int
dkfig_output_mp DK_P1(dk_fig_conversion *,c)
{
  int back = 0;
  
  if(c) {
    /* PROGRESS: Gathering font information */
    dkfig_tool2_msg1(c, DK_LOG_LEVEL_PROGRESS, 55);
    if(preparation_pass(c)) {
      ((dk_fig_output_mp *)(c->outds))->multi = 0;	/* disable mmp */
      /* PROGRESS: Starting output */
      dkfig_tool2_msg1(c, DK_LOG_LEVEL_PROGRESS, 56);
      back = output_pass(c);
      /* PROGRESS: Output finished */
      dkfig_tool2_msg1(c, DK_LOG_LEVEL_PROGRESS, 57);
    }
    cleanup_pass(c);
  }
  
  return back;
}


