/*
Copyright (c) 2004-2005, 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
  its 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.
*/

#define DKFIGMP_C 1
#include "dkfig.h"




#line 43 "dkfigmp.ctr"




#define drd(v,o,w) dkfig_tool2_drd(v,o,w)



#line 51 "dkfigmp.ctr"



/* {{{ treace_bezier_point

  Issue debugging output about a Bezier point.

*/
#if TRACE_DEBUG
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
#define TR_PTR(x) ((x) ? "PTR" : "(NULL)")
#endif


#define HAVE_LINEWIDTH		 1
#define HAVE_LINECAP		 2
#define HAVE_LINEJOIN		 4
#define HAVE_AHLENGTH		 8
#define HAVE_AHANGLE		16

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://fig2vect.sourceforge.net",
 /* 100 */ "labeloffset:=0;bbmargin:=0;",
 /* 101 */ ".0",
 /* 102 */ "mp",

  NULL
};

static size_t number_of_keywords = sizeof(keywords)/sizeof(PCHAR);
/* }}} */



/* {{{ kw_to_stream

  Write one keyword to output stream.

*/
static void
kw_to_stream DK_P2(dk_stream_t *,strm, size_t,index)
{
  if(index < number_of_keywords) {
    dkstream_puts(strm, keywords[index]);
  }
}
/* }}} */



/* {{{ stream_puts_double

  Write double value to stream, convert for
  MetaPost representation if neccesary.
  (i.e. 3.5e8 -> (3.5*(10**8)) )

*/
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);
      }
    }
  }
}
/* }}} */



/* {{{ ccd_x

  Convert co-ordinate x from fig to MP.

*/
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;
}
/* }}} */



/* {{{ ccd_y

  Convert co-ordinate y from fig to MP.

*/
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;
}
/* }}} */



/* {{{ cc_x

  Convert co-ordinate x from fig to MP.

*/
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;
}
/* }}} */



/* {{{ cc_radius

  Convert a distance from Fig to MetaPost.

*/
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;
}
/* }}} */



/* {{{ ccd_radius

  Convert a distance from Fig to MetaPost.

*/
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;
}
/* }}} */



/* {{{ cc_y

  Convert co-ordinate y from fig to MP.

*/
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;
}
/* }}} */



/* {{{ cc_bb

  Convert a bounding box from Fig to MetaPost.

*/
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));
  
}
/* }}} */



/* {{{ cc_noenl_linewidth

  Convert line width from Fig to MetaPost, ignore
  "lighten look" option.

*/
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_noconv_double_point

  Write point given in MetaPost co-ordinates.

*/
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_long_point

  Write point data given in Fig co-ordinates.

*/
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_double_point

  Write point data given in Fig co-ordinates.

*/
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);
  
}
/* }}} */



/* {{{ write_dcc_data

  Write color cell RGB-triple.

*/
static void
write_dcc_data DK_P3(dk_stream_t *,os, dk_fig_dcc *,dcc, dk_fig_conversion *,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);
}
/* }}} */



/* {{{ encode_text_to_mp

  Output UTF-8 encoded text encoded for mp.

*/
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++;
  }
  */
}
/* }}} */



/* {{{ encode_text_to_mp

  Output text encoded for mp.

*/
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++;
  }
}
/* }}} */



/* {{{ print_text_object

  Write text object.

*/
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) {
    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);
      kw_to_stream(oi->s, 43);
      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);
    }
  }
  
  return back;
}
/* }}} */



/* {{{ is_ellipse

  Check whether we have an ellipse (return 1)
  or a circle (return 0).

*/
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;
}
/* }}} */



/* {{{ path_ellipse

  Write path for an ellipse.

*/
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;
}
/* }}} */



/* {{{ path_polyline

  Write path for a polyline.

*/
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;
}
/* }}} */



/* {{{ path_spline

  Write path for a spline.

*/
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 1156 "dkfigmp.ctr"
      
      
#line 1158 "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 1187 "dkfigmp.ctr"
	
	
#line 1189 "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 1209 "dkfigmp.ctr"
      
      
#line 1211 "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;
}
/* }}} */



/* {{{ path_arc

  Write path for an arc.

*/
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_color_c

  Write a color cell.

*/
static void
write_color_c DK_P2(\
  dkfig_mp_output_instruction *,oi, dk_fig_dcc *,dcc\
)
{
      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_line_join

  Set new line join (only if it differs from the
  current 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_ahlength

  Set new arrowhead length (only if it differs from
  the current 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_ahangle

  Set a new arrowhead angle (only if it differs from the
  current arrowhead angle).

*/
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_line_cap

  Set a new line cap (only if it differs from
  the current line cap).

*/
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_line_width

  Set a new line width (only if the new line width
  differs from the current 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;
  }
}
/* }}} */



/* {{{ arrowhead_path

  Write path for arrowhead.

*/
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);
  }
}
/* }}} */



/* {{{ arrowhead_fd

  Write instructions to draw arrowhead.

*/
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);
    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);
    }
    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);
  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);
  }
  kw_to_stream(oi->s, 4); kw_to_stream(oi->s, 0);
}
/* }}} */



/* {{{ start_addto
  
  Write start of addto ... instruction.

*/
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);
}
/* }}} */



/* {{{ end_addto

  Write end of addto ... instruction.

*/
static void
end_addto DK_P1(dkfig_mp_output_instruction *,oi)
{
  kw_to_stream(oi->s, 0);
  kw_to_stream(oi->s, 3);
  kw_to_stream(oi->s, 1);
  kw_to_stream(oi->s, 43);
  kw_to_stream(oi->s, 1);
  kw_to_stream(oi->s, 69);
  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);
}
/* }}} */



/* {{{ diagonal_left_30

  Fill pattern 30 degree lines to the left.

*/
static int
diagonal_left_30 DK_P1(dkfig_mp_output_instruction *,oi)
{
  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);
    y = dkma_add_double_ok(y, deltay, &me);
  }
  if(me) { oi->me = me; back = 0; }
  return back;
}
/* }}} */



/* {{{ diagonal_right_30

  Fill pattern 30 degree lines to the right.

*/
static int
diagonal_right_30 DK_P1(dkfig_mp_output_instruction *,oi)
{
  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);
    y = dkma_add_double_ok(y, deltay, &me);
  }
  if(me) { oi->me = me; back = 0; }
  return back;
}
/* }}} */



/* {{{ crosshatch_30

  Fill pattern 30 degree crosshatch.

*/
static int
crosshatch_30 DK_P1(dkfig_mp_output_instruction *,oi)
{
  int back = 1;
  if(!diagonal_left_30(oi)) { back = 0; }
  if(!diagonal_right_30(oi)) { back = 0; }
  return back;
}
/* }}} */



/* {{{ diagonal_left_45

  Fill pattern 45 degree lines to the left.

*/
static int
diagonal_left_45 DK_P1(dkfig_mp_output_instruction *,oi)
{
  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);
    y = dkma_add_double_ok(y, deltay, &me);
  }
  if(me) { oi->me = me; back = 0; }
  return back;
}
/* }}} */



/* {{{ diagonal_right_45

  Fill pattern 45 degree lines to the right.

*/
static int
diagonal_right_45 DK_P1(dkfig_mp_output_instruction *,oi)
{
  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);
    y = dkma_add_double_ok(y, deltay, &me);
  }
  if(me) { oi->me = me; back = 0; }
  return back;
}
/* }}} */



/* {{{ crosshatch_45

  Fill pattern 45 degree crosshatch.

*/
static int
crosshatch_45 DK_P1(dkfig_mp_output_instruction *,oi)
{
  int back = 1;
  if(!diagonal_left_45(oi)) { back = 0; }
  if(!diagonal_right_45(oi)) { back = 0; }
  return back;
}
/* }}} */



/* {{{ horizontal_bricks

  Fill pattern horizontal bricks.

*/
static int
horizontal_bricks DK_P1(dkfig_mp_output_instruction *,oi)
{
  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);
    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);
      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;
}
/* }}} */



/* {{{ vertical_bricks
 
  Fill pattern vertical bricks.

*/
static int
vertical_bricks DK_P1(dkfig_mp_output_instruction *,oi)
{
  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);
    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);
      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;
}
/* }}} */



/* {{{ horizontal_lines

  Fill pattern horizontal lines.

*/
static int
horizontal_lines DK_P1(dkfig_mp_output_instruction *,oi)
{
  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);
    y = dkma_add_double_ok(y, deltay, &me);
  }
  if(me) { oi->me = me; back = 0; }
  return back;
}
/* }}} */



/* {{{ vertical_lines

  Fill pattern vertical lines.

*/
static int
vertical_lines DK_P1(dkfig_mp_output_instruction *,oi)
{
  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);
    x = dkma_add_double_ok(x, deltax, &me);
  }
  if(me) { oi->me = me; back = 0; }
  return back;
}
/* }}} */



/* {{{ crosshatch

  Fill pattern crosshatch.

*/
static int
crosshatch DK_P1(dkfig_mp_output_instruction *,oi)
{
  int back = 1;
  if(!horizontal_lines(oi)) { back = 0; }
  if(!vertical_lines(oi)) { back = 0; }
  return back;
}
/* }}} */



/* {{{ horiz_shingles_right

  Fill pattern horizontal shingles skewed to
  the right.

*/
static int
horiz_shingles_right DK_P1(dkfig_mp_output_instruction *,oi)
{
  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);
    /*
    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);
      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;
}
/* }}} */



/* {{{ horiz_shingles_left

  Fill pattern horizontal shingles skewed to
  the left.

*/
static int
horiz_shingles_left DK_P1(dkfig_mp_output_instruction *,oi)
{
  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);
    /*
    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);
      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;
}
/* }}} */



/* {{{ vert_shingles_one

  Fill pattern vertical shingles 1.

*/
static int
vert_shingles_one DK_P1(dkfig_mp_output_instruction *,oi)
{
  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);
    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);
      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;
}
/* }}} */



/* {{{ vert_shingles_two

  Fill pattern vertical shingles 2.

*/
static int
vert_shingles_two DK_P1(dkfig_mp_output_instruction *,oi)
{
  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);
    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);
      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;
}
/* }}} */



/* {{{ do_fish_scales

  Create fish scale fill patterns.

*/
static int
do_fish_scales DK_P3(\
  dkfig_mp_output_instruction *,oi,\
  double,ar, double,phi\
)
{
  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);
      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;
}
/* }}} */



/* {{{ large_fish_scales

  Fill pattern large fish scales.

*/
static int
large_fish_scales DK_P1(dkfig_mp_output_instruction *,oi)
{
  int back = 1;
  back = do_fish_scales(oi, 1.25, 1.881618);
  return back;
}
/* }}} */



/* {{{ small_fish_scales

  Fill pattern small fish scales.

*/
static int
small_fish_scales DK_P1(dkfig_mp_output_instruction *,oi)
{
  int back = 1;
  back = do_fish_scales(oi, 0.5, M_PI);
  return back;
}
/* }}} */



/* {{{ circles

  Fill pattern circles.

*/
static int
circles DK_P1(dkfig_mp_output_instruction *,oi)
{
  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);
      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.

*/
static int
hexagons DK_P1(dkfig_mp_output_instruction *,oi)
{
  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);
      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);
      y  = y2;
    }
    x = dkma_add_double_ok(x, deltax, &me);
  }
  if(me) { oi->me = me; back = 0; }
  return back;
}
/* }}} */



/* {{{ octagons
  
  Fill pattern octagons.

*/
static int
octagons DK_P1(dkfig_mp_output_instruction *,oi)
{
  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);
      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;
}
/* }}} */



/* {{{ horiz_tires

  Fill pattern horizontal tires

*/
static int
horiz_tires DK_P1(dkfig_mp_output_instruction *,oi)
{
  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);
    y = dkma_add_double_ok(y, deltay, &me);
  }
  if(me) { oi->me = me; back = 0; }
  return back;
}
/* }}} */



/* {{{ vert_tires

  Fill pattern vertical tires.

*/
static int
vert_tires DK_P1(dkfig_mp_output_instruction *,oi)
{
  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);
    x = dkma_add_double_ok(x, deltax, &me);
  }
  return back;
}
/* }}} */



/* {{{ add_dash_pattern

  Write dash pattern for dashed lines.

*/
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_path_object

  Print one non-text object.
*/
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);
          kw_to_stream(oi->s, 43);
          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);
        }
        /* 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)) back = 0; } break;
  	      case 42: { if(!diagonal_right_30(oi)) back = 0; } break;
  	      case 43: { if(!crosshatch_30(oi)) back = 0; } break;
  	      case 44: { if(!diagonal_left_45(oi)) back = 0;} break;
  	      case 45: { if(!diagonal_right_45(oi)) back = 0; } break;
  	      case 46: { if(!crosshatch_45(oi)) back = 0; } break;
  	      case 47: { if(!horizontal_bricks(oi)) back = 0; } break;
  	      case 48: { if(!vertical_bricks(oi)) back = 0; } break;
  	      case 49: { if(!horizontal_lines(oi)) back = 0; } break;
  	      case 50: { if(!vertical_lines(oi)) back = 0; } break;
  	      case 51: { if(!crosshatch(oi)) back = 0; } break;
  	      case 52: { if(!horiz_shingles_right(oi)) back = 0; } break;
  	      case 53: { if(!horiz_shingles_left(oi)) back = 0; } break;
  	      case 54: { if(!vert_shingles_one(oi)) back = 0; } break;
  	      case 55: { if(!vert_shingles_two(oi)) back = 0; } break;
  	      case 56: { if(!large_fish_scales(oi)) back = 0; } break;
  	      case 57: { if(!small_fish_scales(oi)) back = 0; } break;
  	      case 58: { if(!circles(oi)) back = 0; } break;
  	      case 59: { if(!hexagons(oi)) back = 0; } break;
  	      case 60: { if(!octagons(oi)) back = 0; } break;
  	      case 61: { if(!horiz_tires(oi)) back = 0; } break;
  	      case 62: { if(!vert_tires(oi)) 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(((oi->c)->opt1) & DKFIG_OPT_REMOVE_BG_RECTANGLE) {
    int wbgr = 0;
    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) {
    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);
    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);
    }
    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;
}
/* }}} */



/* {{{ print_object

  Draw one object. Use the functions above
  to do the real work.

*/
static int
print_object DK_P1(dkfig_mp_output_instruction *,oi)
{
  int back = 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: {
      back = print_path_object(oi);
    } break;
    default: {		
    } break;
  }
  
  return back;
}
/* }}} */



/* {{{ do_preamble

  Write the MetaPost preamble (which includes the
  LaTeX preamble).

*/
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);
  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) {
    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_file

  End mp output by writing the "end" line.

*/
static void
end_file DK_P1(dk_stream_t *,os)
{
  kw_to_stream(os, 24); kw_to_stream(os, 0);
}
/* }}} */



/* {{{ end_image

  End the current image.

*/
static
void
end_image DK_P1(dk_stream_t *,os)
{
  kw_to_stream(os, 23); kw_to_stream(os, 0);
}
/* }}} */



/* {{{ do_not_have_anything

  All settings empty at beginning of an image.

*/
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_image

  Begin a new image.
  Write the beginfig line and increase the
  image number.

*/
static
void
begin_image DK_P2(\
  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);
}
/* }}} */



/* {{{ next_image

  For the mmp driver: end the current image
  and start a new one.

*/
static
void
next_image DK_P2(\
  dk_stream_t *,os, dk_fig_output_mp *,mpo\
)
{
  end_image(os);
  begin_image(os, mpo);
}
/* }}} */



/* {{{ handle_special_comments
*/
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.

*/
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;
  
  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) {
	  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(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;
            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(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;
	  }
          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

*/
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.

*/
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;
  }
  
}
/* }}} */



/* {{{ outds_coord_transform

  Set up co-ordinates transformation according
  to the bounding box.

*/
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->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->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->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->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;
}
/* }}} */



/* {{{ preparation_pass

  Prepare before writing.

*/
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;
}
/* }}} */



/* {{{ dkfig_output_mmp

  Output multi metapost.

*/
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;
}
/* }}} */



/* {{{ dkfig_output_mp

  Write MetaPost output.

*/
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;
}
/* }}} */



/* {{{ SCCS ID */
#ifndef LINT
static char sccs_id[] = {
"@(#)dkfigmp.ctr 1.110 05/29/07\t(krause) - fig2vect"
};
#endif
/* }}} */
