/*
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	dkfigtoo.c	Tool functions module.
*/


/**	Inside the dkfigtoo module.
*/
#define DKFIGTOO_C 1



#include "dkfig.h"




#line 54 "dkfigtoo.ctr"




/**	Alphabet, used for string encoding of numbers.
*/
static char alphabet[] = { "ABCDEFGHIJKLMNOPQRSTUVWXYZ" };




#line 65 "dkfigtoo.ctr"
#if TRACE_DEBUG
/**	Write trace information for one Bezier point.
	@param	bp	The Bezier point.
*/
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



/**	Check whether or not to invert y coordinates.
	@param	d	Fig drawing structure.
	@return	Test result (1=invert, 0=do not invert).
*/
int
dkfig_tool_invert_y DK_P1(dk_fig_drawing *,d)
{
  int back = 1;
  if(d) {
    if(d->cstype == 1) {
      if((d->opt1) & DKFIG_OPT_USE_CS_SETTING) {
        back = 0;
      }
    }
  }
  return back;
}



/**	Initialize point.
	@param	p	The point to initialize.
*/
static void
null_point DK_P1(dk_fig_point *,p)
{
  p->x = p->y = 0.0;
}



/**	Initialize arrowhead structure.
	@param	a	Arrowhead structure.
*/
void
dkfig_tool_null_arrow DK_P1(dk_fig_arrow *,a)
{
  if(a) {
    a->type = 0;
    a->style = 0;
    a->thickness = 0.0;
    a->w = 0.0;
    a->h = 0.0;
    a->alpha = 0.0;
    null_point(&(a->p1)); null_point(&(a->p2));
    null_point(&(a->p3)); null_point(&(a->p4));
    a->numpoints = 0;
    a->decrease  = 0.0;
  }
}



/**	Calculate arrowhead polygon points.
	@param	a	Arrowhead structure (destination).
	@param	p	Arrowhead end point.
	@param	phi	Direction at the end of line.
	@param	f	Objects filling, pattern and drawing.
	@param	d	Fig drawing structure.
	@param	c	Conversion job structure.
	@return	1 on success, 0 on error.
*/
int
dkfig_tool_calc_arrow DK_P6(dk_fig_arrow *,a, dk_fig_point *,p, double,phi, dk_fig_fpd *,f, dk_fig_drawing *,d, dk_fig_conversion *,c)
{
  int back = 0;
  int matherr = 0;
  double lw, dist, deltal, radius, w, h, sf, pointdec;
  
  if((a) && (p) && (f) && (d)) {		
    back = 1;
    lw = dist = a->alpha = deltal = 0.0; sf = 1.0;
    a->numpoints = 3;
    /* lw = (dkma_l_to_double(f->lt) * d->fres) / 80.0; */
    lw = dkma_div_double_ok(
      dkma_mul_double_ok(dkma_l_to_double(f->lt), d->fres, &matherr),
      (((d->opt1) & DKFIG_OPT_ENLIGHTEN_LOOK) ? 160.0 : 80.0),
      &matherr
    ); 
    a->alpha = dkma_atan2((0.5 * a->w), a->h);
    
    /*
      For beveled and rounded arrowheads, the length correction
      deltal is half of the linewidth.
    */
    deltal = 0.5 * lw;	
    /*
      For mitered arrowhead we need a trigonometric
      calculation.
    */
    if(d->ahlj == 0) {
      deltal = dkma_div_double_ok(deltal, sin(a->alpha), &matherr);
      
    }
    /*
      pointdec is the "top" corner of the arrowhead,
      a->decrease is the amount to decrease the line.
    */
    pointdec = a->decrease = deltal;
    
    /*
      Find optimum decrease if no metapost arrowheads are in use
      and the arrowhead is mitered.
    */ 
    if(d->ahlj == 0) {
      if((!((d->opt1) & DKFIG_OPT_METAPOST_ARROWHEADS)) || (c->bdnum > 1)) {
        double cmin, cmax;
	cmin = dkma_div_double_ok((0.5 * lw), tan(a->alpha), &matherr);
        cmax = dkma_mul_double_ok(2.0, pointdec, &matherr);
	a->decrease = 0.5 * dkma_add_double_ok(cmin, cmax, &matherr);
	
      }
    }
    
    w = a->w;
    h = a->h;
    /* radius = sqrt(0.25*w*w+h*h); */
    radius = sqrt(
      dkma_add_double_ok(
        (0.25 * dkma_mul_double_ok(w, w, &matherr)),
	dkma_mul_double_ok(h, h, &matherr),
        &matherr
      )
    );
    /* (a->p2).x = p->x - pointdec * cos(phi); */
    (a->p2).x = dkma_sub_double_ok(p->x, (pointdec * cos(phi)), &matherr);
    /* (a->p2).y = p->y - pointdec * sin(phi); */
    if(dkfig_tool_invert_y(d)) {
      (a->p2).y = dkma_add_double_ok(p->y, (pointdec * sin(phi)), &matherr);
    } else {
      (a->p2).y = dkma_sub_double_ok(p->y, (pointdec * sin(phi)), &matherr);
    }
    /* p1->x = p2->x + radius * cos(phi + M_PI - a->alpha); */
    (a->p1).x = dkma_add_double_ok(
      (a->p2).x, (radius * cos(phi + M_PI - a->alpha)), &matherr
    );
    if(dkfig_tool_invert_y(d)) {
      (a->p1).y = dkma_sub_double_ok(
        (a->p2).y, (radius * sin(phi + M_PI - a->alpha)), &matherr
      );
    } else {
      (a->p1).y = dkma_add_double_ok(
        (a->p2).y, (radius * sin(phi + M_PI - a->alpha)), &matherr
      );
    }
    (a->p3).x = dkma_add_double_ok(
      (a->p2).x, (radius * cos(phi + M_PI + a->alpha)), &matherr
    );
    if(dkfig_tool_invert_y(d)) {
      (a->p3).y = dkma_sub_double_ok(
        (a->p2).y, (radius * sin(phi + M_PI + a->alpha)), &matherr
      );
    } else {
      (a->p3).y = dkma_add_double_ok(
        (a->p2).y, (radius * sin(phi + M_PI + a->alpha)), &matherr
      );
    }
    switch(a->type) {
      case 2: sf = 0.75; a->numpoints = 4; break;
      case 3: sf = 1.25; a->numpoints = 4; break;
    }
    (a->p4).x = dkma_sub_double_ok(
      (a->p2).x,
      (dkma_mul_double_ok(sf, h, &matherr) * cos(phi)),
      &matherr
    );
    if(dkfig_tool_invert_y(d)) {
      (a->p4).y = dkma_add_double_ok(
        (a->p2).y,
	(dkma_mul_double_ok(sf, h, &matherr) * sin(phi)),
	&matherr
      );
    } else {
      (a->p4).y = dkma_sub_double_ok(
        (a->p2).y,
        (dkma_mul_double_ok(sf, h, &matherr) * sin(phi)),
        &matherr
      );
    }
  }
  
  if(matherr) { back = 0; }
  
  return back;
}



/**	Initialize a fill, pattern and drawing structure.
	@param	p	Structure to initialize.
*/
void
dkfig_tool_null_fpd DK_P1(dk_fig_fpd *,p)
{
  p->cl = 0;	/* not closed */
  p->ot = -1;	/* unknown sub type */
  p->ls = 0;	/* line style contigous */
  p->lt = 0UL;	/* no line thickness */
  p->pc = -1;	/* unknown pen color */
  p->fc = -1;	/* unknown fill color */
  p->af = -1;	/* unknown fill style */
  p->js = 0;	/* linjoin=0 */
  p->cs = 0;	/* linecap=0 */
  p->ar = 0;	/* no arrowheads */
  p->sv = 0.0;	/* style value 0.0 */
  p->ps = 0;	/* no pen style */
  dkfig_tool_null_arrow(&(p->ahf));	/* emtpy arrowhead structures */
  dkfig_tool_null_arrow(&(p->ahb));
}



/**	Plain TeX does not provide all the font handling instructions
	we want to use with LaTeX. So we need to apply corrections.
	@param	fhptr	Font handling structure.
*/
static void
correct_fonth_for_plain_tex DK_P1(dk_fig_fonth_t *,fhptr)
{
	
	if(fhptr->handling == 4) {
	  
	  fhptr->handling = 3;
	  if((fhptr->oflags) & 4) {		
	    fhptr->fontno = fhptr->ofontno;
	    if(fhptr->fontno < 0) fhptr->fontno = 0;
	    if(fhptr->fontno > 34) fhptr->fontno = 34;
	  } else {				
	    switch(fhptr->ofontno) {
	      case 2: {				
	        fhptr->fontno = 2;
              } break;
	      case 3: {				
	        fhptr->fontno = 1;
	      } break;
	      case 4: {				
	        fhptr->fontno = 16;
	      } break;
	      case 5: {				
	        fhptr->fontno = 12;
	      } break;
	      default: {
	        fhptr->fontno = 0;		
	      } break;
	    }
	  }
	}
	if(fhptr->handling == 5) {
	  fhptr->handling = 2;
	}
	
}



/**	Correct all font handling structures for use with plain TeX.
	@param	c	Conversion job structure.
*/
void
dkfig_tool_correct_for_plain_tex DK_P1(dk_fig_conversion *,c)
{
  dk_fig_drawing *d = NULL;
  dk_fig_fonth_t *fhptr = NULL;
  dk_fig_object  *o = NULL;
  
  if(c) {					
    if((c->opt1) & DKFIG_OPT_OLD_TEX) {		
      o = c->drwng;
      if(o) {
        d = (dk_fig_drawing *)(o->data);
        if(d) {					
          if(d->fonthi) {				
	    dksto_it_reset(d->fonthi);
            while((fhptr=(dk_fig_fonth_t *)dksto_it_next(d->fonthi)) != NULL) {
	      
	      correct_fonth_for_plain_tex(fhptr);
	    }
	  } else {				
	  }
        }
      }
    } else {					
    }
  }
  
}



/**	Initialize a bounding box structure.
	@param	bb	Structure to initialize.
*/
void
dkfig_tool_bb_reset DK_P1(dk_fig_bb *,bb)
{		
  if(bb) {
    bb->xmin  = bb->xmax = bb->ymin = bb->ymax = 0.0;
    bb->flags = 0x00;
  }		
}



/**	Add x value to bounding box.
	@param	bb	Bounding box structure.
	@param	x	X value to add.
*/
void
dkfig_tool_bb_add_x DK_P2(dk_fig_bb *,bb, double,x)
{				
  if(bb) {
    if(bb->flags & 0x01) {
      if(x < bb->xmin) bb->xmin = x;
      if(x > bb->xmax) bb->xmax = x;
    } else {
      bb->xmin = bb->xmax = x;
      bb->flags |= 0x01;
    }
  }				
}



/**	Add y value to bounding box.
	@param	bb	Bounding box structure.
	@param	y	Y value to add.
*/
void
dkfig_tool_bb_add_y DK_P2(dk_fig_bb *,bb, double,y)
{		
  if(bb) {
    if(bb->flags & 0x02) {
      if(y < bb->ymin) bb->ymin = y;
      if(y > bb->ymax) bb->ymax = y;
    } else {
      bb->ymin = bb->ymax = y;
      bb->flags |= 0x02;
    }
  }		
}



/**	Get minimum x value from bounding box structure.
	@param	bb	Bounding box structure.
	@return	Minimum x value.
*/
double
dkfig_tool_bb_get_xmin DK_P1(dk_fig_bb *,bb)
{
  double back = 0.0;	
  if(bb) {
    if(bb->flags & 0x01) {
      back = bb->xmin;
    }
  }			
  return back;
}

/**	Get maximum x value from bounding box structure.
	@param	bb	Bounding box structure.
	@return	Maximum x value.
*/
double
dkfig_tool_bb_get_xmax DK_P1(dk_fig_bb *,bb)
{
  double back = 0.0;	
  if(bb) {
    if(bb->flags & 0x01) {
      back = bb->xmax;
    }
  }			
  return back;
}

/**	Get minimum y value from bounding box structure.
	@param	bb	Bounding box structure.
	@return	Minimum y value.
*/
double
dkfig_tool_bb_get_ymin DK_P1(dk_fig_bb *,bb)
{
  double back = 0.0;	
  if(bb) {
    if(bb->flags & 0x02) {
      back = bb->ymin;
    }
  }			
  return back;
}

/**	Get maximum y value from bounding box structure.
	@param	bb	Bounding box structure.
	@return	Maximum y value.
*/
double
dkfig_tool_bb_get_ymax DK_P1(dk_fig_bb *,bb)
{
  double back = 0.0;	
  if(bb) {
    if(bb->flags & 0x02) {
      back = bb->ymax;
    }
  }			
  return back;
}



/**	Check: X values available in bounding box structure.
	@param	bb	Bounding box structure.
	@return	Check result (1=values available, 0=no values).
*/
int
dkfig_tool_bb_have_x DK_P1(dk_fig_bb *,bb)
{
  int back = 0;	
  if(bb) {
    if(bb->flags & 0x01) back = 1;
  }		
  return back;
}

/**	Check: Y values available in bounding box structure.
	@param	bb	Bounding box structure.
	@return	Check result (1=values available, 0=no values).
*/
int
dkfig_tool_bb_have_y DK_P1(dk_fig_bb *,bb)
{
  int back = 0;
  
  if(bb) {
    if(bb->flags & 0x02) back = 1;
  } 
  return back;
}



/**	Add object bounding box to drawing bounding box.
	@param	dest	Destination bounding box (drawing).
	@param	src	Source bounding box (object).
*/
void
dkfig_tool_bb_add DK_P2(dk_fig_bb *,dest, dk_fig_bb *,src)
{
  
  if(dest && src) {
    if(src->flags & 0x01) {
      dkfig_tool_bb_add_x(dest, src->xmin);
      dkfig_tool_bb_add_x(dest, src->xmax);
    }
    if(src->flags & 0x02) {
      dkfig_tool_bb_add_y(dest, src->ymin);
      dkfig_tool_bb_add_y(dest, src->ymax);
    }
  } 
}



/**	Check whether the value "val" is in the given range.
	@param	left	Interval start.
	@param	right	Interval end.
	@param	val	Value to test.
	@return	1=in range, 0=outside range.
*/
static int
in_range DK_P3(double,left, double,right, double,val)
{
  int back = 0;
  double min, max;
  
  if(left < right) {
    min = left; max = right;
  } else {
    min = right; max = left;
  }
  if((min <= val) && (val <= max)) {
    back = 1;
  }
  
  return back;
}



/**	Add one point to a bounding box.
	@param	bb	Bounding box structure.
	@param	p	Point to add.
	@param	lwh	Half line width to add to point in each direction.
*/
static void
add_point_to_bb DK_P3(dk_fig_bb *,bb, dk_fig_point *,p, double,lwh)
{
  double v;
  int matherr;
  
  matherr = 0;
  v = dkma_add_double_ok(p->x, lwh, &matherr);
  if(!matherr) { dkfig_tool_bb_add_x(bb, v); }
  matherr = 0;
  v = dkma_sub_double_ok(p->x, lwh, &matherr);
  if(!matherr) { dkfig_tool_bb_add_x(bb, v); }
  matherr = 0;
  v = dkma_add_double_ok(p->y, lwh, &matherr);
  if(!matherr) { dkfig_tool_bb_add_y(bb, v); }
  matherr = 0;
  v = dkma_sub_double_ok(p->y, lwh, &matherr);
  if(!matherr) { dkfig_tool_bb_add_y(bb, v); }
  
}



/**	Add arrowhead data to bounding box.
	@param	bb	Bounding box structure.
	@param	a	Arrowhead structure.
	@param	lwh	Half line width to add in each direction.
*/
static void
add_arrow_to_bb DK_P3(dk_fig_bb *,bb, dk_fig_arrow *,a, double,lwh)
{
  
  add_point_to_bb(bb, &(a->p1), lwh);
  add_point_to_bb(bb, &(a->p2), lwh);
  add_point_to_bb(bb, &(a->p3), lwh);
  if(a->numpoints > 3) {
    add_point_to_bb(bb, &(a->p4), lwh);
  }
  
}




/**	Find arc extrema if both start and end point have y>0
	and the B point is on the stroke from A to C.
	@param	arc	Arc calculation structure.
*/
static void
top_arc_inside_extrema DK_P1(dk_fig_arc_calc *,arc)
{
  
  if(in_range(arc->aa, arc->ac, 0.0)) {		
    arc->xright = dkma_add_double_ok(arc->xm, arc->ra, &(arc->mathok));
  }
  if(in_range(arc->aa, arc->ac, M_PI_2)) {	
    arc->ytop = dkma_add_double_ok(arc->ym, arc->ra, &(arc->mathok));
  }
  if(in_range(arc->aa, arc->ac, M_PI)) {	
    arc->xleft = dkma_sub_double_ok(arc->xm, arc->ra, &(arc->mathok));
  }
  
}



/**	Find arc extrema if both start and end point have y>0
	and the B point is outside the stroke from A to C.
	@param	arc	Arc calculation structure.
*/
static void
top_arc_outside_extrema DK_P1(dk_fig_arc_calc *,arc)
{
  double min, max;
  
  if(arc->aa < arc->ac) {
    min = arc->aa; max = arc->ac;
  } else {
    min = arc->ac; max = arc->aa;
  }
  min += 2.0 * M_PI;
  if(in_range(min, max, 0.0)) {		
    arc->xright = dkma_add_double_ok(arc->xm, arc->ra, &(arc->mathok));
  }
  if(in_range(min, max, M_PI_2)) {	
    arc->ytop = dkma_add_double_ok(arc->ym, arc->ra, &(arc->mathok));
  }
  if(in_range(min, max, M_PI)) {	
    arc->xleft = dkma_sub_double_ok(arc->xm, arc->ra, &(arc->mathok));
  }
  if(in_range(min, max, (M_PI + M_PI_2))) {	
    arc->ybottom = dkma_sub_double_ok(arc->ym, arc->ra, &(arc->mathok));
  }
  if(in_range(min, max, (2.0 * M_PI))) {	
    arc->xright = dkma_add_double_ok(arc->xm, arc->ra, &(arc->mathok));
  }
  if(in_range(min, max, (2.0 * M_PI + M_PI_2))) {
    arc->ytop = dkma_add_double_ok(arc->ym, arc->ra, &(arc->mathok));
  }
  if(in_range(min, max, (3.0 * M_PI))) {
    arc->xleft = dkma_sub_double_ok(arc->xm, arc->ra, &(arc->mathok));
  }
  
}



/**	Find arc extrema if both start and end point have y>0.
	@param	arc	Arc calculation structure.
*/
static void
top_arc_extrema DK_P1(dk_fig_arc_calc *,arc)
{
  int inside;
  
  inside = in_range(arc->aa, arc->ac, arc->ab);
  if(inside) {
    top_arc_inside_extrema(arc);
    if(arc->aa <= arc->ac) {
      arc->astart = arc->aa; arc->alength = arc->ac - arc->aa;
    } else {
      arc->astart = arc->ac; arc->alength = arc->aa - arc->ac;
      arc->revert = 1;
    }
  } else {
    top_arc_outside_extrema(arc);
    if(arc->ac <= arc->aa) {
      arc->astart = arc->aa;
      arc->alength = 2 * M_PI + arc->ac - arc->aa;
    } else {
      arc->astart = arc->ac;
      arc->alength = 2 * M_PI + arc->aa - arc->ac;
      arc->revert = 1;
    }
  }
  
}



/**	Find arc extrema if both start and end point have y<0
	and the B point is on the stroke from A to C.
	@param	arc	Arc calculation structure.
*/
static void
bottom_arc_inside_extrema DK_P1(dk_fig_arc_calc *,arc)
{
  if(in_range(arc->aa, arc->ac, (0.0 - M_PI_2))) {	
    arc->ybottom = dkma_sub_double_ok(arc->ym, arc->ra, &(arc->mathok));
  }
}



/**	Find arc extrema if both start and end point have y<0
	and the B point is not on the stroke from A to C.
	@param	arc	Arc calculation structure.
*/
static void
bottom_arc_outside_extrema DK_P1(dk_fig_arc_calc *,arc)
{
  double min, max;
  if(arc->aa < arc->ac) {
    min = arc->aa; max = arc->ac;
  } else {
    min = arc->ac; max = arc->aa;
  }
  min += 2.0 * M_PI;
  if(in_range(min, max, (0.0 - M_PI))) {
    arc->xleft = dkma_sub_double_ok(arc->xm, arc->ra, &(arc->mathok));
  }
  if(in_range(min, max, (0.0 - M_PI_2))) {
    arc->ybottom = dkma_sub_double_ok(arc->ym, arc->ra, &(arc->mathok));
  }
  if(in_range(min, max, 0.0)) {
    arc->xright = dkma_add_double_ok(arc->xm, arc->ra, &(arc->mathok));
  }
  if(in_range(min, max, M_PI_2)) {
    arc->ytop = dkma_add_double_ok(arc->ym, arc->ra, &(arc->mathok));
  }
  if(in_range(min, max, M_PI)) {
    arc->xleft = dkma_sub_double_ok(arc->xm, arc->ra, &(arc->mathok));
  }
  if(in_range(min, max, (M_PI + M_PI_2))) {
    arc->ybottom = dkma_sub_double_ok(arc->ym, arc->ra, &(arc->mathok));
  }
  if(in_range(min, max, (2.0 * M_PI))) {
    arc->xright = dkma_add_double_ok(arc->xm, arc->ra, &(arc->mathok));
  }
}



/**	Find arc extrema if both start and end point have y<0.
	@param	arc	Arc calculation structure.
*/
static void
bottom_arc_extrema DK_P1(dk_fig_arc_calc *,arc)
{
  int inside;
  
  inside = in_range(arc->aa, arc->ac, arc->ab);
  if(inside) {
    bottom_arc_inside_extrema(arc);
    if(arc->aa <= arc->ac) {
      arc->astart = arc->aa; arc->alength = arc->ac - arc->aa;
    } else {
      arc->astart = arc->ac; arc->alength = arc->aa - arc->ac;
      arc->revert = 1;
    }
  } else {
    bottom_arc_outside_extrema(arc);
    if(arc->ac <= arc->aa) {
      arc->astart = arc->aa;
      arc->alength = 2.0 * M_PI + arc->ac - arc->aa;
    } else {
      arc->astart = arc->ac;
      arc->alength = 2.0 * M_PI + arc->aa - arc->ac;
      arc->revert = 1;
    }
  }
  
}



/**	Find arc extrema for strokes on the left side.
	@param	arc	Arc calculation structure.
	@param	pos	Positive alpha value.
	@param	neg	Negative alpha value.
*/
static void
left_side_extrema DK_P3(dk_fig_arc_calc *,arc, double,pos, double,neg)
{
  if(in_range(pos, (neg + 2.0 * M_PI), M_PI_2)) {
    arc->ytop = dkma_add_double_ok(arc->ym, arc->ra, &(arc->mathok));
  }
  if(in_range(pos, (neg + 2.0 * M_PI), (0.0 - M_PI_2))) {
    arc->ybottom = dkma_sub_double_ok(arc->ym, arc->ra, &(arc->mathok));
  }
  if(in_range(pos, (neg + 2.0 * M_PI), M_PI)) {
    arc->xleft = dkma_sub_double_ok(arc->xm, arc->ra, &(arc->mathok)); 
  }
}



/**	Find arc extrema for strokes on the right side.
	@param	arc	Arc calculation structure.
	@param	pos	Positive alpha value.
	@param	neg	Negative alpha value.
*/
static void
right_side_extrema DK_P3(dk_fig_arc_calc *,arc, double,pos, double,neg)
{
  if(in_range(neg,pos,0.0)) {
    arc->xright = dkma_add_double_ok(arc->xm, arc->ra, &(arc->mathok));
  }
  if(in_range(neg, pos, (0.0 - M_PI_2))) {
    arc->ybottom = dkma_sub_double_ok(arc->ym, arc->ra, &(arc->mathok));
  }
  if(in_range(neg, pos, M_PI_2)) {
    arc->ytop = dkma_add_double_ok(arc->ym, arc->ra, &(arc->mathok));
  }
}



/**	Find arc extrema for strokes crossing the y=0 line.
	@param	arc	Arc calculation structure.
*/
static void
side_arc_extrema DK_P1(dk_fig_arc_calc *,arc)
{
  double pos, neg;
  if(arc->aa < 0.0) {
    neg = arc->aa; pos = arc->ac;
  } else {
    neg = arc->ac; pos = arc->aa;
  }
  if(arc->ab >= 0.0) {
    if(arc->ab >= pos) {
      left_side_extrema(arc, pos, neg);
    } else {
      right_side_extrema(arc, pos, neg);
    }
  } else {
    if(arc->ab <= neg) {
      left_side_extrema(arc, pos, neg);
    } else {
      right_side_extrema(arc, pos, neg);
    }
  }
}



/**	Search for minimum and maximum x and y.
	@param	arc	Arc calculation structure.
*/
static void
arc_extrema DK_P1(dk_fig_arc_calc *,arc)
{
  if(arc->aa >= 0.0) {
    if(arc->ac >= 0.0) {
      top_arc_extrema(arc);
    } else {
      side_arc_extrema(arc);
      if((arc->ab >= arc->aa) || (arc->ab <= arc->ac)) {
        arc->astart = arc->aa;
	arc->alength = 2.0 * M_PI + arc->ac - arc->aa;
      } else {
        arc->astart = arc->ac;
	arc->alength = arc->aa - arc->ac;
	arc->revert = 1;
      }
    }
  } else {
    if(arc->ac >= 0.0) {	
      side_arc_extrema(arc);
      if((arc->ab >= arc->ac) || (arc->ab <= arc->aa)) {
        arc->astart = arc->ac;
	arc->alength = 2.0 * M_PI + arc->aa - arc->ac;
	arc->revert = 1;	
      } else {
        arc->astart = arc->aa;	
	arc->alength = arc->ac - arc->aa;
      }
    } else {
      bottom_arc_extrema(arc);
    }
  }
}



/**	Calculate the center point for three given points.
	On success the arc->mathok component is unchanged.
	On errors (2 or three equal points or three points
	on on line) the component is set.
	@param	arc	Arc calculation structure.
*/
static void
calculate_arc_center DK_P1(dk_fig_arc_calc *,arc)
{
  double t, zaehler, nenner;
  
#if NO_MATH_CHECK
  zaehler = 0.5 * ((arc->xb - arc->xc) * (arc->xc - arc->xa) - (arc->yc - arc->yb) * (arc->yc - arc->ya));
  
  nenner = (arc->yb - arc->ya) * (arc->xb - arc->xc) - (arc->yc - arc->yb) * (arc->xa - arc->xb);
  
  t = zaehler / nenner; 
  arc->xm = 0.5 * (arc->xa + arc->xb) + t * (arc->yb - arc->ya);
  arc->ym = 0.5 * (arc->ya + arc->yb) + t * (arc->xa - arc->xb);
  
#endif
  zaehler = 0.5 * dkma_sub_double_ok(
    dkma_mul_double_ok(
      dkma_sub_double_ok(arc->xb, arc->xc, &(arc->mathok)),
      dkma_sub_double_ok(arc->xc, arc->xa, &(arc->mathok)),
      &(arc->mathok)
    ),
    dkma_mul_double_ok(
      dkma_sub_double_ok(arc->yc, arc->yb, &(arc->mathok)),
      dkma_sub_double_ok(arc->yc, arc->ya, &(arc->mathok)),
      &(arc->mathok)
    ),
    &(arc->mathok)
  ); 
  nenner = dkma_sub_double_ok(
    dkma_mul_double_ok(
      dkma_sub_double_ok(arc->yb, arc->ya, &(arc->mathok)),
      dkma_sub_double_ok(arc->xb, arc->xc, &(arc->mathok)),
      &(arc->mathok)
    ),
    dkma_mul_double_ok(
      dkma_sub_double_ok(arc->yc, arc->yb, &(arc->mathok)),
      dkma_sub_double_ok(arc->xa, arc->xb, &(arc->mathok)),
      &(arc->mathok)
    ),
    &(arc->mathok)
  ); 
  t = dkma_div_double_ok(zaehler, nenner, &(arc->mathok));
  
  arc->xm = dkma_add_double_ok(
    (0.5 * dkma_add_double_ok(arc->xa, arc->xb, &(arc->mathok))),
    dkma_mul_double_ok(
      t,
      dkma_sub_double_ok(arc->yb, arc->ya, &(arc->mathok)),
      &(arc->mathok)
    ),
    &(arc->mathok)
  );
  arc->ym = dkma_add_double_ok(
    (0.5 * dkma_add_double_ok(arc->ya, arc->yb, &(arc->mathok))),
    dkma_mul_double_ok(
      t,
      dkma_sub_double_ok(arc->xa, arc->xb, &(arc->mathok)),
      &(arc->mathok)
    ),
    &(arc->mathok)
  );
  
  
}



/**	Calculate bounding box for an arc in mathematical
	coordinates (positive y grow upwards).
	@param	arc	Arc calculation structure.
*/
void
dkfig_tool_arc_calc DK_P1(dk_fig_arc_calc *,arc)
{
  double detx, dety;
  
  arc->xm = arc->ym = arc->ra = 0.0;
  arc->aa = arc->ab = arc->ac = 0.0;
  arc->astart = arc->alength = 0.0;
  arc->revert = 0;
  arc->xleft = arc->xright = arc->ytop = arc->ybottom = 0.0;
  arc->mathok = 0;
  calculate_arc_center(arc);
  if(!(arc->mathok)) {
    
    detx = dkma_sub_double_ok(arc->xm, arc->xa, &(arc->mathok));
    dety = dkma_sub_double_ok(arc->ym, arc->ya, &(arc->mathok));
    arc->ra = sqrt(
      dkma_add_double_ok(
        dkma_mul_double_ok(detx, detx, &(arc->mathok)),
	dkma_mul_double_ok(dety, dety, &(arc->mathok)),
        &(arc->mathok)
      )
    ); 
    arc->aa = dkma_atan2(
      dkma_sub_double_ok(arc->ya, arc->ym, &(arc->mathok)),
      dkma_sub_double_ok(arc->xa, arc->xm, &(arc->mathok))
    ); 
    arc->ab = dkma_atan2(
      dkma_sub_double_ok(arc->yb, arc->ym, &(arc->mathok)),
      dkma_sub_double_ok(arc->xb, arc->xm, &(arc->mathok))
    ); 
    arc->ac = dkma_atan2(
      dkma_sub_double_ok(arc->yc, arc->ym, &(arc->mathok)),
      dkma_sub_double_ok(arc->xc, arc->xm, &(arc->mathok))
    ); 
    arc->xleft = arc->xright = arc->xa;
    if(arc->xb < arc->xleft) arc->xleft = arc->xb;
    if(arc->xb > arc->xright) arc->xright = arc->xb;
    if(arc->xc < arc->xleft) arc->xleft = arc->xc;
    if(arc->xc > arc->xright) arc->xright = arc->xc;
    arc->ytop  = arc->ybottom = arc->ya;
    if(arc->yb < arc->ybottom) arc->ybottom = arc->yb;
    if(arc->yb > arc->ytop)    arc->ytop    = arc->yb;
    if(arc->yc < arc->ybottom) arc->ybottom = arc->yc;
    if(arc->yc > arc->ytop)    arc->ytop    = arc->yc;
    arc_extrema(arc);
  } 
}



/**	Get half of the linewidth.
	@param	th	Line thickness.
	@param	d	Fig drawing structure.
*/
static double
make_lwh DK_P2(long,th, dk_fig_drawing *,d)
{
  double back = 0.0;
  /* 2004/04/12 bug fixed: multiplication fres * was missing */
  back = d->fres * dkma_l_to_double(th) / 160.0;
  if((d->opt1) & DKFIG_OPT_ENLIGHTEN_LOOK) {
    back *= 0.5;
  }
  return back;
}



/**	Calculate bounding box for an arc in mathematical
	coordinates (positive y grow upwards).
	@param	o	Arc object.
	@param	d	Fig drawing structure.
*/
void
dkfig_tool_bb_arc DK_P2(dk_fig_object *,o, dk_fig_drawing *,d)
{
  dk_fig_arc_calc arc;
  dk_fig_arc *p;
  double lwh = 0.0, value = 0.0;
  int mathok = 0; 
  
  if(o) { dkfig_tool_bb_reset(&(o->dbb)); }
  if(o && d) {
    p = (dk_fig_arc *)(o->data);
    if(p) {
      lwh = make_lwh((o->fpd).lt, d);
      arc.xa = arc.ya = arc.xb = arc.yb = arc.xc = arc.yc = 0.0;
      arc.xa = dkma_l_to_double(p->x1);
      arc.ya = 0.0 - dkma_l_to_double(p->y1);
      arc.xb = dkma_l_to_double(p->x2);
      arc.yb = 0.0 - dkma_l_to_double(p->y2);
      arc.xc = dkma_l_to_double(p->x3);
      arc.yc = 0.0 - dkma_l_to_double(p->y3);
      dkfig_tool_arc_calc(&arc);
      if(!(arc.mathok)) {
	dkfig_tool_bb_add_x(&(o->dbb), arc.xleft);
	dkfig_tool_bb_add_x(&(o->dbb), arc.xright);
	dkfig_tool_bb_add_y(&(o->dbb), (0.0 - arc.ytop));
	dkfig_tool_bb_add_y(&(o->dbb), (0.0 - arc.ybottom));
	mathok = 0;
	value = dkma_add_double_ok(arc.xright, lwh, &mathok);
	if(!mathok) {
	  dkfig_tool_bb_add_x(&(o->dbb), value);
	}
	mathok = 0;
	value = dkma_sub_double_ok(arc.xleft, lwh, &mathok);
	if(!mathok) {
	  dkfig_tool_bb_add_x(&(o->dbb), value);
	}
	mathok = 0;
	value = dkma_add_double_ok((0.0 - arc.ytop), lwh, &mathok);
	if(!mathok) {
	  dkfig_tool_bb_add_y(&(o->dbb), value);
	}
	mathok = 0;
	value = dkma_sub_double_ok((0.0 - arc.ytop), lwh, &mathok);
	if(!mathok) {
	  dkfig_tool_bb_add_y(&(o->dbb), value);
	}
	mathok = 0;
	value = dkma_add_double_ok((0.0 - arc.ybottom), lwh, &mathok);
	if(!mathok) {
	  dkfig_tool_bb_add_y(&(o->dbb), value);
	}
	mathok = 0;
	value = dkma_sub_double_ok((0.0 - arc.ybottom), lwh, &mathok);
	if(!mathok) {
	  dkfig_tool_bb_add_y(&(o->dbb), value);
	}
      }
      if((o->fpd).ar & 1) {
        add_arrow_to_bb(&(o->dbb), &((o->fpd).ahf), lwh);
      }
      if((o->fpd).ar & 2) {
        add_arrow_to_bb(&(o->dbb), &((o->fpd).ahb), lwh);
      }
    } 
  } 
}



/**	Calculate bounding box for polyline object.
	@param	o	Polyline object.
	@param	d	Fig drawing structure.
*/
void
dkfig_tool_bb_polyline DK_P2(dk_fig_object *,o, dk_fig_drawing *,d)
{
  dk_fig_polyline *p;
  double lwh = 0.0;
  
  long *lptr = NULL;
  size_t i = 0;
  double value;
  
  if(o) { dkfig_tool_bb_reset(&(o->dbb)); }
  if(o && d) {
    p = (dk_fig_polyline *)(o->data);
    if(p) {
      lwh = make_lwh((o->fpd).lt, d);
      lptr = p->xvalues;
      if(lptr) {
        for(i = 0; i < p->npoints; i++) {
	  value = dkma_l_to_double(*(lptr++));
	  dkfig_tool_bb_add_x(&(o->dbb), value);
	  dkfig_tool_bb_add_x(&(o->dbb), (value-lwh));
	  dkfig_tool_bb_add_x(&(o->dbb), (value+lwh));
	}
      }
      lptr = p->yvalues;
      if(lptr) {
        for(i = 0; i < p->npoints; i++) {
	  value = dkma_l_to_double(*(lptr++));
	  dkfig_tool_bb_add_y(&(o->dbb), value);
	  dkfig_tool_bb_add_y(&(o->dbb), (value-lwh));
	  dkfig_tool_bb_add_y(&(o->dbb), (value+lwh));
	}
      }
      if((o->fpd).ar & 1) {
        add_arrow_to_bb(&(o->dbb), &((o->fpd).ahf), lwh);
      }
      if((o->fpd).ar & 2) {
        add_arrow_to_bb(&(o->dbb), &((o->fpd).ahb), lwh);
      }
    } 
  } 
}



/**	Calculate bounding box for an ellipse object.
	@param	o	Ellipse object.
	@param	d	Fig drawing structure.
*/
void
dkfig_tool_bb_ellipse DK_P2(dk_fig_object *,o, dk_fig_drawing *,d)
{
  dk_fig_rot_ellipse e;
  dk_fig_ellipse *p;
  double lwh;
  
  if(o) { dkfig_tool_bb_reset(&(o->dbb)); }
  if(o && d) {
    p = (dk_fig_ellipse *)(o->data);
    if(p) {
      lwh    = make_lwh((o->fpd).lt, d);
      e.rx   = dkma_l_to_double(p->radiusx);
      e.ry   = dkma_l_to_double(p->radiusy);
      e.phi0 = p->angle;
      dkfig_tool_rotated_ellipse(&e);
      /* centerx, centery */
      dkfig_tool_bb_add_x(&(o->dbb), dkma_l_to_double(p->centerx));
      dkfig_tool_bb_add_y(&(o->dbb), dkma_l_to_double(p->centery));
      dkfig_tool_bb_add_x(&(o->dbb), (dkma_l_to_double(p->centerx) - e.w - lwh));
      dkfig_tool_bb_add_y(&(o->dbb), (dkma_l_to_double(p->centery) - e.h - lwh));
      dkfig_tool_bb_add_x(&(o->dbb), (dkma_l_to_double(p->centerx) + e.w + lwh));
      dkfig_tool_bb_add_y(&(o->dbb), (dkma_l_to_double(p->centery) + e.h + lwh));
    }
  }
  
  
}



/**	Calculate bounding box for a spline object.
	@param	o	Spline object.
	@param	d	Fig drawing structure.
*/
void
dkfig_tool_bb_spline DK_P2(dk_fig_object *,o, dk_fig_drawing *,d)
{
  int matherr;
  dk_fig_spline *sptr;	dk_fig_bezier_point *bptr;
  size_t bsegs, cbseg, lindex, rindex;
  double lwh, value, d0, d1;
  dk_bspline_t bsp;
  
  lwh = 0.0;
  if(o) {	
  dkfig_tool_bb_reset(&(o->dbb));
  if(d) {	
  sptr = (dk_fig_spline *)(o->data);
  if(sptr) {
  bptr = sptr->bpoints;
  if(bptr) {	
    lwh = make_lwh((o->fpd).lt, d);
    /* 2004/05/24 bug fixed: npoints was used instead of nbpoints */
    bsegs = sptr->nbpoints - 1;
    switch((o->fpd).st) {
      case 1: case 3: case 5: bsegs = sptr->nbpoints; break;
    }
    for(cbseg = 0; cbseg < bsegs; cbseg++) {
      lindex = cbseg;
      rindex = lindex + 1;
      if(lindex >= sptr->nbpoints) { lindex = lindex - sptr->nbpoints; }
      if(rindex >= sptr->nbpoints) { rindex = rindex - sptr->nbpoints; }
      matherr = 0;
      value = dkma_add_double_ok((bptr[lindex]).value.x, lwh, &matherr);
      if(!matherr) { dkfig_tool_bb_add_x(&(o->dbb), value); }
      matherr = 0;
      value = dkma_sub_double_ok((bptr[lindex]).value.x, lwh, &matherr);
      if(!matherr) { dkfig_tool_bb_add_x(&(o->dbb), value); }
      matherr = 0;
      value = dkma_add_double_ok((bptr[lindex]).value.y, lwh, &matherr);
      if(!matherr) { dkfig_tool_bb_add_y(&(o->dbb), value); }
      matherr = 0;
      value = dkma_sub_double_ok((bptr[lindex]).value.y, lwh, &matherr);
      if(!matherr) { dkfig_tool_bb_add_y(&(o->dbb), value); }
      matherr = 0;
      value = dkma_add_double_ok((bptr[rindex]).value.x, lwh, &matherr);
      if(!matherr) { dkfig_tool_bb_add_x(&(o->dbb), value); }
      matherr = 0;
      value = dkma_sub_double_ok((bptr[rindex]).value.x, lwh, &matherr);
      if(!matherr) { dkfig_tool_bb_add_x(&(o->dbb), value); }
      matherr = 0;
      value = dkma_add_double_ok((bptr[rindex]).value.y, lwh, &matherr);
      if(!matherr) { dkfig_tool_bb_add_y(&(o->dbb), value); }
      matherr = 0;
      value = dkma_sub_double_ok((bptr[rindex]).value.y, lwh, &matherr); 
      if(!matherr) { dkfig_tool_bb_add_y(&(o->dbb), value); }
      
      
      d0 = ((bptr[lindex]).rcontrol.x - (bptr[lindex]).value.x) * 3.0;
      d1 = ((bptr[rindex]).value.x - (bptr[rindex]).lcontrol.x) * 3.0;
      if(dkbsp_minmax(&bsp, (bptr[lindex]).value.x, d0, (bptr[rindex]).value.x, d1)) {
        matherr = 0;
	value = dkma_add_double_ok(bsp.min, lwh, &matherr);
	if(!matherr) { dkfig_tool_bb_add_x(&(o->dbb), value); }
	matherr = 0;
	value = dkma_sub_double_ok(bsp.min, lwh, &matherr);
	if(!matherr) { dkfig_tool_bb_add_x(&(o->dbb), value); }
        matherr = 0;
	value = dkma_add_double_ok(bsp.max, lwh, &matherr);
	if(!matherr) { dkfig_tool_bb_add_x(&(o->dbb), value); }
	matherr = 0;
	value = dkma_sub_double_ok(bsp.max, lwh, &matherr);
	if(!matherr) { dkfig_tool_bb_add_x(&(o->dbb), value); }
      }
      
      
      d0 = ((bptr[lindex]).rcontrol.y - (bptr[lindex]).value.y) * 3.0;
      d1 = ((bptr[rindex]).value.y - (bptr[rindex]).lcontrol.y) * 3.0;
      if(dkbsp_minmax(&bsp, (bptr[lindex]).value.y, d0, (bptr[rindex]).value.y, d1)) {
        matherr = 0;
	value = dkma_add_double_ok(bsp.min, lwh, &matherr);
	if(!matherr) { dkfig_tool_bb_add_y(&(o->dbb), value); }
	matherr = 0;
	value = dkma_sub_double_ok(bsp.min, lwh, &matherr);
	if(!matherr) { dkfig_tool_bb_add_y(&(o->dbb), value); }
        matherr = 0;
	value = dkma_add_double_ok(bsp.max, lwh, &matherr);
	if(!matherr) { dkfig_tool_bb_add_y(&(o->dbb), value); }
	matherr = 0;
	value = dkma_sub_double_ok(bsp.max, lwh, &matherr);
	if(!matherr) { dkfig_tool_bb_add_y(&(o->dbb), value); }
      }
    }
  }
  if((o->fpd).ar & 1) {
    add_arrow_to_bb(&(o->dbb), &((o->fpd).ahf), lwh);
  }
  if((o->fpd).ar & 2) {
    add_arrow_to_bb(&(o->dbb), &((o->fpd).ahb), lwh);
  }
  }
  }
  }
  
  
}



/**	Distance between point (xp,yp) and line (0,0)--(x0,y0).
	@param	xp	Point x value.
	@param	yp	Point y value.
	@param	x0	Line endpoint x value.
	@param	y0	Line endpoint y value.
	@return	Distance between point and line.
*/
double
dkfig_tool_dist_pt_to_line0 DK_P4(double,xp,double,yp,double,x0,double,y0)
{
  double back = 0.0;
  int    mathok = 0;
  double tF, xF, yF, res, deltax, deltay;
  
  tF = dkma_div_double_ok(
    dkma_add_double_ok(
      dkma_mul_double_ok(yp,y0,&mathok),
      dkma_mul_double_ok(xp,x0,&mathok),
      &mathok
    ),
    dkma_add_double_ok(
      dkma_mul_double_ok(y0,y0,&mathok),
      dkma_mul_double_ok(x0,x0,&mathok),
      &mathok
    ),
    &mathok
  );
  xF = dkma_mul_double_ok(tF,x0,&mathok);
  yF = dkma_mul_double_ok(tF,y0,&mathok);
  deltax = dkma_sub_double_ok(xF,xp,&mathok);
  deltay = dkma_sub_double_ok(yF,yp,&mathok);
  res = sqrt(
    dkma_add_double_ok(
      dkma_mul_double_ok(deltax,deltax,&mathok),
      dkma_mul_double_ok(deltay,deltay,&mathok),
      &mathok
    )
  );
  if(!mathok) {
    back = res;
  } 
  return back;
}



/**	Calculate width and height of a rotated ellipse.
	The ellipse parameters rx, ry and phi0 (radians) are
	used as calculation input, output is stored in w and
	h (center to right, center to top).
	@param	e	Ellipse object.
*/
void
dkfig_tool_rotated_ellipse DK_P1(dk_fig_rot_ellipse *,e)
{
  double th, tw, w, h, xp, yp;
  int mathok;
  
  if(e) { 
    mathok = 0; e->h = 0.0; e->w = 0.0;
    th = dkma_atan2(
      dkma_mul_double_ok(e->ry, cos(e->phi0), &mathok),
      dkma_mul_double_ok(e->rx, sin(e->phi0), &mathok)
    ); 
    tw = dkma_atan2(
      (0.0 - dkma_mul_double_ok(e->ry, sin(e->phi0), &mathok)),
      dkma_mul_double_ok(e->rx, cos(e->phi0), &mathok)
    ); 
    if(!mathok) {
      xp = dkma_mul_double_ok(e->rx, cos(th), &mathok);
      yp = dkma_mul_double_ok(e->ry, sin(th), &mathok);
      h = dkfig_tool_dist_pt_to_line0(xp,yp,cos(e->phi0),(0.0-sin(e->phi0)));
      xp = dkma_mul_double_ok(e->rx, cos(tw), &mathok);
      yp = dkma_mul_double_ok(e->ry, sin(tw), &mathok);
      w = dkfig_tool_dist_pt_to_line0(
        xp,yp,cos(M_PI_2 - e->phi0),sin(M_PI_2 - e->phi0)
      ); 
      if(!mathok) {
        e->h = h; e->w = w;
      }
    } 
  } 
}



/**	Initialize data structure for one Fig point.
	@param	pptr	Point to initialize.
*/
static void
null_fig_point DK_P1(dk_fig_point *,pptr)
{
  pptr->x = pptr->y = 0.0;
}



/**	Initialize data structure for one Bezier point.
	@param	pptr	Bezier point to initialize.
*/
static void
null_bezier_point DK_P1(dk_fig_bezier_point *,pptr)
{
  null_fig_point(&(pptr->value));
  null_fig_point(&(pptr->lcontrol));
  null_fig_point(&(pptr->rcontrol));
}



/**	Initialize all Bezier points in a spline object.
	@param	points	Beginning of array.
	@param	nelem	Number of Bezier points in the array.
*/
static void
null_all_bezier_points DK_P2(dk_fig_bezier_point *,points, size_t,nelem)
{
  size_t i; dk_fig_bezier_point *ptr;
  i = nelem; ptr = points;
  while(i--) {
    null_bezier_point(ptr++);
  }
}



/**	Newton iteration scheme for spline shortening.
*/
typedef struct {
  dk_fig_object *o;		/**< Current object. */
  dk_fig_drawing*d;		/**< Fig drawing object. */
  dk_fig_spline *s;		/**< Spline data. */
  unsigned long min;		/**< Minimum number of iteration steps. */
  unsigned long max;		/**< Maximum number of iteration steps. */
  int		 end;		/**< Flag: finished (in). */
  double	 t;		/**< t-value for iteration step (in,out). */
  double	 value;		/**< Coordinate value (out). */
  double	 dvdt;		/**< dv/dt (out). */
  double	 dist;		/**< delta t (in). */
  double	 ox;		/**< Old x (in). */
  double	 oy;		/**< Old y (in). */
  /* internals */
  double	 xl;		/**< Left x  (in,out). */
  double	 xr;		/**< Right x (in,out). */
  double	 xlp;		/**< Left x control (in,out). */
  double	 xrm;		/**< Right x control (in,out). */
  double	 yl;		/**< Left y (in,out). */
  double	 yr;		/**< Right y (in,out). */
  double	 ylp;		/**< Left y control (in,out). */
  double	 yrm;		/**< Right y control (in,out). */
  double	 tcur;		/**< Current t value (in,out). */
  unsigned long	 currentstep;	/**< Current step width (in,out). */
  size_t	 lindex;	/**< Index of left point (in). */
  size_t	 rindex;	/**< Index of right point (in). */
  double	 xcurrent;	/**< Current x (in, out). */
  double	 ycurrent;	/**< Current y (in, out). */
  double	 dxdt;		/**< dx/dt (in). */
  double	 dydt;		/**< dy/dt (in). */
} spline_iteration_t;



/**	For a current value t calculate f(t), df/dt at t and t_next for Newton
	iteration scheme.
	@param	si	Spline iteration structure.
	@return	1 on success, 0 on error.
*/
static int
do_calculate DK_P1(spline_iteration_t *,si)
{
  int back = 0;
  int me   = 0;
  dk_bspline_t bsp;
  double x, y, dxdt, dydt, sqrv, dx, dy;
  
  if(dkbsp_for_t(&bsp,si->xl,si->xlp,si->xr,si->xrm,si->tcur)) {
    x = si->xcurrent = bsp.xvalue; dxdt = si->dxdt = bsp.dxdt;
    if(dkbsp_for_t(&bsp,si->yl,si->ylp,si->yr,si->yrm,si->tcur)) {
      y = si->ycurrent = bsp.xvalue; dydt = si->dydt = bsp.dxdt;
      back = 1;
      dx = dkma_sub_double_ok(x, si->ox, &me);
      dy = dkma_sub_double_ok(y, si->oy, &me);	
      sqrv = sqrt(
        dkma_add_double_ok(
	  dkma_mul_double_ok(dx, dx, &me),
	  dkma_mul_double_ok(dy, dy, &me),
	  &me
	)
      );					
      si->value = dkma_sub_double_ok(sqrv, si->dist, &me);
      si->dvdt  = dkma_div_double_ok(
        dkma_add_double_ok(
	  dkma_mul_double_ok(dx, dxdt, &me),
	  dkma_mul_double_ok(dy, dydt, &me),
	  &me
	),
	sqrv,
	&me
      );					
    }
  }
  if(me) { back = 0; }
  
  return back;
}



/**	Run an iteration to shorten a spline for arrowheads.  The Newton
	iteration scheme is used.
	@param	si	Spline iteration structure.
	@return	1 on success, 0 on error.
*/
static int
do_iteration DK_P1(spline_iteration_t *,si)
{
  int back = 0;
  int cc = 0;
  int me = 0;	/* math error */
  double oldt, oldvalue;
  
  oldt = oldvalue = 0.0;
  si->currentstep = 0UL; cc = 1;
  while(cc && (!back)) {
    
    /* set lindex, rindex */
    if(si->t <= dkma_l_to_double((long)((si->s)->nbpoints) - 1L)) {
      if(si->t >= 0.0) {
	si->lindex = (size_t)dkma_double_to_l_ok(floor(si->t), &me);
	si->rindex = si->lindex + 1;
	if(si->rindex >= (si->s)->nbpoints) {
	  si->rindex = (si->s)->nbpoints - 1;
	  si->lindex = si->rindex - 1;
	}
      } else {
	cc = 0;	
      }
    } else {
      cc = 0;	
    }
    if(me) { cc = 0; }
    if(cc) {
      si->xl   = ((si->s)->bpoints)[si->lindex].value.x;
      si->yl   = ((si->s)->bpoints)[si->lindex].value.y;
      si->xr   = ((si->s)->bpoints)[si->rindex].value.x;
      si->yr   = ((si->s)->bpoints)[si->rindex].value.y;
      si->xlp  = ((si->s)->bpoints)[si->lindex].rcontrol.x;
      si->ylp  = ((si->s)->bpoints)[si->lindex].rcontrol.y;
      si->xrm  = ((si->s)->bpoints)[si->rindex].lcontrol.x;
      si->yrm  = ((si->s)->bpoints)[si->rindex].lcontrol.y;
      si->tcur = si->t - dkma_l_to_double((long)(si->lindex));
      
      
      
      if(do_calculate(si)) {
        
	
        if(si->currentstep) {			
	  if(si->currentstep >= si->min) {	
	  if(fabs(si->value) < DKFIG_EPSILON) {	
	  if(fabs(dkma_sub_double_ok(si->t, oldt, &me)) < DKFIG_EPSILON) {
	  if(!me) {				
	    back = 1;	
	  }
	  }
	  }
	  }
	}
	if(!back) {		
	  oldvalue = si->value;
	  oldt     = si->t;
	}
      } else {		
        cc = 0;
      }
    }
    if(si->currentstep >= si->max) {
      cc = 0;	
    }
    if((cc) && (!back)) {
      si->currentstep += 1UL;
      si->t = dkma_sub_double_ok(
        si->t,
	dkma_div_double_ok(si->value, si->dvdt, &me),
	&me
      );
      if(me) { cc = 0; }
    }
    
  }
  if(me) {
    back = 0;
  }
  
  return back;
}



/**	Calculate distance between two points.
	@param	x0	First point, x value.
	@param	x1	Second point, x value.
	@param	y0	First point, y value.
	@param	y1	Second point, y value.
	@param	me	Pointer to variable for mathematical error flag.
	@return	Distance between the points.
*/
static double
distance DK_P5(double,x0, double,x1, double,y0, double,y1, int *,me)
{
  double back;
  double dx, dy;
  dx = dkma_sub_double_ok(x1,x0,me);
  dy = dkma_sub_double_ok(y1,y0,me);
  back = dkma_add_double_ok(
    dkma_mul_double_ok(dx,dx,me),
    dkma_mul_double_ok(dy,dy,me),
    me
  );
  back = sqrt(back);
  return back;
}



/**	Setup partial bezier segments on the ends for arrowheads.
	@param	bp	Array of Bezier point structures.
	@param	width	Line width.
	@param	side	0=left side of segment, 1=right side of segment.
	@param	me	Pointer to variable for math error flag.
*/
static void
correct_bezier_point DK_P4(dk_fig_bezier_point *,bp, double,width, int,side, int *,me)
{
  
  
#line 1662 "dkfigtoo.ctr"
  if(side) {	
    (bp->lcontrol).x = dkma_sub_double_ok(
      (bp->value).x,
      dkma_mul_double_ok(
        width,
	dkma_sub_double_ok(
	  (bp->value).x,
	  (bp->lcontrol).x,
	  me
	),
        me
      ),
      me
    );
    (bp->lcontrol).y = dkma_sub_double_ok(
      (bp->value).y,
      dkma_mul_double_ok(
        width,
	dkma_sub_double_ok(
	  (bp->value).y,
	  (bp->lcontrol).y,
	  me
	),
        me
      ),
      me
    );
  } else {	
    (bp->rcontrol).x = dkma_add_double_ok(
      (bp->value).x,
      dkma_mul_double_ok(
        width,
	dkma_sub_double_ok(
	  (bp->rcontrol).x,
	  (bp->value).x,
	  me
	),
	me
      ),
      me
    );
    (bp->rcontrol).y = dkma_add_double_ok(
      (bp->value).y,
      dkma_mul_double_ok(
        width,
	dkma_sub_double_ok(
	  (bp->rcontrol).y,
	  (bp->value).y,
	  me
	),
	me
      ),
      me
    );
  }
  
#line 1718 "dkfigtoo.ctr"
  
}



/**	Correct Bezier spline segment at the end to apply forward arrowhead.
	@param	o	Fig object.
	@param	d	Fig drawing structure.
	@param	sptr	Fig spline structure.
	@return	1 on success, 0 on error.
*/
static int
setup_forward_partial DK_P3(dk_fig_object *,o, dk_fig_drawing *,d, dk_fig_spline *,sptr)
{
  int back = 1;
  int me   = 0;
  double width;
  
  width = dkma_sub_double_ok(
    sptr->te,
    dkma_l_to_double((long)(sptr->normale)),
    &me
  ); 
DK_MEMCPY(&(sptr->pe2),&((sptr->bpoints)[sptr->normale]),sizeof(dk_fig_bezier_point));
  correct_bezier_point(&(sptr->pe2), width, 0, &me);
  correct_bezier_point(&(sptr->pe), width, 1, &me);
  if(me) { back = 0; }
  
  return back;
}



/**	Correct Bezier spline segment at the start to apply backward arrowhead.
	@param	o	Fig object.
	@param	d	Fig drawing structure.
	@param	sptr	Fig spline structure.
	@return	1 on success, 0 on error.
*/
static int
setup_backward_partial DK_P3(dk_fig_object *,o, dk_fig_drawing *,d, dk_fig_spline *,sptr)
{
  int back = 1;
  int me   = 0;
  double width;
  
  width = dkma_sub_double_ok(
    dkma_l_to_double((long)(sptr->normals)),
    sptr->ta,
    &me
  ); 
DK_MEMCPY(&(sptr->pa2),&((sptr->bpoints)[sptr->normals]),sizeof(dk_fig_bezier_point));
  correct_bezier_point(&(sptr->pa), width, 0, &me);
  correct_bezier_point(&(sptr->pa2), width, 1, &me);
  if(me) { back = 0; }
  
  return back;
}



/**	Correct Bezier spline element. This is the very unlikely case that we
	have only one Bezier spline element which needs correction on both
	ends.
	@param	o	Fig object.
	@param	d	Fig drawing object.
	@param	sptr	Spline object structure.
	@return	1 on success, 0 on error.
*/
static int
setup_one_partial DK_P3(dk_fig_object *,o, dk_fig_drawing *,d, dk_fig_spline *,sptr)
{
  int back = 1;
  int me   = 0;
  double width;
  
  width = dkma_sub_double_ok(sptr->te, sptr->ta, &me);
  DK_MEMCPY(&(sptr->pe2),&(sptr->pa),sizeof(dk_fig_bezier_point));
  DK_MEMCPY(&(sptr->pa2),&(sptr->pe),sizeof(dk_fig_bezier_point));
  correct_bezier_point(&(sptr->pe2), width, 0, &me);
  correct_bezier_point(&(sptr->pe), width, 1, &me);
  correct_bezier_point(&(sptr->pa), width, 0, &me);
  correct_bezier_point(&(sptr->pa2), width, 1, &me);
  sptr->flags = sptr->flags | DKFIG_SPLINE_FLAG_ONE_PARTIAL;
  
  if(me) { back = 0; }
  
  return back;
}



/**	Initialize data structure for spline end shortening interpolation.
	@param	si	Spline interpolation structure.
*/
static void
null_si DK_P1(spline_iteration_t *,si)
{
  
  si->xl = 0.0; si->xr = 0.0; si->xlp = 0.0; si->xrm = 0.0;
  si->yl = 0.0; si->yr = 0.0; si->ylp = 0.0; si->yrm = 0.0;
  si->tcur = 0.0; si->currentstep = 0UL;
  si->lindex = 0; si->rindex = 0;
  si->xcurrent = 0.0; si->ycurrent = 0.0;
  
}



/**	Shorten spline ends for arrowheads.
	@param	o	Fig object.
	@param	d	Fig drawing structure.
	@param	sptr	Fig spline structure.
	@param	c	Conversion job structure.
	@return	1 on success, 0 on error.
*/
static int
shorten_spline_for_arrowheads DK_P4(dk_fig_object *,o, dk_fig_drawing *,d, dk_fig_spline *,sptr, dk_fig_conversion *,c)
{
  int back = 1;
  int me   = 0;
  int rm   = 0;
  int suc  = 0;
  double   dist;
  spline_iteration_t si;
  
  si.o = o; si.d = d; si.s = sptr;
  si.min = d->minitsteps; si.max = d->maxitsteps;
  if(((o->fpd).ar) & 1) {	/* forward arrow */
    rm = suc = 0;
    if((sptr->segs > 0) && (sptr->nbpoints > (sptr->segs + 1))) {
      null_si(&si);
      si.end  = 1;
      si.t    = dkma_l_to_double(((long)(sptr->nbpoints)) - 1L);
      si.dist = (o->fpd).ahf.decrease;
      si.ox   = (sptr->bpoints)[sptr->nbpoints - 1].value.x;
      si.oy   = (sptr->bpoints)[sptr->nbpoints - 1].value.y;
      me      = 0;
      dist    = distance(
        (sptr->bpoints)[sptr->nbpoints - 1 - sptr->segs].value.x,
        (sptr->bpoints)[sptr->nbpoints - 1].value.x,
        (sptr->bpoints)[sptr->nbpoints - 1 - sptr->segs].value.y,
        (sptr->bpoints)[sptr->nbpoints - 1].value.y,
        &me
      );
      si.t    = si.t - dkma_mul_double_ok(
	dkma_l_to_double((long)(sptr->segs)),
	dkma_div_double_ok(si.dist, dist, &me),
	&me
      );
      
      if(do_iteration(&si)) {
	
	suc = 1;
        sptr->te = si.t;
        (sptr->pe).value.x = si.xcurrent;
        (sptr->pe).value.y = si.ycurrent;
        (sptr->pe).lcontrol.x = dkma_sub_double_ok(si.xcurrent, (si.dxdt / 3.0), &me);
        (sptr->pe).lcontrol.y = dkma_sub_double_ok(si.ycurrent, (si.dydt / 3.0), &me);
        sptr->normale = (size_t)dkma_double_to_l(floor(si.t));
        
        
#line 1880 "dkfigtoo.ctr"
        if(sptr->normale >= sptr->nbpoints) {
          rm = 1;
        }
        if(me) { rm = 1; }
      } else {
	
	/* rm = 1; */
      }
    }
    if(!suc) {
      null_si(&si);
      si.end  = 1;
      si.t    = dkma_l_to_double(((long)(sptr->nbpoints)) - 1L);
      si.dist = (o->fpd).ahf.decrease;
      si.ox   = (sptr->bpoints)[sptr->nbpoints - 1].value.x;
      si.oy   = (sptr->bpoints)[sptr->nbpoints - 1].value.y;
      me      = 0;
      dist    = distance(
        (sptr->bpoints)[sptr->nbpoints - 2].value.x,
        (sptr->bpoints)[sptr->nbpoints - 1].value.x,
        (sptr->bpoints)[sptr->nbpoints - 2].value.y,
        (sptr->bpoints)[sptr->nbpoints - 1].value.y,
        &me
      );
      si.t    = si.t - dkma_div_double_ok(si.dist, dist, &me);
      
      if(do_iteration(&si)) {
        suc = 1;
        
        sptr->te = si.t;
        (sptr->pe).value.x = si.xcurrent;
        (sptr->pe).value.y = si.ycurrent;
        (sptr->pe).lcontrol.x = dkma_sub_double_ok(si.xcurrent, (si.dxdt / 3.0), &me);
        (sptr->pe).lcontrol.y = dkma_sub_double_ok(si.ycurrent, (si.dydt / 3.0), &me);
        sptr->normale = (size_t)dkma_double_to_l(floor(si.t));
        
        
#line 1917 "dkfigtoo.ctr"
        if(sptr->normale >= sptr->nbpoints) {
          rm = 1;
        }
        if(me) { rm = 1; }
      } else {
        
	rm = 1;
      }
    }
    if(rm || (!suc)) {
      (o->fpd).ar = ((o->fpd).ar & (~1));
      
      /* Warning: forward arrow removed */
      if(c) {
        dkfig_tool2_msg1(c, DK_LOG_LEVEL_WARNING, 51);
      }
    }
  }
  if(((o->fpd).ar) & 2) {	/* backward arrow */
    rm = suc = 0;
    if((sptr->segs > 0) && (sptr->nbpoints > sptr->segs)) {
      null_si(&si);
      si.end  = 2;
      si.t    = 0.0;
      si.dist = (o->fpd).ahb.decrease;
      si.ox   = (sptr->bpoints)[0].value.x;
      si.oy   = (sptr->bpoints)[0].value.y;
      me = 0;
      dist    = distance(
        (sptr->bpoints)[0].value.x,
        (sptr->bpoints)[sptr->segs].value.x,
        (sptr->bpoints)[0].value.y,
        (sptr->bpoints)[sptr->segs].value.y,
        &me
      );
      si.t    = dkma_mul_double_ok(
	dkma_l_to_double((long)(sptr->segs)),
	dkma_div_double_ok(si.dist, dist, &me),
	&me
      );
      
      if(do_iteration(&si)) {
        suc = 1;
	
        sptr->ta = si.t;
        (sptr->pa).value.x = si.xcurrent; (sptr->pa).value.y = si.ycurrent;
        (sptr->pa).rcontrol.x = dkma_add_double_ok(si.xcurrent, (si.dxdt / 3.0), &me);
        (sptr->pa).rcontrol.y = dkma_add_double_ok(si.ycurrent, (si.dydt / 3.0), &me);
        
        
#line 1967 "dkfigtoo.ctr"
        sptr->normals = (size_t)dkma_double_to_l(floor(si.t)) + 1;
        if(me) { rm = 1; }
        if(((o->fpd).ar) & 1) {		
          if(sptr->te <= sptr->ta) {
	    rm = 1;
	  }
        }
      } else {
	
        /* rm = 1; */
      }
    }
    if(!suc) {
      null_si(&si);
      si.end  = 2;
      si.t    = 0.0;
      si.dist = (o->fpd).ahb.decrease;
      si.ox   = (sptr->bpoints)[0].value.x;
      si.oy   = (sptr->bpoints)[0].value.y;
      me      = 0;
      dist    = distance(
        (sptr->bpoints)[0].value.x,
        (sptr->bpoints)[1].value.x,
        (sptr->bpoints)[0].value.y,
        (sptr->bpoints)[1].value.y,
        &me
      );
      si.t    = dkma_div_double_ok(si.dist, dist, &me);
      
      if(do_iteration(&si)) {
        suc = 1;
        
        sptr->ta = si.t;
        (sptr->pa).value.x = si.xcurrent; (sptr->pa).value.y = si.ycurrent;
        (sptr->pa).rcontrol.x = dkma_add_double_ok(si.xcurrent, (si.dxdt / 3.0), &me);
        (sptr->pa).rcontrol.y = dkma_add_double_ok(si.ycurrent, (si.dydt / 3.0), &me);
        
        
#line 2005 "dkfigtoo.ctr"
        sptr->normals = (size_t)dkma_double_to_l(floor(si.t)) + 1;
        if(me) { rm = 1; }
        if(((o->fpd).ar) & 1) {		
          if(sptr->te <= sptr->ta) {
	    rm = 1;
	  }
        }
      } else {
        rm = 1;
        
      }
    }
    if(rm || (!suc)) {
      (o->fpd).ar = ((o->fpd).ar & (~2));
      
      /* Warning: backward arrow removed */
      if(c) {
        dkfig_tool2_msg1(c, DK_LOG_LEVEL_WARNING, 52);
      }
    }
  }
  /* 2004/05/19 end of new code */
  switch(((o->fpd).ar) & 3) {
    case 1: {
      if(!setup_forward_partial(o,d,sptr)) {
        back = 0;
      }
    } break;
    case 2: {
      if(!setup_backward_partial(o,d,sptr)) {
        back = 0;
      }
    } break;
    case 3: {
      if(sptr->normals > sptr->normale) {
        if(!setup_one_partial(o,d,sptr)) {
	  back = 0;
	}
      } else {
        if(!setup_forward_partial(o,d,sptr)) {
          back = 0;
        }
        if(!setup_backward_partial(o,d,sptr)) {
          back = 0;
        }
      }
    } break;
  }
  
  return back;
}



/**	Get the second derivative for a Bezier segment at t=0 (fl=0). The
	intention was t=1 for fl!=0 but this does not work.
	@param	x0	Bezier left end point.
	@param	xp	Bezier left control point.
	@param	xm	Bezier right contol point.
	@param	x1	Bezier right end point.
	@param	fl	Flag (ignored).
	@param	me	Pointer to variable for math error flag.
*/
static double
ddxdtt DK_P6(double,x0, double,xp, double,xm, double,x1, int,fl, int *,me)
{
  double back = 0.0;
  
#if NO_MATH_CHECK
  if(fl) {
    back = xp + x1 - 2.0 * xm;
  } else {
    back = xm + x0 - 2.0 * xp;
  }
  back = 6.0 * back;
#else
  if(fl) {
    back = dkma_sub_double_ok(
      dkma_add_double_ok(xp, x1, me),
      dkma_mul_double_ok(2.0, xm, me),
      me
    );
  } else {
    back = dkma_sub_double_ok(
      dkma_add_double_ok(xm, x0, me),
      dkma_mul_double_ok(2.0, xp, me),
      me
    );
  }
  back = dkma_mul_double_ok(6.0, back, me);
#endif
  
  return back;
}


/**	Final step in spline processing: Shorten spline
	if necessary for arrowheads.
	@param	o	Spline object.
	@param	d	Fig drawing object.
	@param	c	Conversion job structure.
*/
int
dkfig_tool_build_one_spline DK_P3(dk_fig_object *,o, dk_fig_drawing *,d, dk_fig_conversion *,c)
{
  int back = 0;
  int	 matherr = 0;	/* mathematical error */
  size_t noxs;		/* number of bezier segments */
  size_t cxseg;		/* current X-spline segment */
  size_t subsegs;	/* number of bezier segments per X-spline segment */
  size_t lxindex, rxindex, j;	/* X-spline point indices */
  size_t lbindex, rbindex;	/* Bezier point indices */
  double deltat;		/* scale factor for derivations */
  dk_xspline_t xs;	/* X-spline calculation structure */
  dk_fig_spline *sptr;
  
  if(o) {		
  if(o->data) {		
    back = 1; 
    sptr = (dk_fig_spline *)(o->data);
    sptr->ta = 0.0;
    sptr->te = dkma_l_to_double((long)(sptr->nbpoints) - 1L);
    null_bezier_point(&(sptr->pa));
    null_bezier_point(&(sptr->pe));
    null_bezier_point(&(sptr->pa2));
    null_bezier_point(&(sptr->pe2));
    null_all_bezier_points(sptr->bpoints, sptr->nbpoints);
    deltat  = 1.0;
    subsegs = sptr->segs;
    if(subsegs < 1) { subsegs = 1; }
    if(subsegs > 1) {
      deltat = 1.0 / dkma_l_to_double((long)subsegs);
    }
    noxs = sptr->npoints;
    if(!((o->fpd).cl)) { noxs--; }
    for(cxseg = 0; cxseg < noxs; cxseg++) {	/* for all X-spline segments */
      lxindex = cxseg;
      rxindex = lxindex + 1;
      lbindex = lxindex * subsegs;
      rbindex = rxindex * subsegs;
      if(rxindex >= (size_t)(sptr->npoints)) {
        rxindex = rxindex - (size_t)(sptr->npoints);
      }
      if(rbindex >= (size_t)(sptr->nbpoints)) {
        rbindex = rbindex - (size_t)(sptr->nbpoints);
      }
      /* initialize structures */
      dkxsp_reset(&xs);
      if((c->opt2) & DKFIG_OPT_CORRECT_OPEN_SPLINES) {
        xs.docor = 1;	
      } else {
        xs.docor = 0;	
      }
      dkxsp_set_pos(&xs, cxseg, sptr->npoints, (o->fpd).cl);
      /* set A */
      if((cxseg > 0) || (o->fpd).cl) {
        if(cxseg > 0) { j = cxseg - 1; }
	else { j = sptr->npoints - 1; }
        dkxsp_setA(
	  &xs, (sptr->svalues)[j],
	  dkma_l_to_double((sptr->xvalues)[j]),
	  dkma_l_to_double((sptr->yvalues)[j])
	);
      }
      /* set B */
      dkxsp_setB(
        &xs, (sptr->svalues)[cxseg],
	dkma_l_to_double((sptr->xvalues)[cxseg]),
	dkma_l_to_double((sptr->yvalues)[cxseg])
      );
      /* set C */
      j = cxseg + 1;
      if((j < (size_t)(sptr->npoints)) || (o->fpd).cl) {
        if(j >= (size_t)(sptr->npoints)) { j = j - (size_t)(sptr->npoints); }
	dkxsp_setC(
	  &xs, (sptr->svalues)[j],
	  dkma_l_to_double((sptr->xvalues)[j]),
	  dkma_l_to_double((sptr->yvalues)[j])
	);
      }
      /* set D */
      j = cxseg + 2;
      if((j < (size_t)(sptr->npoints)) || (o->fpd).cl) {
        if(j >= (size_t)(sptr->npoints)) { j = j - (size_t)(sptr->npoints); }
	dkxsp_setD(
	  &xs, (sptr->svalues)[j],
	  dkma_l_to_double((sptr->xvalues)[j]),
	  dkma_l_to_double((sptr->yvalues)[j])
	);
      }
      /* prepare calculation */
      dkxsp_step1(&xs);
      /* calculate "left" point */
      if(dkxsp_step2(&xs, 0.0)) {
        ((sptr->bpoints)[lbindex]).value.x = xs.x;
	((sptr->bpoints)[lbindex]).value.y = xs.y;
	((sptr->bpoints)[lbindex]).rcontrol.x
	= dkma_add_double_ok(xs.x, (deltat * xs.ddtx / 3.0), &matherr);
	((sptr->bpoints)[lbindex]).rcontrol.y
	= dkma_add_double_ok(xs.y, (deltat * xs.ddty / 3.0), &matherr);
	
	
      } else {
        matherr = 1;
      }
      /* calculate "right" point */
      if(dkxsp_step2(&xs, 1.0)) {
        ((sptr->bpoints)[rbindex]).value.x = xs.x;
	((sptr->bpoints)[rbindex]).value.y = xs.y;
	((sptr->bpoints)[rbindex]).lcontrol.x
	= dkma_sub_double_ok(xs.x, (deltat * xs.ddtx / 3.0), &matherr);
	((sptr->bpoints)[rbindex]).lcontrol.y
	= dkma_sub_double_ok(xs.y, (deltat * xs.ddty / 3.0), &matherr);
	
	
      } else {
        matherr = 1;
      }
      /* caluculate intermediate points */
      for(j = 1; j < subsegs; j++) {
        if(dkxsp_step2(&xs, (deltat*dkma_l_to_double((long)j)))) {
	  ((sptr->bpoints)[lbindex+j]).value.x = xs.x;
	  ((sptr->bpoints)[lbindex+j]).value.y = xs.y;
	  ((sptr->bpoints)[lbindex+j]).lcontrol.x
	  = dkma_sub_double_ok(xs.x, (deltat * xs.ddtx / 3.0), &matherr);
	  ((sptr->bpoints)[lbindex+j]).lcontrol.y
	  = dkma_sub_double_ok(xs.y, (deltat * xs.ddty / 3.0), &matherr);
	  ((sptr->bpoints)[lbindex+j]).rcontrol.x
	  = dkma_add_double_ok(xs.x, (deltat * xs.ddtx / 3.0), &matherr);
	  ((sptr->bpoints)[lbindex+j]).rcontrol.y
	  = dkma_add_double_ok(xs.y, (deltat * xs.ddty / 3.0), &matherr);
	  
	  
	  
	} else {
	  matherr = 1;
	}
      }
    }
    if((!((o->fpd).cl)) && ((sptr->nbpoints) >= 2)) {
      double phi, deltax, deltay;
      if(((o->fpd).ar) & 1) {
        
	deltay = ((sptr->bpoints)[sptr->nbpoints - 1]).value.y
	         - ((sptr->bpoints)[sptr->nbpoints - 1]).lcontrol.y;
        deltax = ((sptr->bpoints)[sptr->nbpoints - 1]).value.x
	         - ((sptr->bpoints)[sptr->nbpoints - 1]).lcontrol.x;

        phi = dkma_atan2(deltay, deltax);
	
	if((fabs(deltay) < DKFIG_EPSILON) && (fabs(deltax) < DKFIG_EPSILON)) {
	  /*
	  deltay = ddxdtt(
	    ((sptr->bpoints)[sptr->nbpoints - 2]).value.y,
	    ((sptr->bpoints)[sptr->nbpoints - 2]).rcontrol.y,
	    ((sptr->bpoints)[sptr->nbpoints - 1]).lcontrol.y,
	    ((sptr->bpoints)[sptr->nbpoints - 1]).value.y,
	    1,
	    &matherr
	  );
	  deltax = ddxdtt(
	    ((sptr->bpoints)[sptr->nbpoints - 2]).value.x,
	    ((sptr->bpoints)[sptr->nbpoints - 2]).rcontrol.x,
	    ((sptr->bpoints)[sptr->nbpoints - 1]).lcontrol.x,
	    ((sptr->bpoints)[sptr->nbpoints - 1]).value.x,
	    1,
	    &matherr
	  );
	  */
	  deltay = ddxdtt(
	    ((sptr->bpoints)[sptr->nbpoints - 1]).value.y,
	    ((sptr->bpoints)[sptr->nbpoints - 1]).lcontrol.y,
	    ((sptr->bpoints)[sptr->nbpoints - 2]).rcontrol.y,
	    ((sptr->bpoints)[sptr->nbpoints - 2]).value.y,
	    0,
	    &matherr
	  ); deltay = 0.0 - deltay;
	  deltax = ddxdtt(
	    ((sptr->bpoints)[sptr->nbpoints - 1]).value.x,
	    ((sptr->bpoints)[sptr->nbpoints - 1]).lcontrol.x,
	    ((sptr->bpoints)[sptr->nbpoints - 2]).rcontrol.x,
	    ((sptr->bpoints)[sptr->nbpoints - 2]).value.x,
	    0,
	    &matherr
	  ); deltax = 0.0 - deltax;
	  phi = dkma_atan2(deltay, deltax);
	  
	}
	if(dkfig_tool_invert_y(d)) {
	  phi = 0.0 - phi;
	}
	if(!dkfig_tool_calc_arrow(
	  (&(o->fpd).ahf), &(((sptr->bpoints)[sptr->nbpoints - 1]).value),
	  phi, &(o->fpd), d, c
	)
	)
	{
	  back = 0;
	}
      }
      if(((o->fpd).ar) & 2) {
        
	deltay = ((sptr->bpoints)[0]).value.y 
	         - ((sptr->bpoints)[0]).rcontrol.y;
	deltax = ((sptr->bpoints)[0]).value.x 
	         - ((sptr->bpoints)[0]).rcontrol.x;
        phi = dkma_atan2(deltay, deltax);
	
	if((fabs(deltay) < DKFIG_EPSILON) && (fabs(deltax) < DKFIG_EPSILON)) {
	  deltay = ddxdtt(
	    ((sptr->bpoints)[0]).value.y,
	    ((sptr->bpoints)[0]).rcontrol.y,
	    ((sptr->bpoints)[1]).lcontrol.y,
	    ((sptr->bpoints)[1]).value.y,
	    0,
	    &matherr
	  );
	  deltax = ddxdtt(
	    ((sptr->bpoints)[0]).value.x,
	    ((sptr->bpoints)[0]).rcontrol.x,
	    ((sptr->bpoints)[1]).lcontrol.x,
	    ((sptr->bpoints)[1]).value.x,
	    0,
	    &matherr
	  );
	  phi = dkma_atan2(deltay, deltax);
	  
	}
	if(dkfig_tool_invert_y(d)) {
	  phi = 0.0 - phi;
	}
	phi = phi + M_PI;
	if(phi > (2.0 * M_PI)) {
	  phi = phi - 2.0 * M_PI;
	}
	if(!dkfig_tool_calc_arrow(
	  (&(o->fpd).ahb), &(((sptr->bpoints)[0]).value),
	  phi, &(o->fpd), d, c
	)
	)
	{
	  back = 0;
	}
      }
    }
    if((o->fpd).ar & 3) {
    if(!shorten_spline_for_arrowheads(o,d,sptr,c)) {
      back = 0;
    }
    }
  }
  }
  if(matherr) {
    back = 0;		
  }
  
  return back;
}



/**	Initialize arc calculation structure.
	@param	c	Arc calculation structure.
*/
void
dkfig_tool_null_arc_calc DK_P1(dk_fig_arc_calc *,c)
{
  if(c) {
    DK_MEMRES(c,sizeof(dk_fig_arc_calc));
    c->xa = c->ya = c->xb = c->yb = c->xc = c->yc = 0.0;
    c->xm = c->ym = c->ra = 0.0;
    c->aa = c->ab = c->ac = 0.0;
    c->xleft = c->xright = c->ybottom = c->ytop = 0.0;
    c->astart = c->alength = 0.0;
    c->revert = 0; c->mathok = 0;
  }
}



/**	Invert the y values of the points.
	@param	c	Arc calculation structure.
*/
void
dkfig_tool_invert_arc_calc DK_P1(dk_fig_arc_calc *,c)
{
  if(c) {
    c->ya = 0.0 - c->ya;
    c->yb = 0.0 - c->yb;
    c->yc = 0.0 - c->yc;
    c->ym = 0.0 - c->ym;
    c->ybottom = 0.0 - c->ybottom;
    c->ytop = 0.0 - c->ytop;
  }
}



/**	Swap arrowheads on an arc.
	MetaPost requires to draw arcs in positive
	(counterclockwise) direction. If an arc is specified
	in clockwise direction to use
	"fill arrowhead p withcolor ...".
	@param	fpd	Fill, pattern and draw structure.
*/
void
dkfig_tool_swap_arrows DK_P1(dk_fig_fpd *,fpd)
{
  dk_fig_arrow arrow;
  int newar;
  if(fpd) {
    if((fpd->ar) & 3) {
      newar = 0;
      if((fpd->ar) & 1) { newar |= 2; }
      if((fpd->ar) & 2) { newar |= 1; }
      DK_MEMCPY(&arrow, &(fpd->ahf), sizeof(dk_fig_arrow));
      DK_MEMCPY(&(fpd->ahf), &(fpd->ahb), sizeof(dk_fig_arrow));
      DK_MEMCPY(&(fpd->ahb), &arrow, sizeof(dk_fig_arrow));
      fpd->ar = newar;
    }
  }
}



/**	Final processing step on arcs: Shorten arc for arrowheads
	if necessary.
	@param	o	Arc object.
	@param	d	Fig drawing structure.
	@param	c	Conversion job structure.
	@return	1 on success, 0 on error.
*/
int
dkfig_tool_arc_complete DK_P3(dk_fig_object *,o, dk_fig_drawing *,d, dk_fig_conversion *,c)
{
  int back = 0;
  int me   = 0;
  int rm   = 0;
  dk_fig_arc *a;
  double buf, v;
  dk_fig_point pnt;
  
  if(o && d) {
    a = (dk_fig_arc *)(o->data);
    if(a) {
      a->lba = a->rba = 0.0;
      (a->calc).xa = dkma_l_to_double(a->x1);
      (a->calc).ya = dkma_l_to_double(a->y1);
      (a->calc).xb = dkma_l_to_double(a->x2);
      (a->calc).yb = dkma_l_to_double(a->y2);
      (a->calc).xc = dkma_l_to_double(a->x3);
      (a->calc).yc = dkma_l_to_double(a->y3);
      if(dkfig_tool_invert_y(d)) {	
        dkfig_tool_invert_arc_calc(&(a->calc));
      }
      dkfig_tool_arc_calc(&(a->calc));
      if(dkfig_tool_invert_y(d)) {	
        dkfig_tool_invert_arc_calc(&(a->calc));
      }
      if((a->calc).revert) {		
        dkfig_tool_swap_arrows(&(o->fpd));
	buf = (a->calc).xa; (a->calc).xa = (a->calc).xc; (a->calc).xc = buf;
	buf = (a->calc).ya; (a->calc).ya = (a->calc).yc; (a->calc).yc = buf;
	buf = (a->calc).aa; (a->calc).aa = (a->calc).ac; (a->calc).ac = buf;
      }
      if(!((a->calc).mathok)) {		
        back = 1;
	pnt.x = (a->calc).xc; pnt.y = (a->calc).yc;
	if(((o->fpd).ar) & 1) {
if(dkfig_tool_calc_arrow(&((o->fpd).ahf),&pnt,((a->calc).ac + M_PI_2),&(o->fpd),d,c)) {
          rm = 0;
          v = dkma_sub_double_ok(
	    1.0,
	    dkma_div_double_ok(
	      dkma_mul_double_ok((o->fpd).ahf.decrease,(o->fpd).ahf.decrease,&rm),
	      dkma_mul_double_ok(
	        2.0,
		dkma_mul_double_ok((a->calc).ra,(a->calc).ra,&rm),
		&rm
	      ),
	      &rm
	    ),
	    &rm
	  );
	  if(fabs(v) <= 1.0) {
	    a->rba = acos(v);
	    a->rba = fabs(a->rba);
	  } else {
	    rm = 1;
	  }
	  if(rm) {
            (o->fpd).ar = ((o->fpd).ar & (~1));
	    /* WARNING: FORWARD ARROWHEAD REMOVED */
	    if(c) {
	      dkfig_tool2_msg1(c, DK_LOG_LEVEL_WARNING, 51);
	    }
	  }
} else {
	  back = 0;
}
	}
	pnt.x = (a->calc).xa; pnt.y = (a->calc).ya;
	if(((o->fpd).ar) & 2) {
if(dkfig_tool_calc_arrow(&((o->fpd).ahb),&pnt,((a->calc).aa - M_PI_2),&(o->fpd),d,c)) {
          rm = 0;
          v = dkma_sub_double_ok(
	    1.0,
	    dkma_div_double_ok(
	      dkma_mul_double_ok((o->fpd).ahb.decrease,(o->fpd).ahb.decrease,&rm),
	      dkma_mul_double_ok(
	        2.0,
		dkma_mul_double_ok((a->calc).ra,(a->calc).ra,&rm),
		&rm
	      ),
	      &rm
	    ),
	    &rm
	  );
	  if(fabs(v) <= 1.0) {
	    a->lba = acos(v);
	    a->lba = fabs(a->lba);
	  } else {
	    rm = 1;
	  }
	  if(rm) {
            (o->fpd).ar = ((o->fpd).ar & (~2));
	    /* WARNING: ARROWHEAD BACKWARD REMOVED */
	    if(c) {
	      dkfig_tool2_msg1(c, DK_LOG_LEVEL_WARNING, 52);
	    }
	  }
} else {
	  back = 0;
}
        }
      }
    }
  }
  if(me) { back = 0; }
  
  return back;
}



/**	Final processing step on polylines: Shorten line for
	arrowheads if necessary.
	@param	o	Polyline object.
	@param	d	Fig drawing structure.
	@param	c	Conversion job structure.
	@return	1 on success, 0 on error.
*/
int
dkfig_tool_polyline_complete DK_P3(dk_fig_object *,o, dk_fig_drawing *,d, dk_fig_conversion *,c)
{
  int back = 0;
  int matherr = 0;
  int rm = 0;
  double phi = 0.0;
  double seglength;
  dk_fig_polyline *p;
  dk_fig_point pnt;
  
  if(o && d) {
    p = (dk_fig_polyline *)(o->data);
    if(p) {
      back = 1;
      null_point(&(p->pa));
      null_point(&(p->pe));
      if((!((o->fpd).cl)) && ((p->npoints) >= 2)) {
        if((p->xvalues) && (p->yvalues)) {
	  if(((o->fpd).ar) & 1) {		
	    pnt.x = dkma_l_to_double((p->xvalues)[p->npoints - 1]);
	    pnt.y = dkma_l_to_double((p->yvalues)[p->npoints - 1]);
	    phi = dkma_atan2(
	      dkma_sub_double_ok(
	        dkma_l_to_double((p->yvalues)[p->npoints - 1]),
		dkma_l_to_double((p->yvalues)[p->npoints - 2]),
		&matherr
	      ),
	      dkma_sub_double_ok(
	        dkma_l_to_double((p->xvalues)[p->npoints - 1]),
		dkma_l_to_double((p->xvalues)[p->npoints - 2]),
		&matherr
	      )
	    );
	    if(dkfig_tool_invert_y(d)) {
	      phi = 0.0 - phi;
	    }	
	    if(dkfig_tool_calc_arrow(&((o->fpd).ahf),&pnt,phi,&(o->fpd),d,c))
	    {
	      rm = 0;
	      seglength = distance(
	        dkma_l_to_double((p->xvalues)[p->npoints - 2]),
		dkma_l_to_double((p->xvalues)[p->npoints - 1]),
		dkma_l_to_double((p->yvalues)[p->npoints - 2]),
		dkma_l_to_double((p->yvalues)[p->npoints - 1]),
	        &matherr
	      );
	      (p->pe).x = dkma_l_to_double((p->xvalues)[p->npoints - 1]);
	      (p->pe).y = dkma_l_to_double((p->yvalues)[p->npoints - 1]);
	      if(seglength >= (o->fpd).ahf.decrease) {
	        (p->pe).x = dkma_add_double_ok(
		  dkma_l_to_double((p->xvalues)[p->npoints - 2]),
		  dkma_mul_double_ok(
		    dkma_sub_double_ok(
		      dkma_l_to_double((p->xvalues)[p->npoints - 1]),
		      dkma_l_to_double((p->xvalues)[p->npoints - 2]),
		      &matherr
		    ),
		    dkma_sub_double_ok(
		      1.0,
		      dkma_div_double_ok(
		        (o->fpd).ahf.decrease,
			seglength,
			&matherr
		      ),
		      &matherr
		    ),
		    &matherr
		  ),
		  &matherr
		);
		(p->pe).y = dkma_add_double_ok(
		  dkma_l_to_double((p->yvalues)[p->npoints - 2]),
		  dkma_mul_double_ok(
		    dkma_sub_double_ok(
		      dkma_l_to_double((p->yvalues)[p->npoints - 1]),
		      dkma_l_to_double((p->yvalues)[p->npoints - 2]),
		      &matherr
		    ),
		    dkma_sub_double_ok(
		      1.0,
		      dkma_div_double_ok(
		        (o->fpd).ahf.decrease,
			seglength,
			&matherr
		      ),
		      &matherr
		    ),
		    &matherr
		  ),
		  &matherr
		);
		
		
		
	      } else {
	        rm = 1;
	      }
	      if(rm) {
                (o->fpd).ar = ((o->fpd).ar & (~1));
		/* WARNING: ARROWHEAD FORWARD REMOVED */
		if(c) {
		  dkfig_tool2_msg1(c, DK_LOG_LEVEL_WARNING, 51);
		}
	      }
	    }
	    else
	    {
	      back = 0;
	    }
	  }
	  if(((o->fpd).ar) & 2) {		
	    pnt.x = dkma_l_to_double((p->xvalues)[0]);
	    pnt.y = dkma_l_to_double((p->yvalues)[0]);
	    phi = dkma_atan2(
	      dkma_sub_double_ok(
	        dkma_l_to_double((p->yvalues)[0]),
		dkma_l_to_double((p->yvalues)[1]),
		&matherr
	      ),
	      dkma_sub_double_ok(
	        dkma_l_to_double((p->xvalues)[0]),
		dkma_l_to_double((p->xvalues)[1]),
		&matherr
	      )
	    );
	    if(dkfig_tool_invert_y(d)) {
	      phi = 0.0 - phi;
	    }	
	    if(dkfig_tool_calc_arrow(&((o->fpd).ahb),&pnt,phi,&(o->fpd),d,c))
	    {
	      rm = 0;
	      seglength = distance(
	        dkma_l_to_double((p->xvalues)[0]),
		dkma_l_to_double((p->xvalues)[1]),
		dkma_l_to_double((p->yvalues)[0]),
		dkma_l_to_double((p->yvalues)[1]),
	        &matherr
	      );
	      (p->pa).x = dkma_l_to_double((p->xvalues)[0]);
	      (p->pa).y = dkma_l_to_double((p->yvalues)[0]);
	      if(seglength > (o->fpd).ahb.decrease) {
	        (p->pa).x = dkma_add_double_ok(
		   dkma_l_to_double((p->xvalues)[0]),
		   dkma_mul_double_ok(
		     dkma_sub_double_ok(
		       dkma_l_to_double((p->xvalues)[1]),
		       dkma_l_to_double((p->xvalues)[0]),
		       &matherr
		     ),
		     dkma_div_double_ok(
		       (o->fpd).ahb.decrease,
		       seglength,
		       &matherr
		     ),
		     &matherr
		   ),
		  &matherr
		);
	        (p->pa).y = dkma_add_double_ok(
		   dkma_l_to_double((p->yvalues)[0]),
		   dkma_mul_double_ok(
		     dkma_sub_double_ok(
		       dkma_l_to_double((p->yvalues)[1]),
		       dkma_l_to_double((p->yvalues)[0]),
		       &matherr
		     ),
		     dkma_div_double_ok(
		       (o->fpd).ahb.decrease,
		       seglength,
		       &matherr
		     ),
		     &matherr
		   ),
		  &matherr
		);
		
		
		
	      } else {
	        rm = 1;
	      }
	      if(rm) {
                (o->fpd).ar = ((o->fpd).ar & (~2));
		/* WARNING: ARROWHEAD BACKWARD REMOVED */
		if(c) {
		  dkfig_tool2_msg1(c, DK_LOG_LEVEL_WARNING, 52);
		}
	      }
	    }
	    else
	    {
	      back = 0;
	    }
	  }
	} else {
	  back = 0;	
	}
      }
    }
  }
  if(matherr) { back = 0; }
  
  return back;
}



/**	Fill color cell structure by retrieving data from
	Fig drawing color cell.
	@param	d	Fig drawing structure.
	@param	dcc	Destination color cell.
	@param	n	Color cell number.
*/
void
dkfig_tool_fill_dcc DK_P3(dk_fig_drawing *,d, dk_fig_dcc *,dcc, int,n)
{
  dk_fig_colorcell *cc;
  if(dcc) {
    dcc->red = dcc->green = dcc->blue = 0.0;
    dcc->ired = dcc->igreen = dcc->iblue = 0;
  }
  if(d && dcc) {
    if(d->ccit) {
      cc = (dk_fig_colorcell *)dksto_it_find_like(d->ccit, &n, 1);
      if(cc) {
        dcc->red    = dkma_l_to_double(((long)(cc->r)) & 255L) / 255.0;
        dcc->green  = dkma_l_to_double(((long)(cc->g)) & 255L) / 255.0;
        dcc->blue   = dkma_l_to_double(((long)(cc->b)) & 255L) / 255.0;
	dcc->ired   = (int)((cc->r) & 255L);
	dcc->igreen = (int)((cc->g) & 255L);
	dcc->iblue  = (int)((cc->b) & 255L);
      }
    }
  }
}



/**	Correct a color cell structure for an object's
	area fill style (brightness, patterns...)
	@param	dcc	Color cell.
	@param	colno	Color number.
	@param	af	Object's area fill style.
*/
void
dkfig_tool_correct_dcc DK_P3(dk_fig_dcc *,dcc, int,colno, int,af)
{
  double r, g, b, d;
  if(dcc) {
    r = dcc->red; g = dcc->green; b = dcc->blue;
    if(colno >= 1) {
      if(af > 0) {
        if(af <= 19) {
          d = dkma_l_to_double((long)af);
	  dcc->red   = (d * r)/20.0;
	  dcc->green = (d * g)/20.0;
	  dcc->blue  = (d * b)/20.0;
        } else {
          if(af > 20) {
	    if(af < 40) {
	      d =  dkma_l_to_double((long)af) - 20.0;
	      dcc->red   = r + ((1.0 - r) * d)/20.0;
	      dcc->green = g + ((1.0 - g) * d)/20.0;
	      dcc->blue  = b + ((1.0 - b) * d)/20.0;
	    } else {
	      if(af == 40) {
	        dcc->red = dcc->green = dcc->blue = 1.0;
	      }
	    }
	  }
        }
      } else {
        dcc->red = dcc->green = dcc->blue = 0.0;
      }
    } else {
      if((af>= 0) && (af <= 19)) {
        d = dkma_l_to_double((long)af);
	dcc->red = dcc->green = dcc->blue = 1.0 - d/20.0;
      } else {
        dcc->red = dcc->green = dcc->blue = 0.0;
      }
    }
    if(dcc->red > 1.0) dcc->red = 1.0;
    if(dcc->red < 0.0) dcc->red = 0.0;
    if(dcc->green > 1.0) dcc->green = 1.0;
    if(dcc->green < 0.0) dcc->green = 0.0;
    if(dcc->blue > 1.0) dcc->blue = 1.0;
    if(dcc->blue < 0.0) dcc->blue = 0.0;
    dcc->ired   = (int)dkma_double_to_l(255.0 * dcc->red);
    dcc->igreen = (int)dkma_double_to_l(255.0 * dcc->green);
    dcc->iblue  = (int)dkma_double_to_l(255.0 * dcc->blue);
  }
}



/**	Check whether an object must be filled.
	@param	area_fill	Object's area fill style.
	@param	opt		Object options, checked for DKFIG_OPT_FILL_PATTERNS.
	@return	Test result (1=must fill, 0=no fill).
*/
int
dkfig_tool_must_fill DK_P2(int, area_fill, unsigned long,opt)
{
  int back = 0;
  
  if(area_fill >= 0) {
    if((area_fill < 41) || (area_fill > 56)) {
      back = 1;
    } else {
      if((area_fill >= 41) && (area_fill <= 62)) {
        if(!(opt & DKFIG_OPT_FILL_PATTERNS)) {
	  back = 1;
	}
      }
    }
  }
  
  return back;
}



/**	Check whether or not we need to draw fill patterns.
	@param	area_fill	Object's area fill style.
	@param	opt		Object options, checked for DKFIG_OPT_FILL_PATTERNS.
	@return	Test result (1=must pattern fill, 0=no fill).
*/
int
dkfig_tool_must_pattern DK_P2(int, area_fill, unsigned long,opt)
{
  int back = 0;
  
  if((area_fill >= 41) && (area_fill <= 62)) {
    if(opt & DKFIG_OPT_FILL_PATTERNS) {
      back = 1;
    }
  } 
  return back;
}




/**	Write number encoded as string.
	@param	os	Output stream to write to.
	@param	no	Number value.
	@param	lgt	String length.
	@return	1 on success, 0 on errors.
*/
int
dkfig_tool_num_as_string DK_P3(dk_stream_t *,os, unsigned long,no, size_t,lgt)
{
  int back = 0;
  char buffer[128];
  unsigned long num, rest; size_t i, r;
  
  if((os) && lgt) {
    if((lgt < sizeof(buffer)) && (lgt > 0)) {
      back = 1;
      DK_MEMRES(buffer,sizeof(buffer)) ;
      num = no;
      for(i = 0; i < lgt; i++) {	
        rest = num % 26UL;		
	num  = num / 26UL;		
	r    = (size_t)rest;		
	buffer[lgt - 1 - i] = alphabet[r];
      }
      buffer[lgt] = '\0';
      back = dkstream_puts(os, buffer);
    }
  } 
  return back;
}



/**	Remove temporary files used for special text processing.
	@param	c	Conversion job structure.
*/
void
dkfig_tool_delete_tex_files DK_P1(dk_fig_conversion *,c)
{
  if(c) {
    if(c->texn) {
      dksf_remove_file(c->texn);
    }
    if(c->dvin) {
      dksf_remove_file(c->dvin);
    }
    if(c->psn) {
      dksf_remove_file(c->psn);
    }
    if(c->logn) {
      dksf_remove_file(c->logn);
    }
    if(c->auxn) {
      dksf_remove_file(c->auxn);
    }
  }
}



/**	Initialize NetPBM library.
	@param	c	Conversion job structure.
*/
static char program_name[] = { DKFIG_PROGRAM_NAME };
void
dkfig_tool_init_netpbm DK_P1(dk_fig_conversion *,c)
{
#if DK_HAVE_PNM_H || DK_HAVE_NETPBM_PNM_H
  int argc; char *argv[2];
  
  if(!((c->opt1) & DKFIG_OPT_NETPBM_INITIALIZED)) {
    
    c->opt1 |= DKFIG_OPT_NETPBM_INITIALIZED;
    argc = 1; argv[0] = program_name; argv[1] = NULL;
    pnm_init(&argc, argv);
  }
  
#endif
}



