%% options copyright owner = Dirk Krause copyright year = 2018-xxxx SPDX-License-Identifier: BSD-3-Clause %% header #ifdef __cplusplus extern "C" { #endif /** Calculate offset and cut for one arrowhead. @param parrow Arrow to calculate. @param pobj Object the arrow belongs to. @param pdrw Drawing structure. @param pjob Job structure. @return 1 on success, 0 on error. */ int wxd2lah_one_arrowhead( wxd_arrow_t *parrow, wxd_object_t *pobj, wxd_drawing_t *pdrw, wxd2lat_job_t *pjob ); /** Calculate arrowhead data. @param drw Drawing to produce output for. @param job Job structure, probably modified. @param fn Input file name @return 1 on success, 0 on error. */ int wxd2lah_calculate_arrowheads( wxd_drawing_t *drw, wxd2lat_job_t *job ); /** Draw one arrowhead for object. @param arrow Arrowhead structure. @param drw Drawing structure. @param job Job structure. @param obj Object arrow belongs to. @param isbck Flag: Is a backward arrow. @param backptr Address of success variable to reset on error. @param erp Error report, may be NULL. */ void wxd2lah_arrowhead( wxd_arrow_t *arrow, wxd_drawing_t *drw, wxd2lat_job_t *job, wxd_object_t *pobj, int isbck, int *backptr, dk4_er_t *erp ); #ifdef __cplusplus } #endif %% module #ifndef WXD2LAT_H_INCLUDED #include "wxd2lat.h" #endif $!trace-include /** Calculate arrowhead segment on arc. @param seg Segment to fill. @param rs Radius at start. @param re Radius at end. @param as Angle alpha at start. @param ae Angle alpha at end. @param xc Center point x. @param yc Center point y. */ static void wxd2lah_arc_arrow_segment( arc_ah_seg_t *seg, double rs, double re, double as, double ae, double xc, double yc ) { double kappa; double v; kappa = dk4gratool_kappa_for_angle(fabs(ae - as)); seg->p[0].x = xc + rs * cos(as); seg->p[0].y = yc + rs * sin(as); seg->p[3].x = xc + re * cos(ae); seg->p[3].y = yc + re * sin(ae); v = (re-rs)*cos(as)-(ae-as)*rs*sin(as); seg->p[1].x = seg->p[0].x + kappa * v; v = (re-rs)*sin(as)+(ae-as)*rs*cos(as); seg->p[1].y = seg->p[0].y + kappa * v; v = (re-rs)*cos(ae)-(ae-as)*re*sin(ae); seg->p[2].x = seg->p[3].x - kappa * v; v = (re-rs)*sin(ae)+(ae-as)*re*cos(ae); seg->p[2].y = seg->p[3].y - kappa * v; } /** Calculate square of a value. @param x Side length. @return Square area. */ static double wxd2lah_square(double x) { return (x * x); } /** Calculate B-spline through 3 x values for t values -1, 0 and 1. @param p1 Address of variable for dx/dt at t=-1 (output). @param p2 Address of variable for dx/dt at t=0 (output). @param p3 Address of variable for dx/dt at t=1 (output). @param xu X value at t=-1 (input). @param xv X value at t=0 (input). @param xw X value at t=1 (input). */ static void wxd2lah_b_spline_derivatives( double *p1, double *p2, double *p3, double xu, double xv, double xw ) { *p1 = 2.0 * xv + (xw - xu) / 2.0 - xw - xu; *p2 = (xw - xu) / 2.0; *p3 = xw + xu + (xw - xu) / 2.0 - 2.0 * xv; } /** Calculate derivatives values for set of 3 points. @param pd Destination array, derivatives are stored here. @param ps Source array containing the original points. */ static void wxd2lah_sp_ah_b_spline_derivatives( dk4_gra_point_t *pd, dk4_gra_point_t *ps ) { wxd2lah_b_spline_derivatives( &(pd[0].x), &(pd[1].x), &(pd[2].x), ps[0].x, ps[1].x, ps[2].x ); wxd2lah_b_spline_derivatives( &(pd[0].y), &(pd[1].y), &(pd[2].y), ps[0].y, ps[1].y, ps[2].y ); } /** Calculate point index for B-spline drawing. @param i_start Start point index in point array. @param npoints Number of points in spline. @param backward Flag: Draw backwards. @param i Index within spline. @return Calculated index in array. */ static size_t wxd2lah_calculate_point_index( size_t i_start, size_t npoints, int backward, size_t i ) { size_t back = 0; if (0 != backward) { back = i_start + npoints - 1 - i; } else { back = i_start + i; } return back; } /** Create B-spline path segment. @param arrow Arrowhead structure. @param job Job structure. @param pobj Object arrow belongs to. @param s Spline structure to use. @param i_start Index of first point. @param npoints Number of points. @param backward Flag: Draw backwards. @param mvto Flag: Use moveto at start. @param backptr Address of success variable to reset on error. @param erp Error report, may be NULL. */ static void wxd2lah_sp_ah_bspline( wxd2lat_job_t *job, sp_ah_t *s, size_t i_start, size_t npoints, int backward, int mvto, int *backptr, dk4_er_t *erp ) { dk4_gra_point_t pd[4]; dk4_gra_point_t ps[4]; double v0[4]; /* Previous point: x, y, dx/dt, dy/dt */ double v1[4]; /* Current segment end point: x, y, dx/dt, dy/dt */ #if 0 size_t ind; #endif size_t i; size_t iu; size_t iv; size_t iw; $? "+ wxd2lah_sp_ah_bspline" #if 0 $? ". polyline test implementation" for (i = 0; i < npoints; i++) { ind = wxd2lah_calculate_point_index(i_start, npoints, backward, i); if ((0 == i) && (0 != mvto)) { dk4pppt_newpath_moveto( job->ppp, (s->ppoints)[ind].x, (s->ppoints)[ind].y, NULL, backptr, erp ); } if (0 < i) { dk4pppt_lineto( job->ppp, (s->ppoints)[ind].x, (s->ppoints)[ind].y, NULL, backptr, erp ); } } #else $? ". real implementation (empty at this time)" iu = wxd2lah_calculate_point_index(i_start, npoints, backward, 0); iv = wxd2lah_calculate_point_index(i_start, npoints, backward, 1); iw = wxd2lah_calculate_point_index(i_start, npoints, backward, 2); ps[0].x = (s->ppoints)[iu].x; ps[0].y = (s->ppoints)[iu].y; ps[1].x = (s->ppoints)[iv].x; ps[1].y = (s->ppoints)[iv].y; ps[2].x = (s->ppoints)[iw].x; ps[2].y = (s->ppoints)[iw].y; wxd2lah_sp_ah_b_spline_derivatives(pd, ps); v0[0] = (s->ppoints)[iu].x; v0[1] = (s->ppoints)[iu].y; v0[2] = pd[0].x / 3.0; v0[3] = pd[0].y / 3.0; if (0 != mvto) { dk4pppt_newpath_moveto(job->ppp, v0[0], v0[1], NULL, backptr, erp); } for (i = 1; i < npoints; i++) { /* i is the index of the point at segment end */ if ((npoints - 1) == i) { iw = npoints - 1; iv = npoints - 2; iu = npoints - 3; } else { iu = i - 1; iv = i; iw = i + 1; } iu = wxd2lah_calculate_point_index(i_start, npoints, backward, iu); iv = wxd2lah_calculate_point_index(i_start, npoints, backward, iv); iw = wxd2lah_calculate_point_index(i_start, npoints, backward, iw); ps[0].x = (s->ppoints)[iu].x; ps[0].y = (s->ppoints)[iu].y; ps[1].x = (s->ppoints)[iv].x; ps[1].y = (s->ppoints)[iv].y; ps[2].x = (s->ppoints)[iw].x; ps[2].y = (s->ppoints)[iw].y; wxd2lah_sp_ah_b_spline_derivatives(pd, ps); if ((npoints - 1) == i) { v1[0] = (s->ppoints)[iw].x; v1[1] = (s->ppoints)[iw].y; v1[2] = pd[2].x / 3.0; v1[3] = pd[2].y / 3.0; } else { v1[0] = (s->ppoints)[iv].x; v1[1] = (s->ppoints)[iv].y; v1[2] = pd[1].x / 3.0; v1[3] = pd[1].y / 3.0; } dk4pppt_curveto( job->ppp, (v0[0] + v0[2]), (v0[1] + v0[3]), (v1[0] - v1[2]), (v1[1] - v1[3]), v1[0], v1[1], NULL, backptr, erp ); DK4_MEMCPY(v0,v1,sizeof(v0)); } #endif $? "- wxd2lah_sp_ah_bspline" } /** Calculate length of a sub interval. @param xstart Start position of interval. @param xend End position of interval. @param i Number of segments contained in subinterval. @param segments Number of segments used for interval. @return Length of the subinterval. */ static double wxd2lah_partial_length( double xstart, double xend, size_t i, size_t segments ) { double back; back = xstart + ((xend - xstart) * (double)i)/((double)segments); return back; } /** Check whether arrow length and width is large enough (not 0). @param parrow Arrowhead to check. @param pobj Object arrowhead is attached to. @param pdrw Drawing containing the object. @param pjob Job structure, application used for diagnostics. @return 1 on success, 0 if error found. */ static int wxd2lah_check_arrow_length_width( wxd_arrow_t *parrow, wxd2lat_job_t *pjob ) { int back = 0; switch (parrow->type) { case 0: { /* No arrowhead, so no width/height requirements */ back = 1; } break; case 27: case 28: { /* Just length required */ if ((uint8_t)0U != parrow->length) { back = 1; } else { /* ERROR: Positive length required for arrowhead */ dk4app_log_1( pjob->app, pjob->msg, pjob->sz_msg, DK4_LL_ERROR, 24 ); } } break; case 29: { /* Just width required */ if ((uint8_t)0U != parrow->width) { back = 1; } else { /* ERROR: Positive width required for arrowhead */ dk4app_log_1( pjob->app, pjob->msg, pjob->sz_msg, DK4_LL_ERROR, 25 ); } } break; default: { /* Both length and width required */ if ( ((uint8_t)0U != parrow->length) && ((uint8_t)0U != parrow->width) ) { back = 1; } else { /* ERROR: Positive width and height required on arrow */ dk4app_log_1( pjob->app, pjob->msg, pjob->sz_msg, DK4_LL_ERROR, 25 ); } } break; } return back; } int wxd2lah_one_arrowhead( wxd_arrow_t *parrow, wxd_object_t *pobj, wxd_drawing_t *pdrw, wxd2lat_job_t *pjob ) { double l; /* Line width */ double h; /* Arrow length */ double w; /* Arrow width */ double cmin; /* Minimum cut */ double cmax; /* Maximum cut */ int back = 1; $? "+ wxd2lah_one_arrowhead" l = wxd2lat_object_linewidth(pobj, pdrw, pjob); if (0.0 < l) { h = l * parrow->length; w = l * parrow->width; if (0 != wxd2lah_check_arrow_length_width(parrow, pjob)) { switch (parrow->type) { case 1: case 2: case 3: case 4: case 5: case 6: case 7: case 8: case 9: case 10: case 11: case 12: case 13: case 14: case 15: case 16: case 17: { switch (parrow->type) { case 10: case 11: case 12: case 13: { h = (3.0 * h) / 4.0; } break; case 14: case 15: case 16: case 17: { h = h / 2.0; } break; } parrow->offset = (l * sqrt(h * h + ((w * w) / 4.0))) / w; cmax = 2.0 * parrow->offset; switch (pobj->csfs) { case WXD_LC_ROUNDED: { cmin = parrow->offset; parrow->cut = (cmax + cmin) / 2.0; parrow->cuttol = (cmax - cmin) / 4.0; } break; default: { cmin = (l * h) / w; parrow->cut = (cmax + cmin) / 2.0; parrow->cuttol = (cmax - cmin) / 4.0; if (WXD_LC_PROJECTING == pobj->csfs) { parrow->cut += (l / 2.0); } } break; } } break; case 18: case 19: case 20: case 21: case 22: case 23: case 24: case 25: case 26: case 29: { parrow->offset = l / 2.0; switch (pobj->csfs) { case WXD_LC_ROUNDED: { parrow->cut = (3.0 * l) / 4.0; parrow->cuttol = l / 8.0; } break; default: { parrow->cut = l / 2.0; parrow->cuttol = l / 4.0; if (WXD_LC_PROJECTING == pobj->csfs) { parrow->cut += (l / 2.0); } } break; } } break; case 27: case 28: { parrow->offset = l / 2.0; switch (pobj->csfs) { case WXD_LC_ROUNDED: { parrow->cut = (3.0 * l) / 4.0; parrow->cuttol = l / 8.0; } break; default: { cmin = ( (h + l) * ( 1.0 + sqrt( 1.0 - wxd2lah_square(w/(h+l)) ) ) ) / 2.0; cmax = l; parrow->cut = (cmax + cmin) / 2.0; parrow->cuttol = (cmax - cmin) / 4.0; if (WXD_LC_PROJECTING == pobj->csfs) { parrow->cut += (l / 2.0); } } break; } } break; } } else { /* ERROR: Width and height (already reported) */ back = 0; } } else { /* ERROR: Line width */ dk4app_log_1( pjob->app, pjob->msg, pjob->sz_msg, DK4_LL_ERROR, 27 ); back = 0; } $? "- wxd2lah_one_arrowhead %d", back return back; } /** Build path to stroke or fill arrowhead. @param arrow Arrowhead to draw. @param drw Drawing structure. @param job Job structure. @param pobj Graphics object arrowhead is attached to. @param p Point set. @param szp Number of points in point set. @param stage Stage in arrowhead building. @param lw Line width. @param backptr Address of success variable to reset on error. @param erp Error report, may be NULL. */ static void wxd2lah_build_path( wxd_arrow_t *arrow, wxd2lat_job_t *job, dk4_gra_point_t *p, int stage, double lw, int *backptr, dk4_er_t *erp ) { switch (arrow->type) { case 1: { dk4pppt_newpath_moveto(job->ppp,p[0].x,p[0].y,NULL,backptr,erp); dk4pppt_lineto(job->ppp, p[1].x,p[1].y, NULL, backptr, erp); dk4pppt_lineto(job->ppp, p[2].x,p[2].y, NULL, backptr, erp); } break; case 2: case 3: case 23: case 24: { dk4pppt_newpath_moveto(job->ppp,p[0].x,p[0].y,NULL,backptr,erp); dk4pppt_lineto(job->ppp, p[1].x,p[1].y, NULL, backptr, erp); dk4pppt_lineto(job->ppp, p[2].x,p[2].y, NULL, backptr, erp); dk4pppt_lineto(job->ppp, p[0].x,p[0].y, NULL, backptr, erp); dk4pppt_closepath(job->ppp, backptr, erp); } break; case 4: case 5: case 25: case 26: { switch (stage) { case 1: { dk4pppt_newpath_moveto( job->ppp, p[3].x, p[3].y, NULL, backptr, erp ); dk4pppt_lineto(job->ppp, p[1].x,p[1].y, NULL, backptr, erp); dk4pppt_lineto(job->ppp, p[0].x,p[0].y, NULL, backptr, erp); dk4pppt_lineto(job->ppp, p[3].x,p[3].y, NULL, backptr, erp); dk4pppt_closepath(job->ppp, backptr, erp); } break; default : { dk4pppt_newpath_moveto( job->ppp, p[0].x, p[0].y, NULL, backptr, erp ); dk4pppt_lineto(job->ppp, p[1].x,p[1].y, NULL, backptr, erp); dk4pppt_lineto(job->ppp, p[2].x,p[2].y, NULL, backptr, erp); dk4pppt_lineto(job->ppp, p[0].x,p[0].y, NULL, backptr, erp); dk4pppt_closepath(job->ppp, backptr, erp); } break; } } break; case 6: case 7: case 10: case 11: case 14: case 15: case 18: case 19: { dk4pppt_newpath_moveto(job->ppp,p[0].x,p[0].y,NULL,backptr,erp); dk4pppt_lineto(job->ppp, p[1].x,p[1].y, NULL, backptr, erp); dk4pppt_lineto(job->ppp, p[2].x,p[2].y, NULL, backptr, erp); dk4pppt_lineto(job->ppp, p[3].x,p[3].y, NULL, backptr, erp); dk4pppt_lineto(job->ppp, p[0].x,p[0].y, NULL, backptr, erp); dk4pppt_closepath(job->ppp, backptr, erp); } break; case 8: case 9: case 12: case 13: case 16: case 17: { switch (stage) { case 1: { dk4pppt_newpath_moveto( job->ppp, p[3].x, p[3].y, NULL, backptr, erp ); dk4pppt_lineto(job->ppp, p[1].x,p[1].y, NULL, backptr, erp); dk4pppt_lineto(job->ppp, p[0].x,p[0].y, NULL, backptr, erp); dk4pppt_lineto(job->ppp, p[3].x,p[3].y, NULL, backptr, erp); dk4pppt_closepath(job->ppp, backptr, erp); } break; default : { dk4pppt_newpath_moveto( job->ppp, p[0].x, p[0].y, NULL, backptr, erp ); dk4pppt_lineto(job->ppp, p[1].x,p[1].y, NULL, backptr, erp); dk4pppt_lineto(job->ppp, p[2].x,p[2].y, NULL, backptr, erp); dk4pppt_lineto(job->ppp, p[3].x,p[3].y, NULL, backptr, erp); dk4pppt_lineto(job->ppp, p[0].x,p[0].y, NULL, backptr, erp); dk4pppt_closepath(job->ppp, backptr, erp); } break; } } break; case 20: case 21: { switch (stage) { case 1: { dk4pppt_newpath_moveto( job->ppp, p[0].x, p[0].y, NULL, backptr, erp ); dk4pppt_lineto(job->ppp, p[4].x,p[4].y, NULL, backptr, erp); dk4pppt_lineto(job->ppp, p[5].x,p[5].y, NULL, backptr, erp); dk4pppt_lineto(job->ppp, p[3].x,p[3].y, NULL, backptr, erp); dk4pppt_lineto(job->ppp, p[0].x,p[0].y, NULL, backptr, erp); dk4pppt_closepath(job->ppp, backptr, erp); } break; default : { dk4pppt_newpath_moveto( job->ppp, p[0].x, p[0].y, NULL, backptr, erp ); dk4pppt_lineto(job->ppp, p[1].x,p[1].y, NULL, backptr, erp); dk4pppt_lineto(job->ppp, p[2].x,p[2].y, NULL, backptr, erp); dk4pppt_lineto(job->ppp, p[3].x,p[3].y, NULL, backptr, erp); dk4pppt_lineto(job->ppp, p[0].x,p[0].y, NULL, backptr, erp); dk4pppt_closepath(job->ppp, backptr, erp); } break; } } break; case 22: { dk4pppt_newpath_moveto(job->ppp,p[0].x,p[0].y,NULL,backptr,erp); dk4pppt_lineto(job->ppp, p[1].x,p[1].y, NULL, backptr, erp); dk4pppt_lineto(job->ppp, p[2].x,p[2].y, NULL, backptr, erp); dk4pppt_lineto(job->ppp, p[3].x,p[3].y, NULL, backptr, erp); } break; case 27: case 28: { dk4pppt_circle( job->ppp, p[0].x, p[0].y, ((lw * (double)(arrow->length)) / 2.0), NULL, backptr, erp ); } break; case 29: { dk4pppt_newpath_moveto(job->ppp,p[0].x,p[0].y,NULL,backptr,erp); dk4pppt_lineto(job->ppp, p[1].x,p[1].y, NULL, backptr, erp); } break; } } /** Set stroke attributes for arrowhead. @param arrow Arrowhead structure. @param drw Drawing structure. @param job Job structure. @param obj Object arrow belongs to. @param isbck Flag: Is a backward arrow. @param backptr Address of success variable to reset on error. @param erp Error report, may be NULL. */ static void wxd2lah_set_stroke_attributes( wxd_arrow_t *arrow, wxd2lat_job_t *job, int *backptr, dk4_er_t *erp ) { dk4pppt_set_line_style(job->ppp, DK4_GRA_LS_SOLID, 4.0, backptr, erp); switch (arrow->type) { case 1: case 22: { dk4pppt_set_line_cap(job->ppp,DK4_GRA_LC_ROUNDED,backptr,erp); dk4pppt_set_line_join( job->ppp, DK4_GRA_LJ_MITERED, 8, backptr, erp ); } break; case 29: { dk4pppt_set_line_cap(job->ppp,DK4_GRA_LC_ROUNDED,backptr,erp); } break; case 27: case 28: { /* empty by intent */ } break; default: { dk4pppt_set_line_join( job->ppp, DK4_GRA_LJ_MITERED, 8, backptr, erp ); } break; } } /** Draw one arrowhead on polyline. @param arrow Arrowhead structure. @param drw Drawing structure. @param job Job structure. @param obj Object arrow belongs to. @param isbck Flag: Is a backward arrow. @param backptr Address of success variable to reset on error. @param erp Error report, may be NULL. */ static void wxd2lah_ah_head_angle_polyline( wxd_arrow_t *arrow, wxd2lat_job_t *job, wxd_object_t *pobj, dk4_gra_point_t *p, dk4_gra_point_t *phead, double alpha, double lw, int *backptr, dk4_er_t *erp ) { size_t npoints = 0; size_t i; /* Build path points */ switch (arrow->type) { case 1: case 2: case 3: { p[1].y = 0.0; p[1].x = 0.0; p[0].y = (lw * (double)(arrow->width)) / 2.0; p[0].x = 0.0 - lw * (double)(arrow->length); p[2].y = 0.0 - p[0].y; p[2].x = p[0].x; npoints = 3; } break; case 4: { p[1].y = 0.0; p[1].x = 0.0; p[0].y = (lw * (double)(arrow->width)) / 2.0; p[0].x = 0.0 - lw * (double)(arrow->length); p[2].y = 0.0 - (lw * (double)(arrow->width)) / 2.0; p[2].x = 0.0 - lw * (double)(arrow->length); p[3].y = 0.0; p[3].x = 0.0 - lw * (double)(arrow->length); npoints = 4; } break; case 5: { p[1].y = 0.0; p[1].x = 0.0; p[2].y = (lw * (double)(arrow->width)) / 2.0; p[2].x = 0.0 - lw * (double)(arrow->length); p[0].y = 0.0 - (lw * (double)(arrow->width)) / 2.0; p[0].x = 0.0 - lw * (double)(arrow->length); p[3].y = 0.0; p[3].x = 0.0 - lw * (double)(arrow->length); npoints = 4; } break; case 6: case 7: case 8: { p[1].y = 0.0; p[1].x = 0.0; p[0].y = (lw * (double)(arrow->width)) / 2.0; p[0].x = 0.0 - lw * (double)(arrow->length); p[2].y = 0.0 - (lw * (double)(arrow->width)) / 2.0; p[2].x = 0.0 - lw * (double)(arrow->length); p[3].y = 0.0; p[3].x = 0.0 - 0.75 * lw * (double)(arrow->length); npoints = 4; } break; case 9: { p[1].y = 0.0; p[1].x = 0.0; p[2].y = (lw * (double)(arrow->width)) / 2.0; p[2].x = 0.0 - lw * (double)(arrow->length); p[0].y = 0.0 - (lw * (double)(arrow->width)) / 2.0; p[0].x = 0.0 - lw * (double)(arrow->length); p[3].y = 0.0; p[3].x = 0.0 - 0.75 * lw * (double)(arrow->length); npoints = 4; } break; case 10: case 11: case 12: { p[1].y = 0.0; p[1].x = 0.0; p[0].y = (lw * (double)(arrow->width)) / 2.0; p[0].x = 0.0 - 0.75 * lw * (double)(arrow->length); p[2].y = 0.0 - (lw * (double)(arrow->width)) / 2.0; p[2].x = 0.0 - 0.75 * lw * (double)(arrow->length); p[3].y = 0.0; p[3].x = 0.0 - lw * (double)(arrow->length); npoints = 4; } break; case 13: { p[1].y = 0.0; p[1].x = 0.0; p[2].y = (lw * (double)(arrow->width)) / 2.0; p[2].x = 0.0 - 0.75 * lw * (double)(arrow->length); p[0].y = 0.0 - (lw * (double)(arrow->width)) / 2.0; p[0].x = 0.0 - 0.75 * lw * (double)(arrow->length); p[3].y = 0.0; p[3].x = 0.0 - lw * (double)(arrow->length); npoints = 4; } break; case 14: case 15: case 16: { p[1].y = 0.0; p[1].x = 0.0; p[0].y = (lw * (double)(arrow->width)) / 2.0; p[0].x = 0.0 - 0.5 * lw * (double)(arrow->length); p[2].y = 0.0 - (lw * (double)(arrow->width)) / 2.0; p[2].x = 0.0 - 0.5 * lw * (double)(arrow->length); p[3].y = 0.0; p[3].x = 0.0 - lw * (double)(arrow->length); npoints = 4; } break; case 17: { p[1].y = 0.0; p[1].x = 0.0; p[2].y = (lw * (double)(arrow->width)) / 2.0; p[2].x = 0.0 - 0.5 * lw * (double)(arrow->length); p[0].y = 0.0 - (lw * (double)(arrow->width)) / 2.0; p[0].x = 0.0 - 0.5 * lw * (double)(arrow->length); p[3].y = 0.0; p[3].x = 0.0 - lw * (double)(arrow->length); npoints = 4; } break; case 18: case 19: { p[0].x = 0.0; p[0].y = (lw * (double)(arrow->width)) / 2.0; p[1].x = 0.0; p[1].y = 0.0 - (lw * (double)(arrow->width)) / 2.0; p[2].x = 0.0 - lw * (double)(arrow->length); p[2].y = 0.0 - (lw * (double)(arrow->width)) / 2.0; p[3].x = 0.0 - lw * (double)(arrow->length); p[3].y = (lw * (double)(arrow->width)) / 2.0; npoints = 4; } break; case 20: { p[0].x = 0.0; p[0].y = (lw * (double)(arrow->width)) / 2.0; p[1].x = 0.0; p[1].y = 0.0 - (lw * (double)(arrow->width)) / 2.0; p[2].x = 0.0 - lw * (double)(arrow->length); p[2].y = 0.0 - (lw * (double)(arrow->width)) / 2.0; p[3].x = 0.0 - lw * (double)(arrow->length); p[3].y = (lw * (double)(arrow->width)) / 2.0; p[4].x = 0.0; p[4].y = 0.0; p[5].x = 0.0 - lw * (double)(arrow->length); p[5].y = 0.0; npoints = 6; } break; case 21: { p[1].x = 0.0; p[1].y = (lw * (double)(arrow->width)) / 2.0; p[0].x = 0.0; p[0].y = 0.0 - (lw * (double)(arrow->width)) / 2.0; p[3].x = 0.0 - lw * (double)(arrow->length); p[3].y = 0.0 - (lw * (double)(arrow->width)) / 2.0; p[2].x = 0.0 - lw * (double)(arrow->length); p[2].y = (lw * (double)(arrow->width)) / 2.0; p[4].x = 0.0; p[4].y = 0.0; p[5].x = 0.0 - lw * (double)(arrow->length); p[5].y = 0.0; npoints = 6; } break; case 22: { p[0].x = 0.0 - lw * (double)(arrow->length); p[0].y = (lw * (double)(arrow->width)) / 2.0; p[1].x = 0.0; p[1].y = (lw * (double)(arrow->width)) / 2.0; p[2].x = 0.0; p[2].y = 0.0 - (lw * (double)(arrow->width)) / 2.0; p[3].x = 0.0 - lw * (double)(arrow->length); p[3].y = 0.0 - (lw * (double)(arrow->width)) / 2.0; npoints = 4; } break; case 23: case 24: { p[0].x = 0.0; p[0].y = (lw * (double)(arrow->width)) / 2.0; p[1].x = 0.0 - lw * (double)(arrow->length); p[1].y = 0.0; p[2].x = 0.0; p[2].y = 0.0 - p[0].y; npoints = 3; } break; case 25: { p[1].y = 0.0; p[1].x = 0.0 - lw * (double)(arrow->length); p[0].y = (lw * (double)(arrow->width)) / 2.0; p[0].x = 0.0; p[2].y = 0.0 - (lw * (double)(arrow->width)) / 2.0; p[2].x = 0.0; p[3].y = 0.0; p[3].x = 0.0; npoints = 4; } break; case 26: { p[1].y = 0.0; p[1].x = 0.0 - lw * (double)(arrow->length); p[2].y = (lw * (double)(arrow->width)) / 2.0; p[2].x = 0.0; p[0].y = 0.0 - (lw * (double)(arrow->width)) / 2.0; p[0].x = 0.0; p[3].y = 0.0; p[3].x = 0.0; npoints = 4; } break; case 27: case 28: { p[0].x = 0.0 - (lw * (double)(arrow->length)) / 2.0; p[0].y = 0.0; npoints = 1; } break; case 29: { p[0].x = 0.0; p[0].y = (lw * (double)(arrow->width)) / 2.0; p[1].x = 0.0; p[1].y = 0.0 - p[0].y; npoints = 2; } break; } /* Rotate and shift the points */ for (i = 0; i < npoints; i++) { dk4gratool_rotate_point(&(p[i]), alpha); p[i].x += phead->x; p[i].y += phead->y; } /* Set up stroke attributes */ wxd2lah_set_stroke_attributes(arrow, job, backptr, erp); #if 0 dk4pppt_set_line_style(job->ppp, DK4_GRA_LS_SOLID, 4.0, backptr, erp); switch (arrow->type) { case 1: case 22: { dk4pppt_set_line_cap(job->ppp,DK4_GRA_LC_ROUNDED,backptr,erp); dk4pppt_set_line_join( job->ppp, DK4_GRA_LJ_MITERED, 8, backptr, erp ); } break; case 29: { dk4pppt_set_line_cap(job->ppp,DK4_GRA_LC_ROUNDED,backptr,erp); } break; case 27: case 28: { /* empty by intent */ } break; default: { dk4pppt_set_line_join( job->ppp, DK4_GRA_LJ_MITERED, 8, backptr, erp ); } break; } #endif /* Use path */ switch (arrow->type) { case 1: case 22: case 29: { /* Arrowheads to stroke */ dk4pppt_prepare_stroke(job->ppp, backptr, erp); wxd2lah_build_path( arrow, job, p, 0, lw, backptr, erp ); dk4pppt_stroke(job->ppp, backptr, erp); } break; case 2: case 6: case 10: case 14: case 18: case 23: case 27: { /* White filled arrowheads */ dk4pppt_set_fill_rgb(job->ppp, 1.0, 1.0, 1.0, backptr, erp); if (0 != dk4pppt_can_fill_and_stroke(job->ppp)) { dk4pppt_prepare_fill_and_stroke(job->ppp, backptr, erp); wxd2lah_build_path( arrow, job, p, 0, lw, backptr, erp ); dk4pppt_fill_and_stroke(job->ppp, backptr, erp); } else { dk4pppt_prepare_fill(job->ppp, backptr, erp); wxd2lah_build_path( arrow, job, p, 0, lw, backptr, erp ); dk4pppt_fill(job->ppp, backptr, erp); dk4pppt_prepare_stroke(job->ppp, backptr, erp); wxd2lah_build_path( arrow, job, p, 0, lw, backptr, erp ); dk4pppt_stroke(job->ppp, backptr, erp); } } break; case 3: case 7: case 11: case 15: case 24: case 19: case 28: { /* Color filled arrowheads */ dk4pppt_set_fill_rgb( job->ppp, ((double)(pobj->sc[0]) / 255.0), ((double)(pobj->sc[1]) / 255.0), ((double)(pobj->sc[2]) / 255.0), backptr, erp ); if (0 != dk4pppt_can_fill_and_stroke(job->ppp)) { dk4pppt_prepare_fill_and_stroke(job->ppp, backptr, erp); wxd2lah_build_path( arrow, job, p, 0, lw, backptr, erp ); dk4pppt_fill_and_stroke(job->ppp, backptr, erp); } else { dk4pppt_prepare_fill(job->ppp, backptr, erp); wxd2lah_build_path( arrow, job, p, 0, lw, backptr, erp ); dk4pppt_fill(job->ppp, backptr, erp); dk4pppt_prepare_stroke(job->ppp, backptr, erp); wxd2lah_build_path( arrow, job, p, 0, lw, backptr, erp ); dk4pppt_stroke(job->ppp, backptr, erp); } } break; case 4: case 5: case 8: case 9: case 12: case 13: case 16: case 17: case 20: case 21: case 25: case 26: { /* Half-side filled arrowheads */ dk4pppt_set_fill_rgb(job->ppp, 1.0, 1.0, 1.0, backptr, erp); if (0 != dk4pppt_can_fill_and_stroke(job->ppp)) { dk4pppt_prepare_fill_and_stroke(job->ppp, backptr, erp); wxd2lah_build_path( arrow, job, p, 0, lw, backptr, erp ); dk4pppt_fill_and_stroke(job->ppp, backptr, erp); } else { dk4pppt_prepare_fill(job->ppp, backptr, erp); wxd2lah_build_path( arrow, job, p, 0, lw, backptr, erp ); dk4pppt_fill(job->ppp, backptr, erp); dk4pppt_prepare_stroke(job->ppp, backptr, erp); wxd2lah_build_path( arrow, job, p, 0, lw, backptr, erp ); dk4pppt_stroke(job->ppp, backptr, erp); } dk4pppt_set_fill_rgb( job->ppp, ((double)(pobj->sc[0]) / 255.0), ((double)(pobj->sc[1]) / 255.0), ((double)(pobj->sc[2]) / 255.0), backptr, erp ); dk4pppt_prepare_fill(job->ppp, backptr, erp); wxd2lah_build_path( arrow, job, p, 1, lw, backptr, erp ); dk4pppt_fill(job->ppp, backptr, erp); } break; } } /** Draw one arrowhead on polyline. @param arrow Arrowhead structure. @param drw Drawing structure. @param job Job structure. @param obj Object arrow belongs to. @param isbck Flag: Is a backward arrow. @param backptr Address of success variable to reset on error. @param erp Error report, may be NULL. */ static void wxd2lah_ah_polyline( wxd_arrow_t *arrow, wxd_drawing_t *drw, wxd2lat_job_t *job, wxd_object_t *pobj, int isbck, int *backptr, dk4_er_t *erp ) { dk4_gra_point_t p[8]; /* Points to construct arrowhead path */ dk4_gra_point_t head; /* Point where arrowhead ends */ dk4_gra_point_t *pptr; /* Destination for copy operation */ double alpha; /* Direction of arrowhead */ double lw; /* Line width */ double x0; /* Start point X to calculate angle */ double y0; /* Start point Y to calculate angle */ double x1; /* End point X to calculate angle */ double y1; /* End point Y to calculate angle */ $? "+ wxd2lah_ah_polyline" /* Find line width used by object */ lw = wxd2lat_object_linewidth(pobj, drw, job); /* Find head point and angle */ if (0 != isbck) { DK4_MEMCPY(&head,(pobj->det).p.p,sizeof(wxd_point_t)); x1 = ((pobj->det).p.p)[0].x; y1 = ((pobj->det).p.p)[0].y; x0 = ((pobj->det).p.p)[1].x; y0 = ((pobj->det).p.p)[1].y; } else { pptr = (pobj->det).p.p; pptr = &(pptr[(pobj->det).p.n - (uint16_t)1U]); DK4_MEMCPY(&head,pptr,sizeof(wxd_point_t)); x1 = ((pobj->det).p.p)[(pobj->det).p.n - (uint16_t)1U].x; y1 = ((pobj->det).p.p)[(pobj->det).p.n - (uint16_t)1U].y; x0 = ((pobj->det).p.p)[(pobj->det).p.n - (uint16_t)2U].x; y0 = ((pobj->det).p.p)[(pobj->det).p.n - (uint16_t)2U].y; } y1 = y1 - y0; x1 = x1 - x0; /* 2019-03-15: BUGFIX Changed and condition to or condition. It is sufficient to have one of the distances unequal 0. */ if ((1.0e-8 < fabs(y1)) || (1.0e-8 < fabs(x1))) { /* Find angle */ alpha = atan2(y1, x1); /* Move head point by arrow offset */ p[0].x = 0.0 - arrow->offset; p[0].y = 0.0; dk4gratool_rotate_point(&(p[0]), alpha); head.x += p[0].x; head.y += p[0].y; wxd2lah_ah_head_angle_polyline( arrow, job, pobj, p, &head, alpha, lw, backptr, erp ); } else { $? "! angle" *backptr = 0; /* ERROR: Failed to calculate angle for arrowhead */ dk4app_log_1( job->app, job->msg, job->sz_msg, DK4_LL_ERROR, 28 ); } $? "- wxd2lah_ah_polyline" } /** Calculate segments for real arc. @param arrow Arrowhead structure. @param job Job structure. @param pobj Object arrow belongs to. @param ah Angle at head of arrow. @param csgn Coefficient for angles departing from head (1 or -1). @param lw Line width. @param backptr Address of success variable to reset on error. @param erp Error report, may be NULL. */ static void wxd2lah_ah_segs_real_arc( arc_ah_seg_t *s, wxd_arrow_t *arrow, wxd_object_t *pobj, double ah, double csgn, double lw ) { $? "+ wxd2lah_ah_segs_real_arc %d %g", (int)(arrow->type), ah switch (arrow->type) { case 1: case 2: case 3: { wxd2lah_arc_arrow_segment( &(s[0]), ((pobj->det).a.r+((lw*(double)(arrow->width))/2.0)), (pobj->det).a.r, (ah+((csgn*lw*((double)(arrow->length)))/(pobj->det).a.r)), ah, (pobj->det).a.x, (pobj->det).a.y ); wxd2lah_arc_arrow_segment( &(s[1]), ((pobj->det).a.r-((lw*(double)(arrow->width))/2.0)), (pobj->det).a.r, (ah+((csgn*lw*((double)(arrow->length)))/(pobj->det).a.r)), ah, (pobj->det).a.x, (pobj->det).a.y ); } break; case 4: case 5: { wxd2lah_arc_arrow_segment( &(s[0]), ((pobj->det).a.r+((lw*(double)(arrow->width))/2.0)), (pobj->det).a.r, (ah+((csgn*lw*((double)(arrow->length)))/(pobj->det).a.r)), ah, (pobj->det).a.x, (pobj->det).a.y ); wxd2lah_arc_arrow_segment( &(s[1]), ((pobj->det).a.r-((lw*(double)(arrow->width))/2.0)), (pobj->det).a.r, (ah+((csgn*lw*((double)(arrow->length)))/(pobj->det).a.r)), ah, (pobj->det).a.x, (pobj->det).a.y ); wxd2lah_arc_arrow_segment( &(s[2]), (pobj->det).a.r, (pobj->det).a.r, (ah+((csgn*lw*((double)(arrow->length)))/(pobj->det).a.r)), ah, (pobj->det).a.x, (pobj->det).a.y ); } break; case 6: case 7: { wxd2lah_arc_arrow_segment( &(s[0]), ((pobj->det).a.r+((lw*(double)(arrow->width))/2.0)), (pobj->det).a.r, (ah+((csgn*lw*((double)(arrow->length)))/(pobj->det).a.r)), ah, (pobj->det).a.x, (pobj->det).a.y ); wxd2lah_arc_arrow_segment( &(s[1]), ((pobj->det).a.r-((lw*(double)(arrow->width))/2.0)), (pobj->det).a.r, (ah+((csgn*lw*((double)(arrow->length)))/(pobj->det).a.r)), ah, (pobj->det).a.x, (pobj->det).a.y ); wxd2lah_arc_arrow_segment( &(s[2]), ((pobj->det).a.r+((lw*(double)(arrow->width))/2.0)), (pobj->det).a.r, (ah+((csgn*lw*((double)(arrow->length)))/(pobj->det).a.r)), (ah+((0.75*csgn*lw*((double)(arrow->length)))/(pobj->det).a.r)), (pobj->det).a.x, (pobj->det).a.y ); wxd2lah_arc_arrow_segment( &(s[3]), ((pobj->det).a.r-((lw*(double)(arrow->width))/2.0)), (pobj->det).a.r, (ah+((csgn*lw*((double)(arrow->length)))/(pobj->det).a.r)), (ah+((0.75*csgn*lw*((double)(arrow->length)))/(pobj->det).a.r)), (pobj->det).a.x, (pobj->det).a.y ); } break; case 8: case 9: { wxd2lah_arc_arrow_segment( &(s[0]), ((pobj->det).a.r+((lw*(double)(arrow->width))/2.0)), (pobj->det).a.r, (ah+((csgn*lw*((double)(arrow->length)))/(pobj->det).a.r)), ah, (pobj->det).a.x, (pobj->det).a.y ); wxd2lah_arc_arrow_segment( &(s[1]), ((pobj->det).a.r-((lw*(double)(arrow->width))/2.0)), (pobj->det).a.r, (ah+((csgn*lw*((double)(arrow->length)))/(pobj->det).a.r)), ah, (pobj->det).a.x, (pobj->det).a.y ); wxd2lah_arc_arrow_segment( &(s[2]), ((pobj->det).a.r+((lw*(double)(arrow->width))/2.0)), (pobj->det).a.r, (ah+((csgn*lw*((double)(arrow->length)))/(pobj->det).a.r)), (ah+((0.75*csgn*lw*((double)(arrow->length)))/(pobj->det).a.r)), (pobj->det).a.x, (pobj->det).a.y ); wxd2lah_arc_arrow_segment( &(s[3]), ((pobj->det).a.r-((lw*(double)(arrow->width))/2.0)), (pobj->det).a.r, (ah+((csgn*lw*((double)(arrow->length)))/(pobj->det).a.r)), (ah+((0.75*csgn*lw*((double)(arrow->length)))/(pobj->det).a.r)), (pobj->det).a.x, (pobj->det).a.y ); wxd2lah_arc_arrow_segment( &(s[4]), (pobj->det).a.r, (pobj->det).a.r, (ah+((0.75*csgn*lw*((double)(arrow->length)))/(pobj->det).a.r)), ah, (pobj->det).a.x, (pobj->det).a.y ); } break; case 10: case 11: case 12: case 13: { wxd2lah_arc_arrow_segment( &(s[0]), ((pobj->det).a.r+((lw*(double)(arrow->width))/2.0)), (pobj->det).a.r, (ah+((0.75*csgn*lw*((double)(arrow->length)))/(pobj->det).a.r)), ah, (pobj->det).a.x, (pobj->det).a.y ); wxd2lah_arc_arrow_segment( &(s[1]), ((pobj->det).a.r-((lw*(double)(arrow->width))/2.0)), (pobj->det).a.r, (ah+((0.75*csgn*lw*((double)(arrow->length)))/(pobj->det).a.r)), ah, (pobj->det).a.x, (pobj->det).a.y ); wxd2lah_arc_arrow_segment( &(s[2]), ((pobj->det).a.r+((lw*(double)(arrow->width))/2.0)), (pobj->det).a.r, (ah+((0.75*csgn*lw*((double)(arrow->length)))/(pobj->det).a.r)), (ah+((csgn*lw*((double)(arrow->length)))/(pobj->det).a.r)), (pobj->det).a.x, (pobj->det).a.y ); wxd2lah_arc_arrow_segment( &(s[3]), ((pobj->det).a.r-((lw*(double)(arrow->width))/2.0)), (pobj->det).a.r, (ah+((0.75*csgn*lw*((double)(arrow->length)))/(pobj->det).a.r)), (ah+((csgn*lw*((double)(arrow->length)))/(pobj->det).a.r)), (pobj->det).a.x, (pobj->det).a.y ); wxd2lah_arc_arrow_segment( &(s[4]), (pobj->det).a.r, (pobj->det).a.r, (ah+((csgn*lw*((double)(arrow->length)))/(pobj->det).a.r)), ah, (pobj->det).a.x, (pobj->det).a.y ); } break; case 14: case 15: case 16: case 17: { #if TRACE_DEBUG size_t i; size_t j; #endif wxd2lah_arc_arrow_segment( &(s[0]), ((pobj->det).a.r+((lw*(double)(arrow->width))/2.0)), (pobj->det).a.r, (ah+((0.5*csgn*lw*((double)(arrow->length)))/(pobj->det).a.r)), ah, (pobj->det).a.x, (pobj->det).a.y ); wxd2lah_arc_arrow_segment( &(s[1]), ((pobj->det).a.r-((lw*(double)(arrow->width))/2.0)), (pobj->det).a.r, (ah+((0.5*csgn*lw*((double)(arrow->length)))/(pobj->det).a.r)), ah, (pobj->det).a.x, (pobj->det).a.y ); wxd2lah_arc_arrow_segment( &(s[2]), ((pobj->det).a.r+((lw*(double)(arrow->width))/2.0)), (pobj->det).a.r, (ah+((0.5*csgn*lw*((double)(arrow->length)))/(pobj->det).a.r)), (ah+((csgn*lw*((double)(arrow->length)))/(pobj->det).a.r)), (pobj->det).a.x, (pobj->det).a.y ); wxd2lah_arc_arrow_segment( &(s[3]), ((pobj->det).a.r-((lw*(double)(arrow->width))/2.0)), (pobj->det).a.r, (ah+((0.5*csgn*lw*((double)(arrow->length)))/(pobj->det).a.r)), (ah+((csgn*lw*((double)(arrow->length)))/(pobj->det).a.r)), (pobj->det).a.x, (pobj->det).a.y ); wxd2lah_arc_arrow_segment( &(s[4]), (pobj->det).a.r, (pobj->det).a.r, (ah+((csgn*lw*((double)(arrow->length)))/(pobj->det).a.r)), ah, (pobj->det).a.x, (pobj->det).a.y ); #if TRACE_DEBUG for (i = 0; i < 5; i++) { $? ". segment %u", (unsigned)i for (j = 0; j < 4; j++) { $? ". point %u x = %g", (unsigned)j, s[i].p[j].x $? ". point %u y = %g", (unsigned)j, s[i].p[j].y } } #endif } break; case 18: case 19: case 20: case 21: case 22: { wxd2lah_arc_arrow_segment( &(s[0]), ((pobj->det).a.r+((lw*(double)(arrow->width))/2.0)), ((pobj->det).a.r+((lw*(double)(arrow->width))/2.0)), (ah+((csgn*lw*((double)(arrow->length)))/(pobj->det).a.r)), ah, (pobj->det).a.x, (pobj->det).a.y ); wxd2lah_arc_arrow_segment( &(s[1]), ((pobj->det).a.r-((lw*(double)(arrow->width))/2.0)), ((pobj->det).a.r-((lw*(double)(arrow->width))/2.0)), (ah+((csgn*lw*((double)(arrow->length)))/(pobj->det).a.r)), ah, (pobj->det).a.x, (pobj->det).a.y ); wxd2lah_arc_arrow_segment( &(s[2]), (pobj->det).a.r, (pobj->det).a.r, (ah+((csgn*lw*((double)(arrow->length)))/(pobj->det).a.r)), ah, (pobj->det).a.x, (pobj->det).a.y ); } break; case 23: case 24: case 25: case 26: { wxd2lah_arc_arrow_segment( &(s[0]), (pobj->det).a.r, ((pobj->det).a.r+((lw*(double)(arrow->width))/2.0)), (ah+((csgn*lw*((double)(arrow->length)))/(pobj->det).a.r)), ah, (pobj->det).a.x, (pobj->det).a.y ); wxd2lah_arc_arrow_segment( &(s[1]), (pobj->det).a.r, ((pobj->det).a.r-((lw*(double)(arrow->width))/2.0)), (ah+((csgn*lw*((double)(arrow->length)))/(pobj->det).a.r)), ah, (pobj->det).a.x, (pobj->det).a.y ); wxd2lah_arc_arrow_segment( &(s[2]), (pobj->det).a.r, (pobj->det).a.r, (ah+((csgn*lw*((double)(arrow->length)))/(pobj->det).a.r)), ah, (pobj->det).a.x, (pobj->det).a.y ); } break; } $? "- wxd2lah_ah_segs_real_arc" } /** Create path for arrowhead on real arc. @param arrow Arrowhead structure. @param job Job structure. @param pobj Object arrow belongs to. @param ahead Angle at head of arrow. @param csgn Coefficient for angles departing from head (1 or -1). @param lw Line width. @param backptr Address of success variable to reset on error. @param erp Error report, may be NULL. */ static void wxd2lah_ah_path_real_arc( wxd_arrow_t *arrow, wxd2lat_job_t *job, wxd_object_t *pobj, arc_ah_seg_t *s, int stage, double ahead, double csgn, double lw, int *backptr, dk4_er_t *erp ) { double xc; /* Circle center point x */ double yc; /* Circle center point y */ double r; /* Circle radius */ size_t ss; /* Front segment on active side */ size_t ts; /* Butt segment on active side */ $? "+ wxd2lah_ah_path_real_arc" switch (arrow->type) { case 1: { dk4pppt_newpath_moveto( job->ppp, s[0].p[0].x, s[0].p[0].y, NULL, backptr, erp ); dk4pppt_curveto( job->ppp, s[0].p[1].x, s[0].p[1].y, s[0].p[2].x, s[0].p[2].y, s[0].p[3].x, s[0].p[3].y, NULL, backptr, erp ); dk4pppt_curveto( job->ppp, s[1].p[2].x, s[1].p[2].y, s[1].p[1].x, s[1].p[1].y, s[1].p[0].x, s[1].p[0].y, NULL, backptr, erp ); } break; case 2: case 3: { dk4pppt_newpath_moveto( job->ppp, s[0].p[0].x, s[0].p[0].y, NULL, backptr, erp ); dk4pppt_curveto( job->ppp, s[0].p[1].x, s[0].p[1].y, s[0].p[2].x, s[0].p[2].y, s[0].p[3].x, s[0].p[3].y, NULL, backptr, erp ); dk4pppt_curveto( job->ppp, s[1].p[2].x, s[1].p[2].y, s[1].p[1].x, s[1].p[1].y, s[1].p[0].x, s[1].p[0].y, NULL, backptr, erp ); dk4pppt_lineto( job->ppp, s[0].p[0].x, s[0].p[0].y, NULL, backptr, erp ); dk4pppt_closepath(job->ppp, backptr, erp); } break; case 4: case 5: { if (0 == stage) { dk4pppt_newpath_moveto( job->ppp, s[0].p[0].x, s[0].p[0].y, NULL, backptr, erp ); dk4pppt_curveto( job->ppp, s[0].p[1].x, s[0].p[1].y, s[0].p[2].x, s[0].p[2].y, s[0].p[3].x, s[0].p[3].y, NULL, backptr, erp ); dk4pppt_curveto( job->ppp, s[1].p[2].x, s[1].p[2].y, s[1].p[1].x, s[1].p[1].y, s[1].p[0].x, s[1].p[0].y, NULL, backptr, erp ); dk4pppt_lineto( job->ppp, s[0].p[0].x, s[0].p[0].y, NULL, backptr, erp ); dk4pppt_closepath(job->ppp, backptr, erp); } else { ss = ( (4 == arrow->type) ? ((0.0 > csgn) ? (1) : (0)) : ((0.0 > csgn) ? (0) : (1)) ); dk4pppt_newpath_moveto( job->ppp, s[ss].p[0].x, s[ss].p[0].y, NULL, backptr, erp ); dk4pppt_curveto( job->ppp, s[ss].p[1].x, s[ss].p[1].y, s[ss].p[2].x, s[ss].p[2].y, s[ss].p[3].x, s[ss].p[3].y, NULL, backptr, erp ); dk4pppt_curveto( job->ppp, s[2].p[2].x, s[2].p[2].y, s[2].p[1].x, s[2].p[1].y, s[2].p[0].x, s[2].p[0].y, NULL, backptr, erp ); dk4pppt_lineto( job->ppp, s[ss].p[0].x, s[ss].p[0].y, NULL, backptr, erp ); dk4pppt_closepath(job->ppp, backptr, erp); } } break; case 6: case 7: case 10: case 11: case 14: case 15: { dk4pppt_newpath_moveto( job->ppp, s[0].p[0].x, s[0].p[0].y, NULL, backptr, erp ); dk4pppt_curveto( job->ppp, s[0].p[1].x, s[0].p[1].y, s[0].p[2].x, s[0].p[2].y, s[0].p[3].x, s[0].p[3].y, NULL, backptr, erp ); dk4pppt_curveto( job->ppp, s[1].p[2].x, s[1].p[2].y, s[1].p[1].x, s[1].p[1].y, s[1].p[0].x, s[1].p[0].y, NULL, backptr, erp ); dk4pppt_curveto( job->ppp, s[3].p[1].x, s[3].p[1].y, s[3].p[2].x, s[3].p[2].y, s[3].p[3].x, s[3].p[3].y, NULL, backptr, erp ); dk4pppt_curveto( job->ppp, s[2].p[2].x, s[2].p[2].y, s[2].p[1].x, s[2].p[1].y, s[2].p[0].x, s[2].p[0].y, NULL, backptr, erp ); dk4pppt_closepath(job->ppp, backptr, erp); } break; case 8: case 9: case 12: case 13: case 16: case 17: { $? ". stage %d direction %d", stage, (int)((pobj->det).a.d) if (0 == stage) { $? ". segment 0 forward" dk4pppt_newpath_moveto( job->ppp, s[0].p[0].x, s[0].p[0].y, NULL, backptr, erp ); dk4pppt_curveto( job->ppp, s[0].p[1].x, s[0].p[1].y, s[0].p[2].x, s[0].p[2].y, s[0].p[3].x, s[0].p[3].y, NULL, backptr, erp ); $? ". segment 1 backward" dk4pppt_curveto( job->ppp, s[1].p[2].x, s[1].p[2].y, s[1].p[1].x, s[1].p[1].y, s[1].p[0].x, s[1].p[0].y, NULL, backptr, erp ); $? ". segment 3 forward" dk4pppt_curveto( job->ppp, s[3].p[1].x, s[3].p[1].y, s[3].p[2].x, s[3].p[2].y, s[3].p[3].x, s[3].p[3].y, NULL, backptr, erp ); $? ". segment 2 backward" dk4pppt_curveto( job->ppp, s[2].p[2].x, s[2].p[2].y, s[2].p[1].x, s[2].p[1].y, s[2].p[0].x, s[2].p[0].y, NULL, backptr, erp ); $? ". closepath" dk4pppt_closepath(job->ppp, backptr, erp); } else { ss = ((0.0 > csgn) ? (0) : (1)); ts = ((0.0 > csgn) ? (2) : (3)); switch (arrow->type) { case 8: case 12: case 16: { ss = ((0.0 > csgn) ? (1) : (0)); ts = ((0.0 > csgn) ? (3) : (2)); } break; } $? ". segment %d forward", (int)ss dk4pppt_newpath_moveto( job->ppp, s[ss].p[0].x, s[ss].p[0].y, NULL, backptr, erp ); dk4pppt_curveto( job->ppp, s[ss].p[1].x, s[ss].p[1].y, s[ss].p[2].x, s[ss].p[2].y, s[ss].p[3].x, s[ss].p[3].y, NULL, backptr, erp ); $? ". segment 4 backward" dk4pppt_curveto( job->ppp, s[4].p[2].x, s[4].p[2].y, s[4].p[1].x, s[4].p[1].y, s[4].p[0].x, s[4].p[0].y, NULL, backptr, erp ); $? ". segment %d backward", (int)ts dk4pppt_curveto( job->ppp, s[ts].p[2].x, s[ts].p[2].y, s[ts].p[1].x, s[ts].p[1].y, s[ts].p[0].x, s[ts].p[0].y, NULL, backptr, erp ); $? ". closepath" dk4pppt_closepath(job->ppp, backptr, erp); } } break; case 18: case 19: { dk4pppt_newpath_moveto( job->ppp, s[0].p[0].x, s[0].p[0].y, NULL, backptr, erp ); dk4pppt_curveto( job->ppp, s[0].p[1].x, s[0].p[1].y, s[0].p[2].x, s[0].p[2].y, s[0].p[3].x, s[0].p[3].y, NULL, backptr, erp ); dk4pppt_lineto( job->ppp, s[1].p[3].x, s[1].p[3].y, NULL, backptr, erp ); dk4pppt_curveto( job->ppp, s[1].p[2].x, s[1].p[2].y, s[1].p[1].x, s[1].p[1].y, s[1].p[0].x, s[1].p[0].y, NULL, backptr, erp ); dk4pppt_lineto( job->ppp, s[0].p[0].x, s[0].p[0].y, NULL, backptr, erp ); dk4pppt_closepath(job->ppp, backptr, erp); } break; case 20: case 21: { if (0 == stage) { dk4pppt_newpath_moveto( job->ppp, s[0].p[0].x, s[0].p[0].y, NULL, backptr, erp ); dk4pppt_curveto( job->ppp, s[0].p[1].x, s[0].p[1].y, s[0].p[2].x, s[0].p[2].y, s[0].p[3].x, s[0].p[3].y, NULL, backptr, erp ); dk4pppt_lineto( job->ppp, s[1].p[3].x, s[1].p[3].y, NULL, backptr, erp ); dk4pppt_curveto( job->ppp, s[1].p[2].x, s[1].p[2].y, s[1].p[1].x, s[1].p[1].y, s[1].p[0].x, s[1].p[0].y, NULL, backptr, erp ); dk4pppt_lineto( job->ppp, s[0].p[0].x, s[0].p[0].y, NULL, backptr, erp ); dk4pppt_closepath(job->ppp, backptr, erp); } else { ss = ( (20 == arrow->type) ? ((0.0 > csgn) ? (1) : (0)) : ((0.0 > csgn) ? (0) : (1)) ); dk4pppt_newpath_moveto( job->ppp, s[ss].p[0].x, s[ss].p[0].y, NULL, backptr, erp ); dk4pppt_curveto( job->ppp, s[ss].p[1].x, s[ss].p[1].y, s[ss].p[2].x, s[ss].p[2].y, s[ss].p[3].x, s[ss].p[3].y, NULL, backptr, erp ); dk4pppt_lineto( job->ppp, s[2].p[3].x, s[2].p[3].y, NULL, backptr, erp ); dk4pppt_curveto( job->ppp, s[2].p[2].x, s[2].p[2].y, s[2].p[1].x, s[2].p[1].y, s[2].p[0].x, s[2].p[0].y, NULL, backptr, erp ); dk4pppt_lineto( job->ppp, s[ss].p[0].x, s[ss].p[0].y, NULL, backptr, erp ); dk4pppt_closepath(job->ppp, backptr, erp); } } break; case 22: { dk4pppt_newpath_moveto( job->ppp, s[0].p[0].x, s[0].p[0].y, NULL, backptr, erp ); dk4pppt_curveto( job->ppp, s[0].p[1].x, s[0].p[1].y, s[0].p[2].x, s[0].p[2].y, s[0].p[3].x, s[0].p[3].y, NULL, backptr, erp ); dk4pppt_lineto( job->ppp, s[1].p[3].x, s[1].p[3].y, NULL, backptr, erp ); dk4pppt_curveto( job->ppp, s[1].p[2].x, s[1].p[2].y, s[1].p[1].x, s[1].p[1].y, s[1].p[0].x, s[1].p[0].y, NULL, backptr, erp ); } break; case 23: case 24: { dk4pppt_newpath_moveto( job->ppp, s[0].p[0].x, s[0].p[0].y, NULL, backptr, erp ); dk4pppt_curveto( job->ppp, s[0].p[1].x, s[0].p[1].y, s[0].p[2].x, s[0].p[2].y, s[0].p[3].x, s[0].p[3].y, NULL, backptr, erp ); dk4pppt_lineto( job->ppp, s[1].p[3].x, s[1].p[3].y, NULL, backptr, erp ); dk4pppt_curveto( job->ppp, s[1].p[2].x, s[1].p[2].y, s[1].p[1].x, s[1].p[1].y, s[1].p[0].x, s[1].p[0].y, NULL, backptr, erp ); dk4pppt_closepath(job->ppp, backptr, erp); } break; case 25: case 26: { if (0 == stage) { dk4pppt_newpath_moveto( job->ppp, s[0].p[0].x, s[0].p[0].y, NULL, backptr, erp ); dk4pppt_curveto( job->ppp, s[0].p[1].x, s[0].p[1].y, s[0].p[2].x, s[0].p[2].y, s[0].p[3].x, s[0].p[3].y, NULL, backptr, erp ); dk4pppt_lineto( job->ppp, s[1].p[3].x, s[1].p[3].y, NULL, backptr, erp ); dk4pppt_curveto( job->ppp, s[1].p[2].x, s[1].p[2].y, s[1].p[1].x, s[1].p[1].y, s[1].p[0].x, s[1].p[0].y, NULL, backptr, erp ); dk4pppt_closepath(job->ppp, backptr, erp); } else { ss = ( (25 == arrow->type) ? ((0.0 > csgn) ? (1) : (0)) : ((0.0 > csgn) ? (0) : (1)) ); dk4pppt_newpath_moveto( job->ppp, s[ss].p[0].x, s[ss].p[0].y, NULL, backptr, erp ); dk4pppt_curveto( job->ppp, s[ss].p[1].x, s[ss].p[1].y, s[ss].p[2].x, s[ss].p[2].y, s[ss].p[3].x, s[ss].p[3].y, NULL, backptr, erp ); dk4pppt_lineto( job->ppp, s[2].p[3].x, s[2].p[3].y, NULL, backptr, erp ); dk4pppt_curveto( job->ppp, s[2].p[2].x, s[2].p[2].y, s[2].p[1].x, s[2].p[1].y, s[2].p[0].x, s[2].p[0].y, NULL, backptr, erp ); dk4pppt_closepath(job->ppp, backptr, erp); } } break; case 27: case 28: { xc = (pobj->det).a.r * cos(ahead) + (pobj->det).a.x; yc = (pobj->det).a.r * sin(ahead) + (pobj->det).a.y; r = (lw * (double)(arrow->length)) / 2.0; xc += (csgn * r * cos(ahead + M_PI_2)); yc += (csgn * r * sin(ahead + M_PI_2)); dk4pppt_circle(job->ppp, xc, yc, r, NULL, backptr, erp); } break; case 29: { r = (pobj->det).a.r + (lw * (double)(arrow->width)) / 2.0; xc = (pobj->det).a.x + r * cos(ahead); yc = (pobj->det).a.y + r * sin(ahead); dk4pppt_newpath_moveto(job->ppp, xc, yc, NULL, backptr, erp); r = (pobj->det).a.r - (lw * (double)(arrow->width)) / 2.0; xc = (pobj->det).a.x + r * cos(ahead); yc = (pobj->det).a.y + r * sin(ahead); dk4pppt_lineto(job->ppp, xc, yc, NULL, backptr, erp); } break; } $? "- wxd2lah_ah_path_real_arc" } /** Draw one arrowhead on real arc. @param arrow Arrowhead structure. @param drw Drawing structure. @param job Job structure. @param obj Object arrow belongs to. @param isbck Flag: Is a backward arrow. @param backptr Address of success variable to reset on error. @param erp Error report, may be NULL. */ static void wxd2lah_ah_real_arc( wxd_arrow_t *arrow, wxd_drawing_t *drw, wxd2lat_job_t *job, wxd_object_t *pobj, int isbck, int *backptr, dk4_er_t *erp ) { arc_ah_seg_t s[8]; /* Arrowhead segments */ double lw; /* Line width */ double csgn; /* Coefficient for angle, departing from head */ double ah; /* Head alpha */ $? "+ wxd2lah_ah_real_arc" /* Setup */ lw = wxd2lat_object_linewidth(pobj, drw, job); csgn = ( (0 != isbck) ? ((0 < (pobj->det).a.d) ? (1.0) : (-1.0)) : ((0 > (pobj->det).a.d) ? (1.0) : (-1.0)) ); ah = ( (0 != isbck) ? ((pobj->det).a.a + (csgn * (arrow->offset) / (pobj->det).a.r)) : ((pobj->det).a.b + (csgn * (arrow->offset) / (pobj->det).a.r)) ); /* Create segment data. */ wxd2lah_ah_segs_real_arc(s, arrow, pobj, ah, csgn, lw); /* Set up stroke and fill attributes */ wxd2lah_set_stroke_attributes(arrow, job, backptr, erp); /* Use path */ switch (arrow->type) { case 1: case 22: case 29: { /* Arrowheads to stroke */ dk4pppt_prepare_stroke(job->ppp, backptr, erp); wxd2lah_ah_path_real_arc( arrow, job, pobj, s, 0, ah, csgn, lw, backptr, erp ); dk4pppt_stroke(job->ppp, backptr, erp); } break; case 2: case 6: case 10: case 14: case 18: case 23: case 27: { /* White filled arrowheads */ dk4pppt_set_fill_rgb(job->ppp, 1.0, 1.0, 1.0, backptr, erp); if (0 != dk4pppt_can_fill_and_stroke(job->ppp)) { dk4pppt_prepare_fill_and_stroke(job->ppp, backptr, erp); wxd2lah_ah_path_real_arc( arrow, job, pobj, s, 0, ah, csgn, lw, backptr, erp ); dk4pppt_fill_and_stroke(job->ppp, backptr, erp); } else { dk4pppt_prepare_fill(job->ppp, backptr, erp); wxd2lah_ah_path_real_arc( arrow, job, pobj, s, 0, ah, csgn, lw, backptr, erp ); dk4pppt_fill(job->ppp, backptr, erp); dk4pppt_prepare_stroke(job->ppp, backptr, erp); wxd2lah_ah_path_real_arc( arrow, job, pobj, s, 0, ah, csgn, lw, backptr, erp ); dk4pppt_stroke(job->ppp, backptr, erp); } } break; case 3: case 7: case 11: case 15: case 24: case 19: case 28: { /* Color filled arrowheads */ dk4pppt_set_fill_rgb( job->ppp, ((double)(pobj->sc[0]) / 255.0), ((double)(pobj->sc[1]) / 255.0), ((double)(pobj->sc[2]) / 255.0), backptr, erp ); if (0 != dk4pppt_can_fill_and_stroke(job->ppp)) { dk4pppt_prepare_fill_and_stroke(job->ppp, backptr, erp); wxd2lah_ah_path_real_arc( arrow, job, pobj, s, 0, ah, csgn, lw, backptr, erp ); dk4pppt_fill_and_stroke(job->ppp, backptr, erp); } else { dk4pppt_prepare_fill(job->ppp, backptr, erp); wxd2lah_ah_path_real_arc( arrow, job, pobj, s, 0, ah, csgn, lw, backptr, erp ); dk4pppt_fill(job->ppp, backptr, erp); dk4pppt_prepare_stroke(job->ppp, backptr, erp); wxd2lah_ah_path_real_arc( arrow, job, pobj, s, 0, ah, csgn, lw, backptr, erp ); dk4pppt_stroke(job->ppp, backptr, erp); } } break; case 4: case 5: case 8: case 9: case 12: case 13: case 16: case 17: case 20: case 21: case 25: case 26: { /* Half-side filled arrowheads */ dk4pppt_set_fill_rgb(job->ppp, 1.0, 1.0, 1.0, backptr, erp); if (0 != dk4pppt_can_fill_and_stroke(job->ppp)) { dk4pppt_prepare_fill_and_stroke(job->ppp, backptr, erp); wxd2lah_ah_path_real_arc( arrow, job, pobj, s, 0, ah, csgn, lw, backptr, erp ); dk4pppt_fill_and_stroke(job->ppp, backptr, erp); } else { dk4pppt_prepare_fill(job->ppp, backptr, erp); wxd2lah_ah_path_real_arc( arrow, job, pobj, s, 0, ah, csgn, lw, backptr, erp ); dk4pppt_fill(job->ppp, backptr, erp); dk4pppt_prepare_stroke(job->ppp, backptr, erp); wxd2lah_ah_path_real_arc( arrow, job, pobj, s, 0, ah, csgn, lw, backptr, erp ); dk4pppt_stroke(job->ppp, backptr, erp); } dk4pppt_set_fill_rgb( job->ppp, ((double)(pobj->sc[0]) / 255.0), ((double)(pobj->sc[1]) / 255.0), ((double)(pobj->sc[2]) / 255.0), backptr, erp ); dk4pppt_prepare_fill(job->ppp, backptr, erp); wxd2lah_ah_path_real_arc( arrow, job, pobj, s, 1, ah, csgn, lw, backptr, erp ); dk4pppt_fill(job->ppp, backptr, erp); } break; } $? "- wxd2lah_ah_real_arc" } /** Draw one arrowhead on malformed arc. @param arrow Arrowhead structure. @param drw Drawing structure. @param job Job structure. @param obj Object arrow belongs to. @param isbck Flag: Is a backward arrow. @param backptr Address of success variable to reset on error. @param erp Error report, may be NULL. */ static void wxd2lah_ah_malformed_arc( wxd_arrow_t *arrow, wxd_drawing_t *drw, wxd2lat_job_t *job, wxd_object_t *pobj, int isbck, int *backptr, dk4_er_t *erp ) { dk4_gra_point_t p[8]; /* Points to construct arrowhead path */ dk4_gra_point_t orig; /* Original end point of line */ dk4_gra_point_t head; /* Shifted end point for arrowhead */ double lw; /* Line width */ double alpha; /* Rotation angle in end point */ $? "+ wxd2lah_ah_malformed_arc" lw = wxd2lat_object_linewidth(pobj, drw, job); if ( ((1 != isbck) && (0 != (pobj->ab).type)) || ((0 != isbck) && (0 != (pobj->af).type)) ) { if ( (0 != isbck) && ( ((pobj->det).a.x1 != (pobj->det).a.x2) || ((pobj->det).a.y1 != (pobj->det).a.y2) ) ) { alpha = atan2( ((double)((pobj->det).a.y1 - (pobj->det).a.y2)), ((double)((pobj->det).a.x1 - (pobj->det).a.x2)) ); orig.x = wxd2lout_convert_x(drw, job, (double)((pobj->det).a.x1)); orig.y = wxd2lout_convert_x(drw, job, (double)((pobj->det).a.y1)); if (0 != dk4ma_is_finite(alpha)) { head.x = 0.0 - arrow->offset; head.y = 0.0; dk4gratool_rotate_point(&head, alpha); head.x += orig.x; head.y += orig.y; wxd2lah_ah_head_angle_polyline( arrow, job, pobj, p, &head, alpha, lw, backptr, erp ); } } if ( (0 == isbck) && ( ((pobj->det).a.x3 != (pobj->det).a.x2) || ((pobj->det).a.y3 != (pobj->det).a.y2) ) ) { alpha = atan2( ((double)((pobj->det).a.y3 - (pobj->det).a.y2)), ((double)((pobj->det).a.x3 - (pobj->det).a.x2)) ); orig.x = wxd2lout_convert_x(drw, job, (double)((pobj->det).a.x3)); orig.y = wxd2lout_convert_x(drw, job, (double)((pobj->det).a.y3)); if (0 != dk4ma_is_finite(alpha)) { head.x = 0.0 - arrow->offset; head.y = 0.0; dk4gratool_rotate_point(&head, alpha); head.x += orig.x; head.y += orig.y; wxd2lah_ah_head_angle_polyline( arrow, job, pobj, p, &head, alpha, lw, backptr, erp ); } } } $? "- wxd2lah_ah_malformed_arc" } /** Draw one arrowhead on arc. @param arrow Arrowhead structure. @param drw Drawing structure. @param job Job structure. @param obj Object arrow belongs to. @param isbck Flag: Is a backward arrow. @param backptr Address of success variable to reset on error. @param erp Error report, may be NULL. */ static void wxd2lah_ah_arc( wxd_arrow_t *arrow, wxd_drawing_t *drw, wxd2lat_job_t *job, wxd_object_t *pobj, int isbck, int *backptr, dk4_er_t *erp ) { $? "+ wxd2lah_ah_arc" if (0 != (pobj->det).a.d) { wxd2lah_ah_real_arc(arrow, drw, job, pobj, isbck, backptr, erp); } else { wxd2lah_ah_malformed_arc(arrow, drw, job, pobj, isbck, backptr, erp); } $? "- wxd2lah_ah_arc" } /** Calculate number points for spline arrowhead, allocate memory. @param s Spline arrowhead structure to fill. @param arrow Arrowhead structure. @param drw Drawing structure. @param job Job structure. @param obj Object arrow belongs to. @param isbck Flag: Is a backward arrow. @param backptr Address of success variable to reset on error. @param erp Error report, may be NULL. @return 1 on success, 0 on error. */ static int wxd2lah_sp_ah_npoints( sp_ah_t *s, wxd_arrow_t *arrow, wxd2lat_job_t *job, wxd_object_t *pobj, int isbck, dk4_er_t *erp ) { dk4_er_t er; #if 0 double l; #endif double t; size_t np; int back = 0; int res = 0; int res2 = 0; int e_o = 0; /* Overflow */ int e_i = 0; /* Iteration */ int e_m = 0; /* Memory allocation */ $? "+ wxd2lah_sp_ah_npoints" dk4error_init(&er); if (0 != isbck) { $? ". backward" s->csgn = 1.0; s->lo = arrow->offset; } else { $? ". forward" s->csgn = -1.0; s->lo = (pobj->det).s.suml - arrow->offset; } t = 0.0; res = wxd2lxs_parameter_for_length( &t, pobj, s->lo, (job->grco).xslp, (job->grco).xspp, &er ); if (0 != res) { $? ". t_offset = %g", t s->to = t; switch (arrow->type) { case 1: case 2: case 3: { $? ". arrow type 1" s->lb = s->lo + s->csgn * (double)(arrow->length) * s->lw; t = 0.0; res = wxd2lxs_parameter_for_length( &t, pobj, s->lb, (job->grco).xslp, (job->grco).xspp, &er ); if (0 != res) { $? ". t_back = %g", t s->tb = t; s->nf = dk4ma_size_t_from_double( ceil(fabs(s->tb - s->to) * (double)((job->grco).xsss)), &er ); $? ". delta_t = %g", fabs(s->tb - s->to) if (DK4_E_NONE == er.ec) { if (2 > s->nf) { s->nf = 2; } } $? ". nf = %u", (unsigned)(s->nf) s->ifr = dk4ma_size_t_add(s->nf, 1, &er); np = dk4ma_size_t_mul(s->ifr, 2, &er); s->ibl = np; $? ". np = %u", (unsigned)np if (DK4_E_NONE == er.ec) { $? ". size calc" s->ppoints = dk4mem_new(wxd_point_t,np,&er); if (NULL != s->ppoints) { $? ". allocation" back = 1; } else { $? "! allocation" e_m = 1; } } else { $? "! size calculation" e_o = 1; } } else { $? "! parameter for length" e_i = 1; } } break; case 4: case 5: { s->lb = s->lo + s->csgn * (double)(arrow->length) * s->lw; t = 0.0; res = wxd2lxs_parameter_for_length( &t, pobj, s->lb, (job->grco).xslp, (job->grco).xspp, &er ); if (0 != res) { $? ". t_back = %g", t s->tb = t; s->nf = dk4ma_size_t_from_double( ceil(fabs(s->tb - s->to) * (double)((job->grco).xsss)), &er ); $? ". delta_t = %g", fabs(s->tb - s->to) if (DK4_E_NONE == er.ec) { if (2 > s->nf) { s->nf = 2; } } $? ". nf = %u", (unsigned)(s->nf) s->nc = s->nf; s->ifr = dk4ma_size_t_add(s->nf, 1, &er); s->ic = dk4ma_size_t_mul(s->ifr, 2, &er); np = dk4ma_size_t_mul(s->ifr, 3, &er); s->ibl = np; $? ". np = %u", (unsigned)np if (DK4_E_NONE == er.ec) { $? ". size calc" s->ppoints = dk4mem_new(wxd_point_t,np,&er); if (NULL != s->ppoints) { $? ". allocation" back = 1; } else { $? "! allocation" e_m = 1; } } else { $? "! size calculation" e_o = 1; } } else { $? "! parameter for length" e_i = 1; } } break; case 6: case 7: case 8: case 9: case 10: case 11: case 12: case 13: case 14: case 15: case 16: case 17: { $? ". arrow type 6/7/8/9" switch (arrow->type) { case 6: case 7: case 8: case 9: { s->lb = s->lo + s->csgn * (double)(arrow->length) * s->lw; s->lc = s->lo + 0.75 * s->csgn * (double)(arrow->length) * s->lw; } break; case 10: case 11: case 12: case 13: { s->lb = s->lo + 0.75 * s->csgn * (double)(arrow->length) * s->lw; s->lc = s->lo + s->csgn * (double)(arrow->length) * s->lw; } break; case 14: case 15: case 16: case 17: { s->lb = s->lo + 0.5 * s->csgn * (double)(arrow->length) * s->lw; s->lc = s->lo + s->csgn * (double)(arrow->length) * s->lw; } break; } t = 0.0; res = wxd2lxs_parameter_for_length( &t, pobj, s->lb, (job->grco).xslp, (job->grco).xspp, &er ); s->tb = t; t = 0.0; res2 = wxd2lxs_parameter_for_length( &t, pobj, s->lc, (job->grco).xslp, (job->grco).xspp, &er ); s->tc = t; if ((0 != res) && (0 != res2)) { $? ". t_back = %g", t s->nf = dk4ma_size_t_from_double( ceil(fabs(s->tb - s->to) * (double)((job->grco).xsss)), &er ); $? ". delta_t = %g", fabs(s->tb - s->to) s->nb = dk4ma_size_t_from_double( ceil(fabs(s->tb - s->tc) * (double)((job->grco).xsss)), &er ); switch (arrow->type) { case 8: case 9: case 12: case 13: case 16: case 17: { s->nc = dk4ma_size_t_from_double( ceil( fabs( (s->tc - s->to) * (double)((job->grco).xsss) ) ), &er ); } break; } if (DK4_E_NONE == er.ec) { if (2 > s->nf) { s->nf = 2; } if (2 > s->nb) { s->nb = 2; } switch (arrow->type) { case 8: case 9: case 12: case 13: case 16: case 17: { if (2 > s->nc) { s->nc = 2; } } break; } } $? ". nf = %u", (unsigned)(s->nf) s->ifr = dk4ma_size_t_add(s->nf, 1, &er); s->ibl = dk4ma_size_t_mul(s->ifr, 2, &er); s->ibr = dk4ma_size_t_add(s->ibl, s->nb, &er); s->ibr = dk4ma_size_t_add(s->ibr, 1, &er); np = dk4ma_size_t_add(s->nf, s->nb, &er); np = dk4ma_size_t_add(np, 2, &er); np = dk4ma_size_t_mul(np, 2, &er); switch (arrow->type) { case 8: case 9: case 12: case 13: case 16: case 17: { s->ic = np; np = dk4ma_size_t_add(np, s->nc, &er); np = dk4ma_size_t_add(np, 1, &er); } break; } $? ". nf = %u", (unsigned)(s->nf) $? ". nb = %u", (unsigned)(s->nb) #if TRACE_DEBUG switch (arrow->type) { case 8: case 9: case 12: case 13: case 16: case 17: { $? ". nc = %u", (unsigned)(s->nc) } break; } #endif $? ". ifl = %u", (unsigned)(s->ifl) $? ". ifr = %u", (unsigned)(s->ifr) $? ". ibl = %u", (unsigned)(s->ibl) $? ". ibr = %u", (unsigned)(s->ibr) #if TRACE_DEBUG switch (arrow->type) { case 8: case 9: case 12: case 13: case 16: case 17: { $? ". ic = %u", (unsigned)(s->ic) } break; } #endif $? ". np = %u", (unsigned)np if (DK4_E_NONE == er.ec) { $? ". size calc" s->ppoints = dk4mem_new(wxd_point_t,np,&er); if (NULL != s->ppoints) { $? ". allocation" back = 1; } else { $? "! allocation" e_m = 1; } } else { $? "! size calculation" e_o = 1; } } else { $? "! parameter for length" e_i = 1; } } break; case 18: case 19: case 20: case 21: case 22: { s->lb = s->lo + s->csgn * (double)(arrow->length) * s->lw; t = 0.0; res = wxd2lxs_parameter_for_length( &t, pobj, s->lb, (job->grco).xslp, (job->grco).xspp, &er ); s->tb = t; s->nf = dk4ma_size_t_from_double( ceil(fabs(s->tb - s->to) * (double)((job->grco).xsss)), &er ); if (0 != res) { if (DK4_E_NONE == er.ec) { if (2 > s->nf) { s->nf = 2; } s->ifr = dk4ma_size_t_add(s->nf, 1, &er); np = dk4ma_size_t_mul(s->ifr, 2, &er); switch (arrow->type) { case 20: case 21: { s->ic = np; np = dk4ma_size_t_mul(s->ifr, 3, &er); } break; } if (DK4_E_NONE == er.ec) { s->ppoints = dk4mem_new(wxd_point_t,np,&er); if (NULL != s->ppoints) { $? ". allocation" back = 1; } else { $? "! allocation" e_m = 1; } } else { $? "! overflow" e_o = 1; } } else { $? "! calculation" e_o = 1; } } else { e_i = 1; } } break; case 23: case 24: case 25: case 26: { s->lb = s->lo + s->csgn * (double)(arrow->length) * s->lw; t = 0.0; res = wxd2lxs_parameter_for_length( &t, pobj, s->lb, (job->grco).xslp, (job->grco).xspp, &er ); if (0 != res) { s->tb = t; s->nf = dk4ma_size_t_from_double( ceil(fabs(s->tb - s->to) * (double)((job->grco).xsss)), &er ); if (DK4_E_NONE == er.ec) { if (2 > s->nf) { s->nf = 2; } s->ifr = dk4ma_size_t_add(s->nf, 1, &er); np = dk4ma_size_t_mul(s->ifr, 2, &er); switch (arrow->type) { case 25: case 26: { s->ic = np; np = dk4ma_size_t_mul(s->ifr, 3, &er); } break; } if (DK4_E_NONE == er.ec) { s->ppoints = dk4mem_new(wxd_point_t,np,&er); if (NULL != s->ppoints) { $? ". allocation" back = 1; } else { e_m = 1; } } else { $? "! overflow" e_o = 1; } } else { $? "! overflow" e_o = 1; } } else { $? "! iteration" e_i = 1; } } break; case 27: case 28: case 29: { back = 1; } break; default: { $? "! unhandled arrow type" /* ERROR: Unknown arrow type */ dk4app_log_1( job->app, job->msg, job->sz_msg, DK4_LL_ERROR, 29 ); } break; } } else { $? "! parameter for length" e_i = 1; } if (DK4_E_NONE != er.ec) { back = 0; dk4error_copy(erp, &er); } if (0 == back) { if (0 != e_o) { /* ERROR: Math overflow */ dk4app_log_1( job->app, job->msg, job->sz_msg, DK4_LL_ERROR, 30 ); } if (0 != e_i) { /* ERROR: Iteration failed */ dk4app_log_1( job->app, job->msg, job->sz_msg, DK4_LL_ERROR, 31 ); } if (0 != e_m) { /* ERROR: Memory allocation failed */ dk4app_log_1( job->app, job->msg, job->sz_msg, DK4_LL_ERROR, 32 ); } if ((0 == e_o) && (0 == e_i) && (0 == e_m)) { /* ERROR: Failed to calculate number of points */ dk4app_log_1( job->app, job->msg, job->sz_msg, DK4_LL_ERROR, 33 ); } } $? "- wxd2lah_sp_ah_npoints %d", back return back; } /** Calculate points for spline arrowhead. @param s Spline arrowhead structure to fill. @param arrow Arrowhead structure. @param drw Drawing structure. @param job Job structure. @param obj Object arrow belongs to. @param isbck Flag: Is a backward arrow. @param backptr Address of success variable to reset on error. @param erp Error report, may be NULL. */ static int wxd2lah_sp_ah_calc( sp_ah_t *s, wxd_arrow_t *arrow, wxd2lat_job_t *job, wxd_object_t *pobj, int isbck, int *backptr, dk4_er_t *erp ) { dk4_er_t er; double v[4]; dk4_gra_point_t p; size_t i; double t; double l; int back = 0; int res = 0; int e_i = 0; int e_o = 0; int e_m = 0; $? "+ wxd2lah_sp_ah_calc" /* TODO: Implementation */ dk4error_init(&er); if (0 != wxd2lah_sp_ah_npoints(s,arrow,job,pobj,isbck,erp)) { switch (arrow->type) { case 1: case 2: case 3: { back = 1; for (i = 0; i < s->ifr; i++) { if (0 == i) { t = s->tb; } else { if ((s->ifr - 1) == i) { t = s->to; } else { l = wxd2lah_partial_length(s->lb,s->lo,i,(s->ifr - 1)); t = 0.0; res = wxd2lxs_parameter_for_length( &t, pobj, l, (job->grco).xslp, (job->grco).xspp, &er ); if (0 == res) { back = 0; e_i = 1; } } } if (1 == back) { res = wxd2lxs_calculate(v, pobj, t, 1, &er); if (0 != res) { $? ". x = %g", v[0] $? ". y = %g", v[1] if (0.0 < s->csgn) { v[2] += M_PI; } if ((s->ifr - 1) > i) { p.x = 0.0; p.y = ((double)(arrow->width) / 2.0) * (1.0 - ((double)i)/(s->ifr - 1)); dk4gratool_rotate_point(&p, v[2]); p.x += v[0]; p.y += v[1]; DK4_MEMCPY(&((s->ppoints)[i]),&p,sizeof(p)); p.x = 0.0; p.y = 0.0 - ((double)(arrow->width) / 2.0) * (1.0 - ((double)i)/(s->ifr - 1)); dk4gratool_rotate_point(&p, v[2]); p.x += v[0]; p.y += v[1]; DK4_MEMCPY(&((s->ppoints)[i+s->ifr]),&p,sizeof(p)); } else { p.x = v[0]; p.y = v[1]; DK4_MEMCPY(&((s->ppoints)[i]),&p,sizeof(p)); DK4_MEMCPY(&((s->ppoints)[i+s->ifr]),&p,sizeof(p)); } } else { back = 0; e_m = 1; } } } } break; case 4: case 5: { back = 1; for (i = 0; i < s->ifr; i++) { if (0 == i) { t = s->tb; } else { if ((s->ifr - 1) == i) { t = s->to; } else { l = wxd2lah_partial_length(s->lb,s->lo,i,(s->ifr - 1)); t = 0.0; res = wxd2lxs_parameter_for_length( &t, pobj, l, (job->grco).xslp, (job->grco).xspp, &er ); if (0 == res) { back = 0; e_i = 1; } } } if (1 == back) { res = wxd2lxs_calculate(v, pobj, t, 1, &er); if (0 != res) { $? ". x = %g", v[0] $? ". y = %g", v[1] (s->ppoints)[i + s->ic].x = v[0]; (s->ppoints)[i + s->ic].y = v[1]; if (0.0 < s->csgn) { v[2] += M_PI; } if ((s->ifr - 1) > i) { p.x = 0.0; p.y = ((double)(arrow->width) / 2.0) * (1.0 - ((double)i)/(s->ifr - 1)); dk4gratool_rotate_point(&p, v[2]); p.x += v[0]; p.y += v[1]; DK4_MEMCPY(&((s->ppoints)[i]),&p,sizeof(p)); p.x = 0.0; p.y = 0.0 - ((double)(arrow->width) / 2.0) * (1.0 - ((double)i)/(s->ifr - 1)); dk4gratool_rotate_point(&p, v[2]); p.x += v[0]; p.y += v[1]; DK4_MEMCPY(&((s->ppoints)[i+s->ifr]),&p,sizeof(p)); } else { p.x = v[0]; p.y = v[1]; DK4_MEMCPY(&((s->ppoints)[i]),&p,sizeof(p)); DK4_MEMCPY(&((s->ppoints)[i+s->ifr]),&p,sizeof(p)); } } else { back = 0; e_m = 1; } } } } break; case 6: case 7: case 8: case 9: case 10: case 11: case 12: case 13: case 14: case 15: case 16: case 17: { back = 1; for (i = 0; i < s->ifr; i++) { if (0 == i) { t = s->tb; } else { if ((s->ifr - 1) == i) { t = s->to; } else { l = wxd2lah_partial_length(s->lb,s->lo,i,(s->ifr - 1)); t = 0.0; res = wxd2lxs_parameter_for_length( &t, pobj, l, (job->grco).xslp, (job->grco).xspp, &er ); if (0 == res) { back = 0; e_i = 1; } } } if (1 == back) { res = wxd2lxs_calculate(v, pobj, t, 1, &er); if (0 != res) { $? ". i = %u", (unsigned)(i + s->ic) $? ". x = %g", v[0] $? ". y = %g", v[1] if (0.0 < s->csgn) { v[2] += M_PI; } if ((s->ifr - 1) > i) { p.x = 0.0; p.y = ((double)(arrow->width) / 2.0) * (1.0 - ((double)i)/(s->ifr - 1)); dk4gratool_rotate_point(&p, v[2]); p.x += v[0]; p.y += v[1]; $? ". i = %u", (unsigned)i DK4_MEMCPY(&((s->ppoints)[i]),&p,sizeof(p)); p.x = 0.0; p.y = 0.0 - ((double)(arrow->width) / 2.0) * (1.0 - ((double)i)/(s->ifr - 1)); dk4gratool_rotate_point(&p, v[2]); p.x += v[0]; p.y += v[1]; $? ". i = %u", (unsigned)(i + s->ifr) DK4_MEMCPY(&((s->ppoints)[i+s->ifr]),&p,sizeof(p)); } else { p.x = v[0]; p.y = v[1]; $? ". i = %u", (unsigned)i $? ". i = %u", (unsigned)(i + s->ifr) DK4_MEMCPY(&((s->ppoints)[i]),&p,sizeof(p)); DK4_MEMCPY(&((s->ppoints)[i+s->ifr]),&p,sizeof(p)); } } else { back = 0; e_m = 1; } } } for (i = 0; i <= s->nb; i++) { if (0 == i) { t = s->tb; } else { if (s->nb == i) { t = s->tc; } else { l = s->lb + ((s->lc - s->lb) * (double)i) / ((double)(s->nb)); t = 0.0; res = wxd2lxs_parameter_for_length( &t, pobj, l, (job->grco).xslp, (job->grco).xspp, &er ); if (0 == res) { back = 0; e_i = 1; } } } if (0 != back) { res = wxd2lxs_calculate(v, pobj, t, 1, &er); if (0 != res) { $? ". x = %g", v[0] $? ". y = %g", v[1] if (0.0 < s->csgn) { v[2] += M_PI; } if (s->nb != i) { p.x = 0.0; p.y = ((double)(arrow->width) / 2.0) * (1.0 - ((double)i)/(s->nb)); dk4gratool_rotate_point(&p, v[2]); p.x += v[0]; p.y += v[1]; $? ". i = %u", (unsigned)(i + s->ibl) DK4_MEMCPY(&((s->ppoints)[i+s->ibl]),&p,sizeof(p)); p.x = 0.0; p.y = 0.0 - ((double)(arrow->width) / 2.0) * (1.0 - ((double)i)/(s->nb)); dk4gratool_rotate_point(&p, v[2]); p.x += v[0]; p.y += v[1]; $? ". i = %u", (unsigned)(i + s->ibr) DK4_MEMCPY(&((s->ppoints)[i+s->ibr]),&p,sizeof(p)); } else { p.x = v[0]; p.y = v[1]; $? ". i = %u", (unsigned)(i + s->ibl) $? ". i = %u", (unsigned)(i + s->ibr) DK4_MEMCPY(&((s->ppoints)[i+s->ibl]),&p,sizeof(p)); DK4_MEMCPY(&((s->ppoints)[i+s->ibr]),&p,sizeof(p)); } } else { back = 0; e_m = 1; } } } switch (arrow->type) { case 8: case 9: case 12: case 13: case 16: case 17: { for (i = 0; i <= s->nc; i++) { if (0 == i) { t = s->tc; } else { if (s->nc == i) { t = s->to; } else { l = wxd2lah_partial_length( s->lc, s->lo, i, (s->nc) ); t = 0.0; res = wxd2lxs_parameter_for_length( &t, pobj, l, (job->grco).xslp, (job->grco).xspp, &er ); if (0 == res) { back = 0; e_i = 1; } } } if (0 != back) { res = wxd2lxs_calculate(v, pobj, t, 1, &er); if (0 != res) { $? ". x = %g", v[0] $? ". y = %g", v[1] $? ". i = %u", (unsigned)(i + s->ic) (s->ppoints)[i + s->ic].x = v[0]; (s->ppoints)[i + s->ic].y = v[1]; } else { back = 0; e_m = 1; } } } } break; } } break; case 18: case 19: case 20: case 21: case 22: { back = 1; for (i = 0; i < s->ifr; i++) { if (0 == i) { t = s->tb; } else { if ((s->ifr - 1) == i) { t = s->to; } else { l = wxd2lah_partial_length(s->lb,s->lo,i,(s->ifr - 1)); t = 0.0; res = wxd2lxs_parameter_for_length( &t, pobj, l, (job->grco).xslp, (job->grco).xspp, &er ); if (0 == res) { back = 0; e_i = 1; } } } if (0 != back) { res = wxd2lxs_calculate(v, pobj, t, 1, &er); if (0 != res) { if (0.0 < s->csgn) { v[2] += M_PI; } p.x = 0.0; p.y = ((double)(arrow->width) / 2.0); dk4gratool_rotate_point(&p, v[2]); p.x += v[0]; p.y += v[1]; DK4_MEMCPY(&((s->ppoints)[i]),&p,sizeof(p)); p.x = 0.0; p.y = 0.0 - ((double)(arrow->width) / 2.0); dk4gratool_rotate_point(&p, v[2]); p.x += v[0]; p.y += v[1]; DK4_MEMCPY(&((s->ppoints)[i + s->ifr]),&p,sizeof(p)); switch (arrow->type) { case 20: case 21: { (s->ppoints)[i + s->ic].x = v[0]; (s->ppoints)[i + s->ic].y = v[1]; } break; } } else { back = 0; e_m = 1; } } } } break; case 23: case 24: case 25: case 26: { back = 1; for (i = 0; i < s->ifr; i++) { if (0 == i) { t = s->tb; } else { if ((s->ifr - 1) == i) { t = s->to; } else { l = wxd2lah_partial_length(s->lb,s->lo,i,(s->ifr - 1)); t = 0.0; res = wxd2lxs_parameter_for_length( &t, pobj, l, (job->grco).xslp, (job->grco).xspp, &er ); if (0 == res) { back = 0; e_i = 1; } } } if (0 != back) { res = wxd2lxs_calculate(v, pobj, t, 1, &er); if (0 != res) { switch (arrow->type) { case 25: case 26: { (s->ppoints)[i + s->ic].x = v[0]; (s->ppoints)[i + s->ic].y = v[1]; } break; } if (0.0 < s->csgn) { v[2] += M_PI; } p.x = 0.0; p.y = (((double)(arrow->width) / 2.0) * (double)i) / ((double)(s->ifr - 1)); dk4gratool_rotate_point(&p, v[2]); p.x += v[0]; p.y += v[1]; DK4_MEMCPY(&((s->ppoints)[i]),&p,sizeof(p)); p.x = 0.0; p.y = 0.0 - (((double)(arrow->width) / 2.0) * (double)i) / ((double)(s->ifr - 1)); dk4gratool_rotate_point(&p, v[2]); p.x += v[0]; p.y += v[1]; DK4_MEMCPY(&((s->ppoints)[i + s->ifr]),&p,sizeof(p)); } else { back = 0; e_m = 1; } } } } break; case 27: case 28: { res = wxd2lxs_calculate(v, pobj, s->to, 1, &er); if (0 != res) { if (0.0 < s->csgn) { v[2] += M_PI; } p.y = 0.0; p.x = 0.0 - (((double)(arrow->length) * s->lw) / 2.0); dk4gratool_rotate_point(&p, v[2]); p.x += v[0]; p.y += v[1]; s->x0 = p.x; s->y0 = p.y; back = 1; } else { e_m = 1; } } break; case 29: { res = wxd2lxs_calculate(v, pobj, s->to, 1, &er); if (0 != res) { if (0.0 < s->csgn) { v[2] += M_PI; } p.x = 0.0; p.y = (s->lw * (double)(arrow->width)) / 2.0; dk4gratool_rotate_point(&p, v[2]); p.x += v[0]; p.y += v[1]; s->x0 = p.x; s->y0 = p.y; p.x = 0.0; p.y = 0.0 - ((s->lw * (double)(arrow->width)) / 2.0); dk4gratool_rotate_point(&p, v[2]); p.x += v[0]; p.y += v[1]; s->x1 = p.x; s->y1 = p.y; back = 1; } else { e_m = 1; } } break; } } if (0 == back) { *backptr = 0; if (0 != e_i) { /* ERROR: Iteration failed */ dk4app_log_1( job->app, job->msg, job->sz_msg, DK4_LL_ERROR, 31 ); } if (0 != e_o) { /* ERROR: Numeric overflow */ dk4app_log_1( job->app, job->msg, job->sz_msg, DK4_LL_ERROR, 30 ); } if (0 != e_m) { /* ERROR: Mathematical problem */ dk4app_log_1( job->app, job->msg, job->sz_msg, DK4_LL_ERROR, 34 ); } if ((0 == e_i) && (0 == e_o)) { /* ERROR: Arrowhead calculation on spline failed */ dk4app_log_1( job->app, job->msg, job->sz_msg, DK4_LL_ERROR, 35 ); } } $? "- wxd2lah_sp_ah_calc %d", back return back; } /** Draw one arrowhead on spline. @param arrow Arrowhead structure. @param job Job structure. @param pobj Object arrow belongs to. @param s Spline structure to use. @param stage Processing stage. @param backptr Address of success variable to reset on error. @param erp Error report, may be NULL. */ static void wxd2lah_sp_ah_path( wxd_arrow_t *arrow, wxd2lat_job_t *job, sp_ah_t *s, int stage, int *backptr, dk4_er_t *erp ) { size_t ss; $? "+ wxd2lah_sp_ah_path" switch (arrow->type) { case 1: { $? ". known arrow type" wxd2lah_sp_ah_bspline( job, s, 0, s->ifr, 0, 1, backptr, erp ); wxd2lah_sp_ah_bspline( job, s, s->ifr, s->ifr, 1, 0, backptr, erp ); } break; case 2: case 3: { wxd2lah_sp_ah_bspline( job, s, 0, s->ifr, 0, 1, backptr, erp ); wxd2lah_sp_ah_bspline( job, s, s->ifr, s->ifr, 1, 0, backptr, erp ); dk4pppt_lineto( job->ppp,(s->ppoints)[0].x,(s->ppoints)[0].y,NULL,backptr,erp ); dk4pppt_closepath(job->ppp, backptr, erp); } break; case 4: { if (0 == stage) { wxd2lah_sp_ah_bspline( job, s, 0, s->ifr, 0, 1, backptr, erp ); wxd2lah_sp_ah_bspline( job, s, s->ifr, s->ifr, 1, 0, backptr, erp ); dk4pppt_lineto( job->ppp, (s->ppoints)[0].x, (s->ppoints)[0].y, NULL,backptr,erp ); dk4pppt_closepath(job->ppp, backptr, erp); } else { wxd2lah_sp_ah_bspline( job, s, 0, s->ifr, 0, 1, backptr, erp ); wxd2lah_sp_ah_bspline( job, s, s->ic, s->ifr, 1, 0, backptr, erp ); dk4pppt_lineto( job->ppp, (s->ppoints)[0].x, (s->ppoints)[0].y, NULL,backptr,erp ); dk4pppt_closepath(job->ppp, backptr, erp); } } break; case 5: { if (0 == stage) { wxd2lah_sp_ah_bspline( job, s, 0, s->ifr, 0, 1, backptr, erp ); wxd2lah_sp_ah_bspline( job, s, s->ifr, s->ifr, 1, 0, backptr, erp ); dk4pppt_lineto( job->ppp, (s->ppoints)[0].x, (s->ppoints)[0].y, NULL,backptr,erp ); dk4pppt_closepath(job->ppp, backptr, erp); } else { wxd2lah_sp_ah_bspline( job, s, s->ic, s->ifr, 0, 1, backptr, erp ); wxd2lah_sp_ah_bspline( job, s, s->ifr, s->ifr, 1, 0, backptr, erp ); dk4pppt_lineto( job->ppp, (s->ppoints)[s->ic].x, (s->ppoints)[s->ic].y, NULL,backptr,erp ); dk4pppt_closepath(job->ppp, backptr, erp); } } break; case 6: case 7: case 10: case 11: case 14: case 15: { wxd2lah_sp_ah_bspline( job, s, 0, s->ifr, 0, 1, backptr, erp ); wxd2lah_sp_ah_bspline( job, s, s->ifr, (s->nf + 1), 1, 0, backptr, erp ); wxd2lah_sp_ah_bspline( job, s, s->ibr, (s->nb + 1), 0, 0, backptr, erp ); wxd2lah_sp_ah_bspline( job, s, s->ibl, (s->nb + 1), 1, 0, backptr, erp ); dk4pppt_closepath(job->ppp, backptr, erp); } break; case 8: case 12: case 16: { if (0 == stage) { wxd2lah_sp_ah_bspline( job, s, 0, s->ifr, 0, 1, backptr, erp ); wxd2lah_sp_ah_bspline( job, s, s->ifr, (s->nf + 1), 1, 0, backptr, erp ); wxd2lah_sp_ah_bspline( job, s, s->ibr, (s->nb + 1), 0, 0, backptr, erp ); wxd2lah_sp_ah_bspline( job, s, s->ibl, (s->nb + 1), 1, 0, backptr, erp ); dk4pppt_closepath(job->ppp, backptr, erp); } else { wxd2lah_sp_ah_bspline( job, s, 0, s->ifr, 0, 1, backptr, erp ); wxd2lah_sp_ah_bspline( job, s, s->ic, (1 + s->nc), 1, 0, backptr, erp ); wxd2lah_sp_ah_bspline( job, s, s->ibl, (1 + s->nb), 1, 0, backptr, erp ); dk4pppt_closepath(job->ppp, backptr, erp); } } break; case 9: case 13: case 17: { if (0 == stage) { wxd2lah_sp_ah_bspline( job, s, 0, s->ifr, 0, 1, backptr, erp ); wxd2lah_sp_ah_bspline( job, s, s->ifr, (s->nf + 1), 1, 0, backptr, erp ); wxd2lah_sp_ah_bspline( job, s, s->ibr, (s->nb + 1), 0, 0, backptr, erp ); wxd2lah_sp_ah_bspline( job, s, s->ibl, (s->nb + 1), 1, 0, backptr, erp ); dk4pppt_closepath(job->ppp, backptr, erp); } else { wxd2lah_sp_ah_bspline( job, s, s->ifr, s->ifr, 0, 1, backptr, erp ); wxd2lah_sp_ah_bspline( job, s, s->ic, (1 + s->nc), 1, 0, backptr, erp ); wxd2lah_sp_ah_bspline( job, s, s->ibr, (1 + s->nb), 1, 0, backptr, erp ); dk4pppt_closepath(job->ppp, backptr, erp); } } break; case 18: case 19: { wxd2lah_sp_ah_bspline( job, s, 0, s->ifr, 0, 1, backptr, erp ); dk4pppt_lineto( job->ppp, (s->ppoints)[s->nf + s->ifr].x, (s->ppoints)[s->nf + s->ifr].y, NULL, backptr, erp ); wxd2lah_sp_ah_bspline( job, s, s->ifr, s->ifr, 1, 0, backptr, erp ); dk4pppt_lineto( job->ppp, (s->ppoints)[0].x, (s->ppoints)[0].y, NULL, backptr, erp ); dk4pppt_closepath(job->ppp, backptr, erp); } break; case 20: case 21: { if (0 == stage) { wxd2lah_sp_ah_bspline( job, s, 0, s->ifr, 0, 1, backptr, erp ); dk4pppt_lineto( job->ppp, (s->ppoints)[s->nf + s->ifr].x, (s->ppoints)[s->nf + s->ifr].y, NULL, backptr, erp ); wxd2lah_sp_ah_bspline( job, s, s->ifr, s->ifr, 1, 0, backptr, erp ); dk4pppt_lineto( job->ppp, (s->ppoints)[0].x, (s->ppoints)[0].y, NULL, backptr, erp ); dk4pppt_closepath(job->ppp, backptr, erp); } else { ss = ((21 == arrow->type) ? (s->ifr) : (0)); wxd2lah_sp_ah_bspline( job, s, ss, s->ifr, 0, 1, backptr, erp ); dk4pppt_lineto( job->ppp, (s->ppoints)[s->nf + s->ic].x, (s->ppoints)[s->nf + s->ic].y, NULL, backptr, erp ); wxd2lah_sp_ah_bspline( job, s, s->ic, s->ifr, 1, 0, backptr, erp ); dk4pppt_lineto( job->ppp, (s->ppoints)[ss].x, (s->ppoints)[ss].y, NULL, backptr, erp ); dk4pppt_closepath(job->ppp, backptr, erp); } } break; case 22 : { wxd2lah_sp_ah_bspline( job, s, 0, s->ifr, 0, 1, backptr, erp ); dk4pppt_lineto( job->ppp, (s->ppoints)[s->nf + s->ifr].x, (s->ppoints)[s->nf + s->ifr].y, NULL, backptr, erp ); wxd2lah_sp_ah_bspline( job, s, s->ifr, s->ifr, 1, 0, backptr, erp ); } break; case 23: case 24: { wxd2lah_sp_ah_bspline( job, s, 0, s->ifr, 0, 1, backptr, erp ); dk4pppt_lineto( job->ppp, (s->ppoints)[s->nf + s->ifr].x, (s->ppoints)[s->nf + s->ifr].y, NULL, backptr, erp ); wxd2lah_sp_ah_bspline( job, s, s->ifr, s->ifr, 1, 0, backptr, erp ); dk4pppt_closepath(job->ppp, backptr, erp); } break; case 25: case 26: { if (0 == stage) { wxd2lah_sp_ah_bspline( job, s, 0, s->ifr, 0, 1, backptr, erp ); dk4pppt_lineto( job->ppp, (s->ppoints)[s->nf + s->ifr].x, (s->ppoints)[s->nf + s->ifr].y, NULL, backptr, erp ); wxd2lah_sp_ah_bspline( job, s, s->ifr, s->ifr, 1, 0, backptr, erp ); dk4pppt_closepath(job->ppp, backptr, erp); } else { ss = ((26 == arrow->type) ? (s->ifr) : (0)); wxd2lah_sp_ah_bspline( job, s, ss, s->ifr, 0, 1, backptr, erp ); dk4pppt_lineto( job->ppp, (s->ppoints)[s->nf + s->ic].x, (s->ppoints)[s->nf + s->ic].y, NULL, backptr, erp ); wxd2lah_sp_ah_bspline( job, s, s->ic, s->ifr, 1, 0, backptr, erp ); dk4pppt_closepath(job->ppp, backptr, erp); } } break; case 27: case 28: { dk4pppt_circle( job->ppp, s->x0, s->y0, ((s->lw * (double)(arrow->length)) / 2.0), NULL, backptr, erp ); } break; case 29: { dk4pppt_newpath_moveto(job->ppp, s->x0, s->y0, NULL, backptr, erp); dk4pppt_lineto(job->ppp, s->x1, s->y1, NULL, backptr, erp); } break; default : { $? "! arrow type" } break; } $? "- wxd2lah_sp_ah_path" } /** Draw one arrowhead on spline. @param arrow Arrowhead structure. @param drw Drawing structure. @param job Job structure. @param obj Object arrow belongs to. @param isbck Flag: Is a backward arrow. @param backptr Address of success variable to reset on error. @param erp Error report, may be NULL. */ static void wxd2lah_ah_spline( wxd_arrow_t *arrow, wxd_drawing_t *drw, wxd2lat_job_t *job, wxd_object_t *pobj, int isbck, int *backptr, dk4_er_t *erp ) { sp_ah_t spah; $? "+ wxd2lah_ah_spline" /* Initialize struture. */ spah.ppoints = NULL; spah.nf = 0; spah.nb = 0; spah.nc = 0; spah.ifl = 0; spah.ifr = 0; spah.ibl = 0; spah.ibr = 0; spah.ic = 0; spah.to = 0.0; spah.tb = 0.0; spah.tc = 0.0; spah.lo = 0.0; spah.lb = 0.0; spah.lc = 0.0; spah.csgn = 0.0; spah.lw = wxd2lat_object_linewidth(pobj, drw, job); /* Calculate points. */ if (0 != wxd2lah_sp_ah_calc(&spah,arrow,job,pobj,isbck,backptr,erp)) { $? ". can draw arrowhead" /* Set up stroke and fill attributes */ wxd2lah_set_stroke_attributes(arrow, job, backptr, erp); /* Draw and/or fill the path following the points */ switch (arrow->type) { case 1: case 22: case 29: { $? ". type known" /* Arrowheads to stroke */ dk4pppt_prepare_stroke(job->ppp, backptr, erp); wxd2lah_sp_ah_path( arrow, job, &spah, 0, backptr, erp ); dk4pppt_stroke(job->ppp, backptr, erp); } break; case 2: case 6: case 10: case 14: case 18: case 23: case 27: { /* White filled arrowheads */ dk4pppt_set_fill_rgb(job->ppp, 1.0, 1.0, 1.0, backptr, erp); if (0 != dk4pppt_can_fill_and_stroke(job->ppp)) { dk4pppt_prepare_fill_and_stroke(job->ppp, backptr, erp); wxd2lah_sp_ah_path( arrow, job, &spah, 0, backptr, erp ); dk4pppt_fill_and_stroke(job->ppp, backptr, erp); } else { dk4pppt_prepare_fill(job->ppp, backptr, erp); wxd2lah_sp_ah_path( arrow, job, &spah, 0, backptr, erp ); dk4pppt_fill(job->ppp, backptr, erp); dk4pppt_prepare_stroke(job->ppp, backptr, erp); wxd2lah_sp_ah_path( arrow, job, &spah, 0, backptr, erp ); dk4pppt_stroke(job->ppp, backptr, erp); } } break; case 3: case 7: case 11: case 15: case 24: case 19: case 28: { /* Color filled arrowheads */ dk4pppt_set_fill_rgb( job->ppp, ((double)(pobj->sc[0]) / 255.0), ((double)(pobj->sc[1]) / 255.0), ((double)(pobj->sc[2]) / 255.0), backptr, erp ); if (0 != dk4pppt_can_fill_and_stroke(job->ppp)) { dk4pppt_prepare_fill_and_stroke(job->ppp, backptr, erp); wxd2lah_sp_ah_path( arrow, job, &spah, 0, backptr, erp ); dk4pppt_fill_and_stroke(job->ppp, backptr, erp); } else { dk4pppt_prepare_fill(job->ppp, backptr, erp); wxd2lah_sp_ah_path( arrow, job, &spah, 0, backptr, erp ); dk4pppt_fill(job->ppp, backptr, erp); dk4pppt_prepare_stroke(job->ppp, backptr, erp); wxd2lah_sp_ah_path( arrow, job, &spah, 0, backptr, erp ); dk4pppt_stroke(job->ppp, backptr, erp); } } break; case 4: case 5: case 8: case 9: case 12: case 13: case 16: case 17: case 20: case 21: case 25: case 26: { /* Half-side filled arrowheads */ dk4pppt_set_fill_rgb(job->ppp, 1.0, 1.0, 1.0, backptr, erp); if (0 != dk4pppt_can_fill_and_stroke(job->ppp)) { dk4pppt_prepare_fill_and_stroke(job->ppp, backptr, erp); wxd2lah_sp_ah_path( arrow, job, &spah, 0, backptr, erp ); dk4pppt_fill_and_stroke(job->ppp, backptr, erp); } else { dk4pppt_prepare_fill(job->ppp, backptr, erp); wxd2lah_sp_ah_path( arrow, job, &spah, 0, backptr, erp ); dk4pppt_fill(job->ppp, backptr, erp); dk4pppt_prepare_stroke(job->ppp, backptr, erp); wxd2lah_sp_ah_path( arrow, job, &spah, 0, backptr, erp ); dk4pppt_stroke(job->ppp, backptr, erp); } dk4pppt_set_fill_rgb( job->ppp, ((double)(pobj->sc[0]) / 255.0), ((double)(pobj->sc[1]) / 255.0), ((double)(pobj->sc[2]) / 255.0), backptr, erp ); dk4pppt_prepare_fill(job->ppp, backptr, erp); wxd2lah_sp_ah_path( arrow, job, &spah, 1, backptr, erp ); dk4pppt_fill(job->ppp, backptr, erp); } break; } } else { *backptr = 0; } if (NULL != spah.ppoints) { dk4mem_free(spah.ppoints); spah.ppoints = NULL; } $? "- wxd2lah_ah_spline" } void wxd2lah_arrowhead( wxd_arrow_t *arrow, wxd_drawing_t *drw, wxd2lat_job_t *job, wxd_object_t *pobj, int isbck, int *backptr, dk4_er_t *erp ) { $? "+ wxd2lout_arrowhead" switch (pobj->ot) { case WXD_OT_POLYLINE : { wxd2lah_ah_polyline(arrow, drw, job, pobj, isbck, backptr, erp); } break; case WXD_OT_O_ARC : { wxd2lah_ah_arc(arrow, drw, job, pobj, isbck, backptr, erp); } break; case WXD_OT_O_SPLINE : { wxd2lah_ah_spline(arrow, drw, job, pobj, isbck, backptr, erp); } break; } $? "- wxd2lout_arrowhead" } /* vim: set ai sw=4 ts=4 : */