%% options copyright owner = Dirk Krause copyright year = 2012-2014 license = bsd %% header #ifdef __cplusplus extern "C" { #endif /** Calculate distance between a given point and a line through the origin. @param xp X coordinate of given point. @param yp Y coordinate of given point. @param beta Angle of line. @param ec Pointer to error code variable. @return Distance value. */ double dk3figbb_distance_point_line( double xp, double yp, double beta, int *ec ); /** Add ellipse data to bounding box. @param bb Bounding box data to modify. @param elli Details of ellipse to add. @param lw Half line width. @return 1 on success, 0 on error. */ int dk3fig_bb_add_ellipse( dk3_bb_t *bb, dk3_fig_det_ell_t const *elli, double lw ); /** Add arc data to bounding box. @param bb Bounding box data to modify. @param arc Details of arc to add. @param cl Flag: Closed arc. @param lw Half line width. @return 1 on success, 0 on error. */ int dk3fig_bb_add_arc( dk3_bb_t *bb, dk3_fig_det_arc_t const *arc, int cl, double lw ); /** Add polyline data to bounding box. @param bb Bounding box data to modify. @param pol Details of polyline to add. @param lw Half line width. @return 1 on success, 0 on error. */ int dk3fig_bb_add_polyline( dk3_bb_t *bb, dk3_fig_det_pol_t const *pol, double lw ); /** Add spline data to bounding box. @param drw Drawing structure. @param bb Bounding box data to modify. @param spl Details of spline object to add. @param lw Half line width. @param primobj Flag: Primary object (1=object, 0=arrowhead). @param iscl Flag: Closed spline (1=closed, 0=open). @return 1 on success, 0 on error. */ int dk3fig_bb_add_spline( dk3_fig_drawing_t *drw, dk3_bb_t *bb, dk3_fig_det_spl_t const *spl, double lw, int primobj, int iscl ); /** Add text data to bounding box. @param bb Bounding box data to modify. @param txt Details of text object to add. @param res Fig file resolution. @param bbts Flag: Use text size when calculating bounding box. @return 1 on success, 0 on error. */ int dk3fig_bb_add_text( dk3_bb_t *bb, dk3_fig_det_txt_t const *txt, double res, int bbts ); /** Calculate bounding box for half-circle. @param outbb Destination bounding box. @param hci Half-circle details. @param ra Radius around points. @return 1 on success, 0 on error. */ int dk3fig_bb_add_hci( dk3_bb_t *outbb, dk3_fig_det_hci_t const *hci, double ra ); #ifdef __cplusplus } #endif %% module #include "dk3all.h" #include "dk3fig.h" #include "dk3bb.h" #include "dk3xsp.h" #include "dk3bezcu.h" #include "dk3figto.h" #include "dk3figbb.h" $!trace-include /** Check whether a value is in a given range. @param min Interval minimum. @param max Interval maximum. @param val Value to check. @return 1 if the value is in the interval, 0 otherwise. */ static int dk3fig_bb_in_range(double min, double max, double val) { int back = 0; if(min <= val) { if(max >= val) { back = 1; } } return back; } double dk3figbb_distance_point_line( double xp, double yp, double beta, int *ec ) { double sinbeta; /* Sinus of angle. */ double cosbeta; /* Cosinus of angle. */ double deltax; /* X difference. */ double deltay; /* Y difference. */ double back; $? "+ dk3figbb_distance_point_line x=%lg y=%lg beta=%lg", xp, yp, beta sinbeta = sin(beta); cosbeta = cos(beta); deltax = dk3ma_d_sub_ok( xp, (dk3ma_d_add_ok((yp * sinbeta), (xp * cosbeta), ec) * cosbeta), ec ); deltay = dk3ma_d_sub_ok( yp, (dk3ma_d_add_ok((yp * sinbeta), (xp * cosbeta), ec) * sinbeta), ec ); back = sqrt( dk3ma_d_add_ok( dk3ma_d_mul_ok(deltax, deltax, ec), dk3ma_d_mul_ok(deltay, deltay, ec), ec ) ); $? "- dk3figbb_distance_point_line %lg", back return back; } int dk3fig_bb_add_ellipse( dk3_bb_t *bb, dk3_fig_det_ell_t const *elli, double lw ) { double h; /* Height. */ double w; /* Width. */ double x; /* X coordinate of point. */ double y; /* Y coordinate of point. */ double th; /* Parameter t for Ph. */ double tw; /* Parameter t for Pw. */ double pma; /* Pi minus alpha. */ double hpma; /* Half pi minus alpha. */ int back = 0; int ec = 0; /* Error code for math. */ int r; /* Result from dk3bb_add. */ $? "+ dk3fig_bb_add_ellipse %lg", elli->an if((bb) && (elli)) { back = 1; $? ". cx=%lg", elli->cx $? ". cy=%lg", elli->cy $? ". rx=%lg", elli->rx $? ". ry=%lg", elli->ry $? ". an=%lg (%lg degree)", elli->an, (180.0 * elli->an) / M_PI if(fabs(elli->an) > 1.0e-6) { $? ". rotated" pma = dk3ma_d_sub_ok(M_PI, elli->an, &ec); hpma = dk3ma_d_sub_ok(M_PI_2, elli->an, &ec); th = dk3ma_d_atan2( (-1.0 * (elli->ry) * cos(pma)), ((elli->rx) * sin(pma)) ); $? ". th=%lg", th x = (elli->rx) * cos(th); y = (elli->ry) * sin(th); $? ". x=%lg y=%lg", x, y h = dk3figbb_distance_point_line( x, y, (-1.0 * (elli->an)), &ec ); $? ". h=%lg", h tw = dk3ma_d_atan2( (-1.0 * (elli->ry) * cos(hpma)), ((elli->rx) * sin(hpma)) ); $? ". tw=%lg", tw x = (elli->rx) * cos(tw); y = (elli->ry) * cos(tw); $? ". x=%lg y=%lg", x ,y w = dk3figbb_distance_point_line( x, y, dk3ma_d_sub_ok(M_PI_2, (elli->an), &ec), &ec ); $? ". w=%lg", w r = dk3bb_add_y_width( bb, dk3ma_d_sub_ok(elli->cy, h, &ec), (0.5 * lw) ); if(!(r)) { back = 0; } r = dk3bb_add_y_width( bb, dk3ma_d_add_ok(elli->cy, h, &ec), (0.5 * lw) ); if(!(r)) { back = 0; } r = dk3bb_add_x_width( bb, dk3ma_d_sub_ok(elli->cx, w, &ec), (0.5 * lw) ); if(!(r)) { back = 0; } r = dk3bb_add_x_width( bb, dk3ma_d_add_ok(elli->cx, w, &ec), (0.5 * lw) ); if(!(r)) { back = 0; } } else { $? ". not rotated" r = dk3bb_add_y_width( bb, dk3ma_d_sub_ok(elli->cy, elli->ry, &ec), (0.5 * lw) ); if(!(r)) { back = 0; } r = dk3bb_add_y_width( bb, dk3ma_d_add_ok(elli->cy, elli->ry, &ec), (0.5 * lw) ); if(!(r)) { back = 0; } r = dk3bb_add_x_width( bb, dk3ma_d_sub_ok(elli->cx, elli->rx, &ec), (0.5 * lw) ); if(!(r)) { back = 0; } r = dk3bb_add_x_width( bb, dk3ma_d_add_ok(elli->cx, elli->rx, &ec), (0.5 * lw) ); if(!(r)) { back = 0; } } } if(ec) { back = 0; } $? "- dk3fig_bb_add_ellipse %d", back return back; } int dk3fig_bb_add_arc( dk3_bb_t *bb, dk3_fig_det_arc_t const *arc, int cl, double lw ) { double min; /* Minimum angle. */ double max; /* Maximum angle. */ int back = 0; int ec = 0; /* Mathematical error code. */ $? "+ dk3fig_bb_add_arc %lg", lw if((bb) && (arc)) { back = 1; if(!dk3bb_point_width(bb, arc->x1, arc->y1, lw)) { back = 0; } if(!dk3bb_point_width(bb, arc->x2, arc->y2, lw)) { back = 0; } if(!dk3bb_point_width(bb, arc->x3, arc->y3, lw)) { back = 0; } if(cl) { if(!dk3bb_point_width(bb, arc->xc, arc->yc, lw)) { back = 0; } } if(arc->ae >= arc->as) { min = arc->as; max = arc->ae; } else { min = arc->ae; max = arc->as; } $? ". range %lg %lg", min, max if(dk3fig_bb_in_range(min, max, 0.0)) { $? ". 0 in Fig space" if(!dk3bb_add_x_width(bb, dk3ma_d_add_ok(arc->xc, arc->ra, &ec), lw)) { back = 0; } } if(dk3fig_bb_in_range(min, max, M_PI_2)) { $? ". 90 degree in Fig space" if(!dk3bb_add_y_width(bb, dk3ma_d_add_ok(arc->yc, arc->ra, &ec), lw)) { back = 0; } } if(dk3fig_bb_in_range(min, max, M_PI)) { $? ". 180 degree in Fig space" if(!dk3bb_add_x_width(bb, dk3ma_d_sub_ok(arc->xc, arc->ra, &ec), lw)) { back = 0; } } if(dk3fig_bb_in_range(min, max, (3.0 * M_PI_2))) { $? ". 270 degree in Fig space" if(!dk3bb_add_y_width(bb, dk3ma_d_sub_ok(arc->yc, arc->ra, &ec), lw)) { back = 0; } } if(dk3fig_bb_in_range(min, max, (2.0 * M_PI))) { $? ". 360 degree in Fig space" if(!dk3bb_add_x_width(bb, dk3ma_d_add_ok(arc->xc, arc->ra, &ec), lw)) { back = 0; } } if(dk3fig_bb_in_range(min, max, (5.0 * M_PI_2))) { $? ". 450 degree in Fig space" if(!dk3bb_add_y_width(bb, dk3ma_d_add_ok(arc->yc, arc->ra, &ec), lw)) { back = 0; } } if(dk3fig_bb_in_range(min, max, (3.0 * M_PI))) { $? ". 540 degree in Fig space" if(!dk3bb_add_x_width(bb, dk3ma_d_sub_ok(arc->xc, arc->ra, &ec), lw)) { back = 0; } } if(dk3fig_bb_in_range(min, max, (7.0 * M_PI_2))) { $? ". 630 degree in Fig space" if(!dk3bb_add_y_width(bb, dk3ma_d_sub_ok(arc->yc, arc->ra, &ec), lw)) { back = 0; } } if(dk3fig_bb_in_range(min, max, (4.0 * M_PI))) { $? ". 720 degree in Fig space" if(!dk3bb_add_x_width(bb, dk3ma_d_add_ok(arc->xc, arc->ra, &ec), lw)) { back = 0; } } } if(ec) { back = 0; } $? "- dk3fig_bb_add_arc %d", back return back; } int dk3fig_bb_add_polyline( dk3_bb_t *bb, dk3_fig_det_pol_t const *pol, double lw ) { dk3_fig_poly_point_t const *ptr; /* Current point. */ size_t num; /* Index of current point. */ int back = 0; $? "+ dk3fig_bb_add_polyline" if((bb) && (pol)) { if((pol->po) && (0 < pol->np)) { back = 1; ptr = pol->po; num = pol->np; while(num--) { if(!dk3bb_point_width(bb, ptr->x, ptr->y, lw)) { back = 0; } ptr++; } } } $? "- dk3fig_bb_add_polyline %d", back return back; } int dk3fig_bb_add_text( dk3_bb_t *bb, dk3_fig_det_txt_t const *txt, double res, int bbts ) { double ymax; /* Maximum y. */ int back = 0; int ec = 0; /* Mathematical error code. */ $? "+ dk3fig_bb_add_text" if((bb) && (txt)) { back = 1; dk3bb_point(bb, txt->x, txt->y); /* 2013-02-03: Y value is used only if bbts is set. */ /* 2012-12-01: Y values grow downwards in Fig space, so we must substract instead of add. */ if(bbts) { ymax = dk3ma_d_sub_ok( txt->y, dk3ma_d_mul_ok(res, (txt->fs / 72.72), &ec), &ec ); $? ". ymax = %lg", ymax dk3bb_point(bb, txt->x, ymax); } if(ec) { back = 0; } } $? "- dk3fig_bb_add_text %d", back return back; } /** Add X-spline segment to bounding box. @param bb Bounding box structure to modify. @param pa Point A (left neighbour of segment). @param pb Point B (start of segment). @param pc Point C (end of segment). @param pd Point D (right neighbour of segment). @param xssbs Number of Bezier spline segments per X-spline segment. @param cb Flag: Compatibility to XFig interpolated spline bug. @param ra Radius of points. @return 1 on success, 0 on error. */ static int dk3fig_bb_add_xpline_segment( dk3_bb_t *bb, dk3_fig_spline_point_t *pa, dk3_fig_spline_point_t *pb, dk3_fig_spline_point_t *pc, dk3_fig_spline_point_t *pd, size_t xssbs, int cb, double ra ) { dk3_xspline_segment_t xseg; /* Spline segment. */ double x; /* Current x. */ double y; /* Current y. */ double lastx; /* Previous x. */ double lasty; /* Previous y. */ double dxdt; /* X derived. */ double dydt; /* Y derived. */ double lastdxdt; /* X derived, previous value. */ double lastdydt; /* Y derived, previous value. */ double xp; /* Start control point x. */ double yp; /* Start control point y. */ double xm; /* End control point x. */ double ym; /* End control point y. */ double t; /* Current t value. */ double dxssbs; /* Number of sub segments. */ double d3; /* Scale factor for derivatives. */ size_t i; /* Current sub segment. */ int back = 1; int mec = 0; /* Mathematical error code. */ $? "+ dk3fig_bb_add_xpline_segment" dk3xsp_reset(&xseg); if(cb) { dk3xsp_set_cb(&xseg, cb); } dk3xsp_set(&xseg, pa, pb, pc, pd); if(dk3xsp_calculate(&xseg, 0.0, 1)) { $? ". first calc" dxssbs = (double)xssbs; d3 = dk3ma_d_mul_ok(3.0, dxssbs, &mec); lastx = dk3xsp_get_x(&xseg); lasty = dk3xsp_get_y(&xseg); lastdxdt = dk3xsp_get_dxdt(&xseg); lastdydt = dk3xsp_get_dydt(&xseg); for(i = 1; i <= xssbs; i++) { if(i < xssbs) { t = (double)i / dxssbs; } else { t = 1.0; } if(dk3xsp_calculate(&xseg, t, 1)) { x = dk3xsp_get_x(&xseg); y = dk3xsp_get_y(&xseg); dxdt = dk3xsp_get_dxdt(&xseg); dydt = dk3xsp_get_dydt(&xseg); xp = dk3ma_d_add_ok( lastx, dk3ma_d_div_ok(lastdxdt, d3, &mec), &mec ); yp = dk3ma_d_add_ok( lasty, dk3ma_d_div_ok(lastdydt, d3, &mec), &mec ); xm = dk3ma_d_sub_ok( x, dk3ma_d_div_ok(dxdt, d3, &mec), &mec ); ym = dk3ma_d_sub_ok( y, dk3ma_d_div_ok(dydt, d3, &mec), &mec ); if(!dk3bezier_bb(bb, lastx, lasty, xp, yp, xm, ym, x, y, ra, &mec)) { back = 0; $? "! Bezier bb" } lastx = x; lasty = y; lastdxdt = dxdt; lastdydt = dydt; } else { $? "! calc" back = 0; } } } else { $? "! first calc" back = 0; } if(mec) { $? "! math error" back = 0; } $? "- dk3fig_bb_add_xpline_segment %d", back return back; } int dk3fig_bb_add_spline( dk3_fig_drawing_t *drw, dk3_bb_t *bb, dk3_fig_det_spl_t const *spl, double lw, int primobj, int iscl ) { dk3_fig_spline_point_t *pa; /* Point A. */ dk3_fig_spline_point_t *pb; /* Point B. */ dk3_fig_spline_point_t *pc; /* Point C. */ dk3_fig_spline_point_t *pd; /* Point D. */ size_t xssbs; /* Bezier segments per X-spline segment. */ size_t cs; /* Current X-spline segment. */ int back = 0; $? "+ dk3fig_bb_add_spline closed=%d", iscl if((bb) && (spl)) { if((spl->po) && (((iscl) ? (size_t)2 : (size_t)1) < spl->np)) { back = 1; xssbs = dk3fig_tool_xssbs(drw, primobj); if(iscl) { $? ". closed spline" for(cs = 0; cs < (spl->np); cs++) { pb = &((spl->po)[cs]); pc = &((spl->po)[((cs < (spl->np - 1)) ? (cs + 1) : 0)]); pa = &((spl->po)[(cs > 0) ? (cs - 1) : ((spl->np) - 1)]); pd = &((spl->po)[(cs < (spl->np - 2))?(cs + 2):(cs + 2 - spl->np)]); if(!dk3fig_bb_add_xpline_segment(bb,pa,pb,pc,pd,xssbs,drw->cosp,lw)) { back = 0; } } } else { $? ". open spline" for(cs = 0; cs < ((spl->np) - 1); cs++) { pa = pd = NULL; pb = &((spl->po)[cs]); pc = &((spl->po)[cs + 1]); if(0 < cs) { pa = &((spl->po)[cs - 1]); } if(cs < ((spl->np) - 2)) { pd = &((spl->po)[cs + 2]); } if(!dk3fig_bb_add_xpline_segment(bb,pa,pb,pc,pd,xssbs,drw->cosp,lw)) { back = 0; } } } } else { $? "! no point data or too few points" } } $? "- dk3fig_bb_add_spline %d", back return back; } int dk3fig_bb_add_hci( dk3_bb_t *outbb, dk3_fig_det_hci_t const *hci, double ra ) { dk3_fig_poly_point_t po[3]; /* End and middle point of arc. */ size_t i; /* Used as index when rotating. */ int back = 0; int mec = 0; /* Mathematical error code. */ if((outbb) && (hci)) { po[0].x = 0.0; po[0].y = hci->ra; po[1].x = -1.0 * hci->ra; po[1].y = 0.0; po[2].x = 0.0; po[2].y = -1.0 * hci->ra; for(i = 0; i < 3; i++) { dk3fig_tool_rotate_point(&(po[i]), hci->an, &mec); dk3fig_tool_shift_point( &(po[i]), hci->cx, hci->cy, &mec ); } if(0 == mec) { back = 1; if(!dk3bb_point_width(outbb, po[0].x, po[0].y, ra)) { back = 0; } if(!dk3bb_point_width(outbb, po[1].x, po[1].y, ra)) { back = 0; } if(!dk3bb_point_width(outbb, po[2].x, po[2].y, ra)) { back = 0; } /* ##### HIER WEITER: Weitere Punkte je nach Drehung */ } } return back; }