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