/* Copyright (c) 2009-2010, Dirk Krause All rights reserved. Redistribution and use in source and binary forms, with or without modification, are permitted provided that the following conditions are met: * Redistributions of source code must retain the above copyright notice, this list of conditions and the following disclaimer. * Redistributions in binary form must reproduce the above opyright notice, this list of conditions and the following disclaimer in the documentation and/or other materials provided with the distribution. * Neither the name of the Dirk Krause nor the names of contributors may be used to endorse or promote products derived from this software without specific prior written permission. THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. */ /** @file dkfigw.c Fig writer module. This module contains functions to create a graphic in-memory and save that graphics to a Fig file. Programs like XFig or jFig can be used to apply modifications to the graphics file after it is written. Fig files are text files, so you could use standard I/O operations like fprintf() to produce the file. The purpose of this module is to ease up the Fig file production by doing calculations from centimeters and inches to Fig units and the coordinates transformation from "origin in lower left corner" used by the module to "origin in upper left corner" used by the Fig file format. */ #include #if DK_HAVE_MATH_H #include #endif #if DK_HAVE_STDLIB_H #include #endif #if DK_HAVE_UNISTD_H #include #endif #include #include #include #include #include /** Inside the dkfigw module. */ #define DKFIGW_C 1 #include "dkfigw.h" #line 84 "dkfigw.ctr" /** File name suffixes used for compressed files. */ static char *suffixes[] = { ".gz", ".bz2", NULL }; /** Keywords used while producing a Fig file. */ static char *kw[] = { /* 0 */ "\n", /* 1 */ " ", /* 2 */ "w", /* 3 */ "#FIG 3.2", /* 4 */ "Portrait", /* 5 */ "Landscape", /* 6 */ "Center", /* 7 */ "Flush Left", /* 8 */ "Metric", /* 9 */ "Inches", /* 10 */ "100.0", /* 11 */ "Single", /* 12 */ "Multiple", /* 13 */ "1200 2", /* 14 */ "\t", /* 15 */ "2 2 0 0 7 7 999 0 -1 0 0 0 0 0 0 5", /* 16 */ "## *: remove background rectangle = yes", /* 17 */ "## *: background rectangle color = white", /* 18 */ "\\001", /* 19 */ "\\\\", /* 20 */ "## *: encoding = utf-8", NULL }; /** Paper size names. */ static char *paper_sizes[] = { "Letter", "Legal", "Ledger", "Tabloid", "A", "B", "C", "D", "E", "A4", "A3", "A2", "A1", "A0", "B5", NULL }; /** Factor for cm to Fig unit conversion. */ static double cm_to_fig = 1200.0 / 2.54; /** Factor for inch to Fig unit conversion. */ static double in_to_fig = 1200.0; /** Color names. */ static char *color_names[] = { "black", "blue", "green", "cyan", "red", "magenta", "yellow", "white", "blue.darkest", "blue.dark", "blue.light", "blue.lightest", "green.dark", "green.normal", "green.light", "cyan.dark", "cyan.normal", "cyan.light", "red.dark", "red.normal", "red.light", "magenta.dark", "magenta.normal", "magenta.light", "brown.dark", "brown.normal", "brown.light", "pink.darkest", "pink.dark", "pink.light", "pink.lightest", "gold", NULL }; /** PS font names. */ static char *font_names[] = { "Times Roman", "Times Italic", "Times Bold", "Times Bold Italic", "Avantgarde Book", "Avantgarde Book Oblique", "Avantgarde Demi", "Avantgarde Demi Oblique", "Bookman Light", "Bookman Light Italic", "Bookman Demi", "Bookman Demi Italic", "Courier", "Courier Oblique", "Courier Bold", "Courier Bold Oblique", "Helvetica", "Helvetica Oblique", "Helvetica Bold", "Helvetica Bold Oblique", "Helvetica Narrow", "Helvetica Narrow Oblique", "Helvetica Narrow Bold", "Helvetica Narrow Bold Oblique", "New Century Schoolbook Roman", "New Century Schoolbook Italic", "New Century Schoolbook Bold", "New Century Schoolbook Bold Italic", "Palatino Roman", "Palatino Italic", "Palatino Bold", "Palatino Bold Italic", "Symbol", "Zapf Chancery Medium Italic", "Zapf Dingbats", NULL }; /** Find index of text \arg t in array \arg a. When in verbose mode, print a warning and a list of allowed texts if the text is not found. @param a Array of text pointers. @param t Text to find. @param c Flag: Case sensitive (nonzero) or not (0). @param ver Flag: Verbose mode on. @return Index on success, -1 on error. */ static int my_str_array_index DK_P4(char **,a, char *,t, int,c, unsigned char,ver) { int back = -1; char **ptr; back = dkstr_array_index(a,t,c); if(back < 0) { if(ver) { fprintf(stderr, "Warning: Illegal name \"%s\"! Allowed names:\n", t); ptr = a; while(*ptr) { fprintf(stderr, " %s\n", *(ptr++)); } fflush(stderr); } } return back; } /** Convert Distance to Fig units. @param fwp Fig writer structure. @param x Distance to convert. @return The conversion result as double value. */ static double d_to_fig_d DK_P2(dk_fig_writer_t *,fwp, double,x) { double back = 0.0; switch(fwp->uni) { case 1: { back = in_to_fig * x; } break; case 2: { back = cm_to_fig * x; } break; default: { back = x; } break; } return back; } /** Convert distance to Fig units. @param fwp Fig writer structure. @param x Distance to convert. @return The conversion result as long value. */ static long d_to_fig_l DK_P2(dk_fig_writer_t *,fwp, double,x) { long back = 0L; back = dkma_double_to_l(dkma_rint(d_to_fig_d(fwp, x))); return back; } /** Convert x position to Fig units. @param fwp Fig writer structure. @param x X position. @return The conversion result as double value. */ static double x_to_fig_d DK_P2(dk_fig_writer_t *,fwp, double,x) { double back = 0.0; back = d_to_fig_d(fwp, x) + fwp->xsh; return back; } /** Convert x position to Fig units. @param fwp Fig writer structure. @param x X position. @return The conversion result as long value. */ static long x_to_fig_l DK_P2(dk_fig_writer_t *,fwp, double,x) { long back; back = dkma_double_to_l(dkma_rint(x_to_fig_d(fwp, x))); return back; } /** Convert y position to Fig units. @param fwp Fig writer structure. @param y Y position. @return The conversion result as double value. */ static double y_to_fig_d DK_P2(dk_fig_writer_t *,fwp, double,y) { double back; back = d_to_fig_d(fwp, y); if(!(fwp->olt)) { back = d_to_fig_d(fwp, fwp->imh) - back; } back += fwp->ysh; return back; } /** Convert y position to Fig units. @param fwp Fig writer structure. @param y Y position. @return The conversion result as long value. */ static long y_to_fig_l DK_P2(dk_fig_writer_t *,fwp, double,y) { long back; back= dkma_double_to_l(dkma_rint(y_to_fig_d(fwp, y))); return back; } /** Convert unsigned char to integer. @param uc Character to convert. @return Conversion result. */ static int uc_to_int DK_P1(unsigned char,uc) { int back = 0; if(uc == 0xFF) { back = -1; } else { back = (int)((unsigned)uc); } return back; } /** Write unsigned number to output stream. @param os Output stream. @param u Value to write. */ static void put_unsigned DK_P2(dk_stream_t *,os, unsigned,u) { char buffer[64]; sprintf(buffer, "%u", u); dkstream_puts(os, buffer); } /** Return corrected value fitting in range. @param x Value to correct. @param min Range minimum. @param max Range maximum. @return Corrected value. */ #define TO_RANGE(x,min,max) ((x > max) ? max : ((x < min) ? min : x)) #if 0 static void put_unsigned_range DK_P4(dk_stream_t *,os, unsigned,u, unsigned,min, unsigned,max) { unsigned i; i = TO_RANGE(u,min,max); put_unsigned(os, i); } #endif /** Put integer value to output stream. @param os Output stream. @param i Value to put. */ static void put_int DK_P2(dk_stream_t *,os, int,i) { char buffer[64]; sprintf(buffer, "%d", i); dkstream_puts(os, buffer); } /** Put integer value to output stream, correct value if necessary. @param os Output stream. @param i Value to put. @param min Minimum value. @param max Maximum value. */ static void put_int_range DK_P4(dk_stream_t *,os, int,i, int,min, int,max) { int j; j = TO_RANGE(i,min,max); put_int(os, j); } /** Put long value to output stream. @param os Output stream. @param l Value to put. */ static void put_long DK_P2(dk_stream_t *,os, long,l) { char buffer[64]; sprintf(buffer, "%ld", l); dkstream_puts(os, buffer); } /** Put double value to output stream. @param os Output stream. @param d Value to put. */ static void put_double DK_P2(dk_stream_t *,os, double,d) { char buffer[64]; sprintf(buffer, "%.2lf", d); dkstream_puts(os, buffer); } /** Put double value to output stream, use large number of decimal digits. @param os Output stream. @param d Value to put. */ static void put_long_double DK_P2(dk_stream_t *,os, double,d) { char buffer[128]; sprintf(buffer, "%.16lf", d); dkstream_puts(os, buffer); } #if 0 static void put_double_range DK_P4(dk_stream_t *,os, double,d, double,min, double,max) { double e; e = TO_RANGE(d,min,max); put_double(os, e); } #endif /** Initialize arrowhead. @param ahp Arrowhead to initialize. */ static void init_arrowhead DK_P1(dk_fig_ah_t *,ahp) { if(ahp) { ahp->sha = FIG_AS_TRIANGLE; ahp->fil = FIG_AF_PC; ahp->wid = 10.0; ahp->hei = 5.0; } } /** Initialize style information structure. @param stp Structure to initialize. */ static void init_style DK_P1(dk_fig_style_t *,stp) { if(stp) { stp->lay = 998; stp->liw = 1; stp->pco = FIG_COLOR_BLACK; stp->fco = FIG_COLOR_WHITE; stp->fil = FIG_FILL_NONE; stp->lst = FIG_LS_SOLID; stp->ljn = FIG_LJ_MITER; stp->lcp = FIG_CS_BUTT; stp->ahs = 0x00; stp->ffl = FIG_TEXTFLAG_PS; stp->fno = FIG_FONT_PS_TIMES_ROMAN; stp->fsz = 12.0; stp->tal = FIG_SUB_TEXT_LEFT; stp->sva = 5.0; init_arrowhead(&(stp->fwa)); init_arrowhead(&(stp->bwa)); } } /** Compare two polyline/polygon points by number. @param l Left point. @param r Right point. @param c Comparison criteria (ignored). @return Comparison result. */ int dkfigw_compare_pl_points DK_P3(void *,l, void *,r, int,c) { int back = 0; dk_fig_pl_pt_t *pl; dk_fig_pl_pt_t *pr; pl = (dk_fig_pl_pt_t *)l; pr = (dk_fig_pl_pt_t *)r; if(l) { if(r) { if(pl->npt > pr->npt) { back = 1; } else { if(pl->npt < pr->npt) { back = -1; } } } else { back = 1; } } else { if(r) { back = -1; } } return back; } /** Compare two spline points by number. @param l Left point. @param r Right point. @param c Comparison criteria (ignored). @return Comparison result. */ int dkfigw_compare_sp_points DK_P3(void *,l, void *,r, int,c) { int back = 0; dk_fig_sp_pt_t *pl; dk_fig_sp_pt_t *pr; pl = (dk_fig_sp_pt_t *)l; pr = (dk_fig_sp_pt_t *)r; if(l) { if(r) { if(pl->npt > pr->npt) { back = 1; } else { if(pl->npt < pr->npt) { back = -1; } } } else { back = 1; } } else { if(r) { back = -1; } } return back; } /** Compare two color cells. @param l Left color cell. @param r Right color cell. @param c Comparison criteria (0=cell/cell, 1=cell/number). @return Comparison result. */ int dkfigw_compare_color_cells DK_P3(void *,l, void *,r, int,c) { int back = 0; dk_fig_cc_t *lp; dk_fig_cc_t *rp; unsigned short *ccnop; lp = (dk_fig_cc_t *)l; rp = (dk_fig_cc_t *)r; ccnop = (unsigned short *)r; switch(c) { case 1: { if(lp) { if(ccnop) { if(lp->ccn > *ccnop) { back = 1; } else { if(lp->ccn < *ccnop) { back = -1; } } } else { back = 1; } } else { if(ccnop) { back = -1; } } } break; default: { if(lp) { if(rp) { if(rp->ccn > lp->ccn) { back = 1; } else { if(rp->ccn < lp->ccn) { back = -1; } } } else { back = 1; } } else { if(rp) { back = -1; } } } break; } return back; } /** Compare two objects. @param l Left object. @param r Right object. @param c Comparison criteria (0=object/object, 1=object/number). @return Comparison result. */ int dkfigw_compare_objects DK_P3(void *,l, void *,r, int,c) { int back = 0; dk_fig_object_t *lp; dk_fig_object_t *rp; unsigned long *obnp; lp = (dk_fig_object_t *)l; rp = (dk_fig_object_t *)r; obnp = (unsigned long *)r; switch(c) { case 1: { if(lp) { if(obnp) { if(lp->obn > *obnp) { back = 1; } else { if(lp->obn < *obnp) { back = -1; } } } else { back = 1; } } else { if(obnp) { back = -1; } } } break; default: { if(lp) { if(rp) { if(lp->obn > rp->obn) { back = 1; } else { if(lp->obn < rp->obn) { back = -1; } } } else { back = 1; } } else { if(rp) { back = -1; } } } break; } return back; } /** Release memory for Fig object. @param obj Object to release. */ static void object_delete DK_P1(dk_fig_object_t *,obj) { void *x; if(obj) { switch(obj->otp) { case FIG_OBJECT_POLYLINE: case FIG_OBJECT_SPLINE: { if((obj->det).pll.spt) { if((obj->det).pll.ipt) { dksto_it_reset((obj->det).pll.ipt); while((x = dksto_it_next((obj->det).pll.ipt)) != NULL) { dk_delete(x); } dksto_it_close((obj->det).pll.ipt); } dksto_close((obj->det).pll.spt); } if((obj->det).pll.fn) { dk_delete((obj->det).pll.fn); } } break; case FIG_OBJECT_TEXT: { if((obj->det).txt.txt) { dk_delete((obj->det).txt.txt); } } break; } DK_MEMRES(obj,sizeof(dk_fig_object_t)); dk_delete(obj); } } /** Create structure for Fig object. @param fwp Fig writer structure. @param ot Fig object type. @param st Object sub type. @return Pointer to new object on success, NULL on error. */ static dk_fig_object_t * object_new DK_P3(dk_fig_writer_t *,fwp, unsigned char,ot, unsigned char,st) { dk_fig_object_t *back = NULL; back = dk_new(dk_fig_object_t,1); if(back) { back->obn = fwp->non; fwp->non += 1UL; back->otp = ot; back->stp = st; DK_MEMCPY(&(back->sty), &(fwp->sty), sizeof(dk_fig_style_t)); switch(ot) { case FIG_OBJECT_ARC: { (back->det).arc.xm = 0.0; (back->det).arc.ym = 0.0; (back->det).arc.ra = 0.0; (back->det).arc.a0 = 0.0; (back->det).arc.a1 = 0.0; } break; case FIG_OBJECT_ELLIPSE: { (back->det).ell.xm = 0.0; (back->det).ell.ym = 0.0; (back->det).ell.rx = 0.0; (back->det).ell.ry = 0.0; (back->det).ell.ro = 0.0; } break; case FIG_OBJECT_SPLINE: case FIG_OBJECT_POLYLINE: { int ok; (back->det).pll.spt = NULL; (back->det).pll.ipt = NULL; (back->det).pll.npn = 1UL; (back->det).pll.fn = NULL; (back->det).pll.x0 = 0.0; (back->det).pll.y0 = 0.0; (back->det).pll.x1 = 0.0; (back->det).pll.cr = 0.0; ok = 0; switch(ot) { case FIG_OBJECT_SPLINE: { (back->det).pll.spt = dksto_open(0); if((back->det).pll.spt) { dksto_set_comp((back->det).pll.spt, dkfigw_compare_sp_points, 0); (back->det).pll.ipt = dksto_it_open((back->det).pll.spt); if((back->det).pll.ipt) { ok = 1; } } if(!ok) { object_delete(back); back = NULL; } } break; case FIG_OBJECT_POLYLINE: { (back->det).pll.spt = dksto_open(0); if((back->det).pll.spt) { dksto_set_comp((back->det).pll.spt, dkfigw_compare_pl_points, 0); (back->det).pll.ipt = dksto_it_open((back->det).pll.spt); if((back->det).pll.ipt) { ok = 1; } } if(!ok) { object_delete(back); back = NULL; } switch(st) { case FIG_SUB_POLYLINE: case FIG_SUB_POLYGON: { (back->det).pll.spt = dksto_open(0); if((back->det).pll.spt) { dksto_set_comp((back->det).pll.spt, dkfigw_compare_pl_points, 0); (back->det).pll.ipt = dksto_it_open((back->det).pll.spt); if((back->det).pll.ipt) { ok = 1; } } if(!ok) { object_delete(back); back = NULL; } } break; } } break; } } break; case FIG_OBJECT_TEXT: { (back->det).txt.x = 0.0; (back->det).txt.y = 0.0; (back->det).txt.rot = 0.0; (back->det).txt.txt = NULL; } break; } } if(back) { if(!dksto_add(fwp->ost, (void *)back)) { object_delete(back); back = NULL; } } fwp->cob = back; return back; } /** Release memory for color cell. @param ccp Color cell to release. */ static void cc_delete DK_P1(dk_fig_cc_t *,ccp) { if(ccp) { dk_delete(ccp); } } /** Remove writer structure, release memory. @param fwp Pointer to structure to release. */ void dkfigw_delete DK_P1(dk_fig_writer_t *,fwp) { dk_fig_object_t *op; dk_fig_cc_t *cp; if(fwp) { if(fwp->ost) { if(fwp->osi) { dksto_it_reset(fwp->osi); while((op = (dk_fig_object_t *)dksto_it_next(fwp->osi)) != NULL) { object_delete(op); } dksto_it_close(fwp->osi); fwp->osi = NULL; } dksto_close(fwp->ost); fwp->ost = NULL; } if(fwp->ccs) { if(fwp->cci) { dksto_it_reset(fwp->cci); while((cp = (dk_fig_cc_t *)dksto_it_next(fwp->cci)) != NULL) { cc_delete(cp); } dksto_it_close(fwp->cci); fwp->cci = NULL; } dksto_close(fwp->ccs); fwp->ccs = NULL; } } } /** Create new writer structure. @return Pointer to new writer structure on success, NULL on error. */ dk_fig_writer_t * dkfigw_new DK_P0() { dk_fig_writer_t *back = NULL; int ok = 0; char *ptr; back = dk_new(dk_fig_writer_t,1); if(back) { back->ver = 0x00; back->ost = NULL; back->osi = NULL; back->ccs = NULL; back->cci = NULL; back->cob = NULL; back->sob = NULL; back->non = 1UL; back->ncc = FIG_COLOR_GOLD + 1; init_style(&(back->sty)); back->olt = 0x00; back->uni = 0; back->ang = 0x00; back->imw = back->imh = 0.0; back->erc = 0; back->mer = 0; back->tco = -2; back->ori = FIG_ORIENTATION_LANDSCAPE; back->jus = FIG_JUSTIFICATION_CENTER; back->utf = 0x00; ptr = getenv("LANG"); if(ptr) { ptr = strchr(ptr, '.'); if(ptr) { ptr++; if(dkstr_casecmp(ptr, "utf-8") == 0) { back->utf = 0x01; } } } back->fun = 0x00; back->pap = FIG_PAPER_A4; back->ost = dksto_open(0); if(back->ost) { dksto_set_comp(back->ost, dkfigw_compare_objects, 0); back->osi = dksto_it_open(back->ost); if(back->osi) { back->ccs = dksto_open(0); if(back->ccs) { dksto_set_comp(back->ccs, dkfigw_compare_color_cells, 0); back->cci = dksto_it_open(back->ccs); if(back->cci) { ok = 1; } } } } if(!ok) { dkfigw_delete(back); back = NULL; } } return back; } /** Set image origin. @param fwp Writer structure. @param olt Flag: Origin at left top (1) or left bottom (0). */ void dkfigw_set_image_origin DK_P2(dk_fig_writer_t *,fwp, int,olt) { if(fwp) { fwp->olt = (olt ? 0x01 : 0x00); } } /** Set image size. @param fwp Writer structure. @param uni Size unit (0=Fig, 1=inch, 2=cm). @param w Image width. @param h Image height. @return 1 on success, 0 on error. */ int dkfigw_set_image_size DK_P4(dk_fig_writer_t *,fwp, int,uni, double,w, double,h) { int back = 0; if(fwp) { back = 1; fwp->imw = w; fwp->imh = h; fwp->uni = uni; } return back; } /** Add rectangle. @param fwp Writer structure. @param x0 Point 1 x. @param y0 Point 1 y. @param x1 Point 2 x. @param y1 Point 2 y. @return Positive number on success, 0 on error. */ unsigned long dkfigw_rectangle DK_P5(dk_fig_writer_t *,fwp, double,x0, double,y0, double,x1, double,y1) { unsigned long back = 0UL; dk_fig_object_t *obj; obj = object_new(fwp, FIG_OBJECT_POLYLINE, FIG_SUB_BOX); if(obj) { back = obj->obn; (obj->det).pll.x0 = x0; (obj->det).pll.y0 = y0; (obj->det).pll.x1 = x1; (obj->det).pll.y1 = y1; } return back; } /** Add arc box. @param fwp Writer structure. @param x0 Point 1 x. @param y0 Point 1 y. @param x1 Point 2 x. @param y1 Point 2 y. @param r Corner radius. @return Positive number on success, 0 on error. */ unsigned long dkfigw_arc_box DK_P6(dk_fig_writer_t *,fwp, double,x0, double,y0, double,x1, double,y1, double,r) { unsigned long back = 0UL; dk_fig_object_t *obj; obj = object_new(fwp, FIG_OBJECT_POLYLINE, FIG_SUB_ARC_BOX); if(obj) { back = obj->obn; (obj->det).pll.x0 = x0; (obj->det).pll.y0 = y0; (obj->det).pll.x1 = x1; (obj->det).pll.y1 = y1; (obj->det).pll.cr = r; } return back; } /** Add image. @param fwp Writer structure. @param x0 Point 1 x. @param y0 Point 1 y. @param x1 Point 2 x. @param y1 Point 2 y. @param fn File name. @return Positive number on success, 0 on error. */ unsigned long dkfigw_image DK_P6(dk_fig_writer_t *,fwp, double,x0, double,y0, double,x1, double,y1, char *,fn) { unsigned long back = 0UL; dk_fig_object_t *obj; obj = object_new(fwp, FIG_OBJECT_POLYLINE, FIG_SUB_IMAGE); if(obj) { (obj->det).pll.fn = dkstr_dup(fn); if((obj->det).pll.fn) { back = obj->obn; (obj->det).pll.x0 = x0; (obj->det).pll.y0 = y0; (obj->det).pll.x1 = x1; (obj->det).pll.y1 = y1; } else { } } return back; } /** Add polygon. After creating the polygon use dkfigw_point() to add points. @param fwp Writer structure. @return Positive number on success, 0 on error. */ unsigned long dkfigw_polygon DK_P1(dk_fig_writer_t *,fwp) { unsigned long back = 0UL; dk_fig_object_t *obj; obj = object_new(fwp, FIG_OBJECT_POLYLINE, FIG_SUB_POLYGON); if(obj) { back = obj->obn; } return back; } /** Add polyline. After creating the polygon use dkfigw_point() to add points. @param fwp Writer structure. @return Positive number on success, 0 on error. */ unsigned long dkfigw_polyline DK_P1(dk_fig_writer_t *,fwp) { unsigned long back = 0UL; dk_fig_object_t *obj; obj = object_new(fwp, FIG_OBJECT_POLYLINE, FIG_SUB_POLYLINE); if(obj) { back = obj->obn; } return back; } /** Add point to the current polygon or polyline object. @param fwp Writer structure. @param x X position. @param y Y position. @return Positive number on success, 0 on error. */ unsigned long dkfigw_point DK_P3(dk_fig_writer_t *,fwp, double,x, double,y) { unsigned long back = 0UL; dk_fig_pl_pt_t *spp = NULL; if(fwp) { if(fwp->cob) { if(((fwp->cob)->otp) == FIG_OBJECT_POLYLINE) { switch((fwp->cob)->stp) { case FIG_SUB_POLYLINE: case FIG_SUB_POLYGON: { if(((fwp->cob)->det).pll.spt) { spp = dk_new(dk_fig_pl_pt_t,1); if(spp) { spp->npt = ((fwp->cob)->det).pll.npn; ((fwp->cob)->det).pll.npn = ((fwp->cob)->det).pll.npn + 1UL; spp->x = x; spp->y = y; if(dksto_add(((fwp->cob)->det).pll.spt, (void *)spp)) { back = spp->npt; } else { dk_delete(spp); } } else { } } else { } } break; } } } } return back; } /** Add open spline. After creating the spline use dkfigw_spline_point() to add points. @param fwp Writer structure. @return Positive number on success, 0 on error. */ unsigned long dkfigw_open_spline DK_P1(dk_fig_writer_t *,fwp) { unsigned long back = 0UL; dk_fig_object_t *obj; obj = object_new(fwp, FIG_OBJECT_SPLINE, FIG_SUB_SPLINE_OPEN_X); if(obj) { back = obj->obn; } return back; } /** Add closed spline. After creating the spline use dkfigw_spline_point() to add points. @param fwp Writer structure. @return Positive number on success, 0 on error. */ unsigned long dkfigw_closed_spline DK_P1(dk_fig_writer_t *,fwp) { unsigned long back = 0UL; dk_fig_object_t *obj; obj = object_new(fwp, FIG_OBJECT_SPLINE, FIG_SUB_SPLINE_CLOSED_X); if(obj) { back = obj->obn; } return back; } /** Add point to current spline object. @param fwp Writer structure. @param x X position. @param y Y position. @param s Approximation/interpolation parameter. @return Positive number on success, 0 on error. */ unsigned long dkfigw_spline_point DK_P4(dk_fig_writer_t *,fwp, double,x, double,y, double,s) { unsigned long back = 0UL; dk_fig_sp_pt_t *spp = NULL; if(fwp) { if(fwp->cob) { if(((fwp->cob)->otp) == FIG_OBJECT_SPLINE) { switch((fwp->cob)->stp) { case FIG_SUB_SPLINE_OPEN_X: case FIG_SUB_SPLINE_CLOSED_X: { if(((fwp->cob)->det).pll.spt) { spp = dk_new(dk_fig_sp_pt_t,1); if(spp) { spp->npt = ((fwp->cob)->det).pll.npn; ((fwp->cob)->det).pll.npn = ((fwp->cob)->det).pll.npn + 1UL; spp->x = x; spp->y = y; spp->s = s; if(dksto_add(((fwp->cob)->det).pll.spt, (void *)spp)) { back = spp->npt; } else { dk_delete(spp); } } } } break; } } } } return back; } /** Add open arc. @param fwp Writer structure. @param x Center x. @param y Center y. @param r Radius. @param a0 Start angle in radians. @param a1 End angle in radians. @return Positive number on success, 0 on error. */ unsigned long dkfigw_open_arc DK_P6(dk_fig_writer_t *,fwp, double,x, double,y, double,r, double,a0, double,a1) { unsigned long back = 0UL; dk_fig_object_t *obj; obj = object_new(fwp, FIG_OBJECT_ARC, FIG_SUB_ARC_OPEN); if(obj) { back = obj->obn; (obj->det).arc.xm = x; (obj->det).arc.ym = y; (obj->det).arc.ra = r; (obj->det).arc.a0 = a0; (obj->det).arc.a1 = a1; } return back; } /** Add closed arc (pie wedge). @param fwp Writer structure. @param x Center x. @param y Center y. @param r Radius. @param a0 Start angle in radians. @param a1 End angle in radians. @return Positive number on success, 0 on error. */ unsigned long dkfigw_closed_arc DK_P6(dk_fig_writer_t *,fwp, double,x, double,y, double,r, double,a0, double,a1) { unsigned long back = 0UL; dk_fig_object_t *obj; obj = object_new(fwp, FIG_OBJECT_ARC, FIG_SUB_ARC_CLOSED); if(obj) { back = obj->obn; (obj->det).arc.xm = x; (obj->det).arc.ym = y; (obj->det).arc.ra = r; (obj->det).arc.a0 = a0; (obj->det).arc.a1 = a1; } return back; } /** Add circle. @param fwp Writer structure. @param x Center x. @param y Center y. @param r Radius. @return Positive number on success, 0 on error. */ unsigned long dkfigw_circle DK_P4(dk_fig_writer_t *,fwp, double,x, double,y, double,r) { unsigned long back = 0UL; dk_fig_object_t *obj; obj = object_new(fwp, FIG_OBJECT_ELLIPSE, FIG_SUB_CIRCLE_RADIUS); if(obj) { back = obj->obn; (obj->det).ell.xm = x; (obj->det).ell.ym = y; (obj->det).ell.rx = r; (obj->det).ell.ry = r; (obj->det).ell.ro = 0.0; } return back; } /** Add ellipse. @param fwp Writer structure. @param x Center x. @param y Center y. @param rx Horizontal radius. @param ry Vertical radius. @param rot Rotation in radians. @return Positive number on success, 0 on error. */ unsigned long dkfigw_ellipse DK_P6(dk_fig_writer_t *,fwp, double,x, double,y, double,rx, double,ry, double,rot) { unsigned long back = 0UL; dk_fig_object_t *obj; obj = object_new(fwp, FIG_OBJECT_ELLIPSE, FIG_SUB_ELLIPSE_RADII); if(obj) { back = obj->obn; (obj->det).ell.xm = x; (obj->det).ell.ym = y; (obj->det).ell.rx = rx; (obj->det).ell.ry = ry; (obj->det).ell.ro = rot; } return back; } /** Add text. @param fwp Writer structure. @param x X position. @param y Y position. @param t Text. @param a Rotation in radians. @return Positive number on success, 0 on error. */ unsigned long dkfigw_text DK_P5(dk_fig_writer_t *,fwp, double,x, double,y, char *,t, double,a) { unsigned long back = 0UL; dk_fig_object_t *obj; if(fwp) { obj = object_new(fwp, FIG_OBJECT_TEXT, (fwp->sty).tal); if(obj) { (obj->det).txt.x = x; (obj->det).txt.y = y; (obj->det).txt.rot = a; (obj->det).txt.txt = dkstr_dup(t); if((obj->det).txt.txt) { back = obj->obn; } } } return back; } /** Set text alignment for all following texts added. @param fwp Writer structure. @param tal Alignment (FIG_SUB_TEXT_xxx). */ void dkfigw_set_text_align DK_P2(dk_fig_writer_t *,fwp, unsigned char,tal) { if(fwp) { if(tal < FIG_SUB_TEXT_LEFT) { (fwp->sty).tal = FIG_SUB_TEXT_LEFT; } else { if(tal > FIG_SUB_TEXT_RIGHT) { (fwp->sty).tal = FIG_SUB_TEXT_RIGHT; } else { (fwp->sty).tal = tal; } } } } /** Set/reset rigid flag for all following texts added. @param fwp Writer structure. @param fl Set (non-zero) or reset (0) flag. */ void dkfigw_set_text_rigid DK_P2(dk_fig_writer_t *,fwp, int,fl) { if(fwp) { if(fl) { (fwp->sty).ffl |= FIG_TEXTFLAG_RIGID; } else { (fwp->sty).ffl &= (~( FIG_TEXTFLAG_RIGID)); } } } /** Set/reset special flag for all following texts added. @param fwp Writer structure. @param fl Set (non-zero) or reset (0) flag. */ void dkfigw_set_text_special DK_P2(dk_fig_writer_t *,fwp, int,fl) { if(fwp) { if(fl) { (fwp->sty).ffl |= FIG_TEXTFLAG_SPECIAL; } else { (fwp->sty).ffl &= (~(FIG_TEXTFLAG_SPECIAL)); } } } /** Set PS font index for all following texts added. @param fwp Writer structure. @param fno Font index (0 to 34). */ void dkfigw_set_text_psfont DK_P2(dk_fig_writer_t *,fwp, unsigned char,fno) { if(fwp) { if(fno < 0x00) { (fwp->sty).fno = FIG_FONT_PS_DEFAULT; } else { if(fno > FIG_FONT_PS_ZAPF_DINGBATS) { (fwp->sty).fno = FIG_FONT_PS_ZAPF_DINGBATS; } else { (fwp->sty).fno = fno; } } (fwp->sty).ffl |= FIG_TEXTFLAG_PS; } } /** Set PS font for all following texts added, choose font by name. @param fwp Writer structure. @param n Font name: one of the strings in font_names. */ void dkfigw_set_text_psfont_by_name DK_P2(dk_fig_writer_t *,fwp, char *,n) { int i; if(fwp) { if(n) { i = my_str_array_index(font_names, n, 0, fwp->ver); if(i < 0) i = 0; dkfigw_set_text_psfont(fwp, (unsigned char)i); } } } /** Set LaTeX font index for all following texts added. @param fwp Writer structure. @param fno Font index (0=default, 1=roman, 2=bold, 3=italic, 4=sans-serif, 5=typewriter). */ void dkfigw_set_text_latexfont DK_P2(dk_fig_writer_t *,fwp, unsigned char,fno) { if(fwp) { if(fno < 0x00) { (fwp->sty).fno = 0x00; } else { if(fno > FIG_FONT_LATEX_TYPEWRITER) { (fwp->sty).fno = FIG_FONT_LATEX_TYPEWRITER; } else { (fwp->sty).fno = fno; } } (fwp->sty).ffl &= (~(FIG_TEXTFLAG_PS)); } } /** Set text size fo all following texts added. @param fwp Writer structure. @param fsz Font size in pt. */ void dkfigw_set_text_size DK_P2(dk_fig_writer_t *,fwp, double,fsz) { if(fwp) { (fwp->sty).fsz = fsz; if((fwp->sty).fsz < 0.0) (fwp->sty).fsz = 0.0; } } /** Set layer for all following objects. @param fwp Writer structure. @param lay Layer number. */ void dkfigw_set_layer DK_P2(dk_fig_writer_t *,fwp, unsigned short,lay) { if(fwp) { if(lay < 0) { (fwp->sty).lay = 0; } else { if(lay > 999) { (fwp->sty).lay = 999; } else { (fwp->sty).lay = lay; } } } } /** Move one layer upwards. @param fwp Writer structure. @return Non-zero number on success, 0 on error. */ int dkfigw_layer_up DK_P1(dk_fig_writer_t *,fwp) { int back = 0; if(fwp) { (fwp->sty).lay = (fwp->sty).lay - 1; if((fwp->sty).lay >= 0) { back = 1; } else { (fwp->sty).lay = 0; } } return back; } /** Set pen color for all following objects. @param fwp Writer structure. @param col Color cell number (0 to 31 for predefined colors, 32 and above for self-defined colors). */ void dkfigw_set_pen_color DK_P2(dk_fig_writer_t *,fwp, short,col) { if(fwp) { if(col < -1) { (fwp->sty).pco = -1; } else { (fwp->sty).pco = col; } } } /** Set pen color for all following objects by color name. @param fwp Writer structure. @param n Color name: One of the names in color_names. */ void dkfigw_set_pen_color_by_name DK_P2(dk_fig_writer_t *,fwp, char *,n) { int i; if(fwp) { if(n) { i = my_str_array_index(color_names, n, 0, fwp->ver); if(i < 0) i = 0; dkfigw_set_pen_color(fwp, (short)i); } } } /** Set fill color for all following objects. @param fwp Writer structure. @param col Color cell number, either a user defined color (32 and above) or a predefined color: FIG_COLOR_BLACK, FIG_COLOR_BLUE, FIG_COLOR_GREEN, FIG_COLOR_CYAN, FIG_COLOR_RED, FIG_COLOR_MAGENTA, FIG_COLOR_YELLOW, FIG_COLOR_WHITE, FIG_COLOR_DARKEST_BLUE, FIG_COLOR_DARK_BLUE, FIG_COLOR_LIGHT_BLUE, FIG_COLOR_LIGHTEST_BLUE, FIG_COLOR_DARK_GREEN, FIG_COLOR_NORMAL_GREEN, FIG_COLOR_LIGHT_GREEN, FIG_COLOR_DARK_CYAN, FIG_COLOR_NORMAL_CYAN, FIG_COLOR_LIGHT_CYAN, FIG_COLOR_DARK_RED, FIG_COLOR_NORMAL_RED, FIG_COLOR_LIGHT_RED, FIG_COLOR_DARK_MAGENTA, FIG_COLOR_NORMAL_MAGENTA, FIG_COLOR_LIGHT_MAGENTA, FIG_COLOR_DARK_BROWN, FIG_COLOR_NORMAL_BROWN, FIG_COLOR_LIGHT_BROWN, FIG_COLOR_DARKEST_PINK, FIG_COLOR_DARK_PINK, FIG_COLOR_LIGHT_PINK, FIG_COLOR_LIGHTEST_PINK or FIG_COLOR_GOLD. */ void dkfigw_set_fill_color DK_P2(dk_fig_writer_t *,fwp, short,col) { if(fwp) { if(col < -1) { (fwp->sty).fco = -1; } else { (fwp->sty).fco = col; } } } /** Set fill color for all following objects by color name. @param fwp Writer structure. @param n Color name: One of the names in color_names. */ void dkfigw_set_fill_color_by_name DK_P2(dk_fig_writer_t *,fwp, char *,n) { int i; if(fwp) { if(n) { i = my_str_array_index(color_names, n, 0, fwp->ver); if(i < 0) i = 7; dkfigw_set_fill_color(fwp, (short)i); } } } /** Set transparent color @param fwp Writer structure. @param col Index of the transparent color. */ void dkfigw_set_transparent_color DK_P2(dk_fig_writer_t *,fwp, short,col) { if(fwp) { if(col < -3) { fwp->tco = -3; } else { fwp->tco = col; } } } /** Set fill style for all following objects. @param fwp Writer structure. @param fil Fill style, one from: FIG_FILL_NONE, FIG_FILL_BLACK, FIG_FILL_005, FIG_FILL_010, FIG_FILL_015, FIG_FILL_020, FIG_FILL_025, FIG_FILL_030, FIG_FILL_035, FIG_FILL_040, FIG_FILL_045, FIG_FILL_050, FIG_FILL_055, FIG_FILL_060, FIG_FILL_065, FIG_FILL_070, FIG_FILL_075, FIG_FILL_080, FIG_FILL_085, FIG_FILL_090, FIG_FILL_095, FIG_FILL_100, FIG_FILL_PURE, FIG_FILL_105, FIG_FILL_110, FIG_FILL_115, FIG_FILL_120, FIG_FILL_125, FIG_FILL_130, FIG_FILL_135, FIG_FILL_140, FIG_FILL_145, FIG_FILL_150, FIG_FILL_155, FIG_FILL_160, FIG_FILL_165, FIG_FILL_170, FIG_FILL_175, FIG_FILL_180, FIG_FILL_185, FIG_FILL_190, FIG_FILL_195, FIG_FILL_200, FIG_FILL_WHITE, FIG_FILL_LEFT_DIAGONAL_30, FIG_FILL_RIGHT_DIAGONAL_30, FIG_FILL_CROSSHATCH_30, FIG_FILL_LEFT_DIAGONAL_45, FIG_FILL_RIGHT_DIAGONAL_45, FIG_FILL_CROSSHATCH_45, FIG_FILL_BRICKS_HORIZONTAL, FIG_FILL_BRICKS_VERTICAL, FIG_FILL_HORIZONTAL_LINES, FIG_FILL_VERTICAL_LINES, FIG_FILL_CROSSHATCH, FIG_FILL_HORIZONTAL_SHINGLES_RIGHT, FIG_FILL_HORIZONTAL_SHINGLES_LEFT, FIG_FILL_VERTICAL_SHINGLES_1, FIG_FILL_VERTICAL_SHINGLES_2, FIG_FILL_LARGE_FISH_SCALES, FIG_FILL_SMALL_FISH_SCALES, FIG_FILL_CIRCLES, FIG_FILL_HEXAGONS, FIG_FILL_OCTAGONS, FIG_FILL_HORIZONTAL_TIRE_TREADS or FIG_FILL_VERTICAL_TIRE_TREADS. */ void dkfigw_set_fill_style DK_P2(dk_fig_writer_t *,fwp, unsigned char, fil) { if(fwp) { if(fil < -1) { (fwp->sty).fil = -1; } else { if(fil > 62) { (fwp->sty).fil = 62; if(fil > 127) { (fwp->sty).fil = 0xFF; } } else { (fwp->sty).fil = fil; } } } } /** Set line style for all following objects. @param fwp Writer structure. @param lst Line style, one from: FIG_LS_SOLID, FIG_LS_DASHED, FIG_LS_DOTTED, FIG_LS_DASH_DOTTED, FIG_LS_DASH_DOUBLE_DOTTED or FIG_LS_DASH_TRIPLE_DOTTED. */ void dkfigw_set_line_style DK_P2(dk_fig_writer_t *,fwp, unsigned char, lst) { if(fwp) { if(lst < FIG_LS_SOLID) { (fwp->sty).lst = FIG_LS_DEFAULT; } else { if(lst > FIG_LS_DASH_TRIPLE_DOTTED) { (fwp->sty).lst = FIG_LS_DASH_TRIPLE_DOTTED; } else { (fwp->sty).lst = lst; } } } } /** Set line width for all following objects. @param fwp Writer structure. @param lw Line width in Fig linewidth units (1/80 inch). */ void dkfigw_set_line_width DK_P2(dk_fig_writer_t *,fwp, short,lw) { if(fwp) { (fwp->sty).liw = ((lw >= 0) ? lw : 0); } } /** Set "angle-in-degree" flag in writer. @param fwp Writer structure. @param fl Set (non-zero value) or reset (0) the flag. */ void dkfigw_set_angle_degree DK_P2(dk_fig_writer_t *,fwp, int,fl) { if(fwp) { fwp->ang = (fl ? 0x01 : 0x00); } } /** Set line join style for all following objects. @param fwp Writer structure. @param ljn Line join style, one from: FIG_LJ_MITER, FIG_LJ_ROUND, or FIG_LJ_BEVEL. */ void dkfigw_set_line_join DK_P2(dk_fig_writer_t *,fwp, unsigned char, ljn) { if(fwp) { if(ljn < FIG_LJ_MITER) { (fwp->sty).ljn = FIG_LJ_MITER; } else { if(ljn > FIG_LJ_BEVEL) { (fwp->sty).ljn = FIG_LJ_BEVEL; } else { (fwp->sty).ljn = ljn; } } } } /** Set line cap style for all following objects. @param fwp Writer structure. @param lcp Line cap style, one from: FIG_CS_BUTT, FIG_CS_ROUND or FIG_CS_PROJECTING. */ void dkfigw_set_line_cap DK_P2(dk_fig_writer_t *,fwp, unsigned char, lcp) { if(fwp) { if(lcp < FIG_CS_BUTT) { (fwp->sty).lcp = FIG_CS_BUTT; } else { if(lcp > FIG_CS_PROJECTING) { (fwp->sty).lcp = FIG_CS_PROJECTING; } else { (fwp->sty).lcp = lcp; } } } } /** Set shape, fill type and lengths for one arrowhead. @param ah Arrowhead structure. @param sha Shape. @param fil Fill type. @param wid Width. @param hei Height */ static void set_arrowhead DK_P5(dk_fig_ah_t *,ah, unsigned char,sha, unsigned char,fil, double,wid, double,hei) { ah->sha = sha; ah->fil = fil; ah->wid = wid; ah->hei = hei; } /** Set shape, fill type and lengths for forward arrowhead. @param fwp Fig writer structure. @param sha Shape. @param fil Fill type. @param wid Width. @param hei Height */ void dkfigw_set_arrowhead_f DK_P5(dk_fig_writer_t *,fwp, unsigned char,sha, unsigned char,fil, double,wid, double, hei) { if(fwp) { set_arrowhead(&((fwp->sty).fwa), sha, fil, wid, hei); } } /** Set shape, fill type and lengths for backward arrowhead. @param fwp Fig writer structure. @param sha Shape. @param fil Fill type. @param wid Width. @param hei Height */ void dkfigw_set_arrowhead_b DK_P5(dk_fig_writer_t *,fwp, unsigned char,sha, unsigned char,fil, double,wid, double, hei) { if(fwp) { set_arrowhead(&((fwp->sty).bwa), sha, fil, wid, hei); } } /** Set arrowheads directions. @param fwp Fig writer structure. @param ahs Directions (0x00=no arrowheads, 0x01=forward, 0x02=backward, 0x03=both forward and backward). */ void dkfigw_set_arrowheads DK_P2(dk_fig_writer_t *,fwp, unsigned char,ahs) { if(fwp) { (fwp->sty).ahs = ahs; } } /** Write one keyword from the \arg kw array to output stream. @param os Output stream. @param n Keyword index. */ static void kw_out DK_P2(dk_stream_t *,os, size_t,n) { dkstream_puts(os, kw[n]); } /** Write one arrowhead line to output stream. @param os Output stream. @param fwp Fig writer structure. @param sty Fig style structure. @param ah Arrowhead structure. @param o Current object. */ static void put_arrow DK_P5(dk_stream_t *,os, dk_fig_writer_t *,fwp, dk_fig_style_t *,sty, dk_fig_ah_t *,ah, dk_fig_object_t *,o) { kw_out(os, 1); kw_out(os, 1); put_int(os, uc_to_int(ah->sha)); kw_out(os, 1); put_int(os, uc_to_int(ah->fil)); kw_out(os, 1); put_double(os, dkma_l_to_double((long)(sty->liw))); kw_out(os, 1); put_double(os, dkma_rint(d_to_fig_d(fwp, ah->wid))); kw_out(os, 1); put_double(os, dkma_rint(d_to_fig_d(fwp, ah->hei))); kw_out(os, 0); } /** Initial settings for arrowheads. @param fwp Fig structure. */ void dkfigw_set_suggested_arrow_settings DK_P1(dk_fig_writer_t *,fwp) { if(fwp) { switch(fwp->uni) { case 1: { set_arrowhead(&((fwp->sty).fwa),1,1,72.001/in_to_fig,120.001/in_to_fig); set_arrowhead(&((fwp->sty).bwa),1,1,72.001/in_to_fig,120.001/in_to_fig); } break; case 2: { set_arrowhead(&((fwp->sty).fwa),1,1,72.001/cm_to_fig,120.001/cm_to_fig); set_arrowhead(&((fwp->sty).bwa),1,1,72.001/cm_to_fig,120.001/cm_to_fig); } break; default: { set_arrowhead(&((fwp->sty).fwa), 1, 1, 72.001, 120.001); set_arrowhead(&((fwp->sty).bwa), 1, 1, 72.001, 120.001); } break; } } } /** Write line to start a spline to output stream. @param os Output stream. @param f Fig writer structure. @param o Current object. @param sty Fig style structure. @param np Number of points. @param afw Flag: Arrowhead forward. @param abw Flag: Arrowhead backward. */ static void spline_start DK_P7(dk_stream_t *,os, dk_fig_writer_t *,f, dk_fig_object_t *,o, dk_fig_style_t *,sty, unsigned long,np, int,afw, int,abw) { /* 3 (type) */ put_int(os, 3); kw_out(os, 1); /* sub type */ put_int(os, o->stp); kw_out(os, 1); /* line style */ put_int_range(os, uc_to_int(sty->lst),-1,FIG_LS_DASH_TRIPLE_DOTTED); kw_out(os, 1); /* thickness */ put_int(os, (int)(sty->liw)); kw_out(os, 1); /* pen color */ put_int(os, (int)(sty->pco)); kw_out(os, 1); /* fill color */ put_int(os, (int)(sty->fco)); kw_out(os, 1); /* layer */ put_unsigned(os, (unsigned)(sty->lay)); kw_out(os, 1); /* pen style */ put_unsigned(os, 0); kw_out(os, 1); /* area fill */ put_int(os, uc_to_int(sty->fil)); kw_out(os, 1); /* style value */ put_double(os, sty->sva); kw_out(os, 1); /* cap style */ put_int(os, uc_to_int(sty->lcp)); kw_out(os, 1); /* forward arrow */ put_int(os, (afw ? 1 : 0)); kw_out(os, 1); /* backward arrow */ put_int(os, (abw ? 1 : 0)); kw_out(os, 1); /* npoints */ put_long(os, (long)np); kw_out(os, 0); } /** Write points coordinates to output stream. @param os Output stream. @param f Fig writer structure. @param o Current object. */ static void spline_points DK_P3(dk_stream_t *,os, dk_fig_writer_t *,f, dk_fig_object_t *,o) { dk_storage_iterator_t *it; dk_fig_sp_pt_t *pt; unsigned long ptno; ptno = 0UL; it = (o->det).pll.ipt; dksto_it_reset(it); while((pt = (dk_fig_sp_pt_t *)dksto_it_next(it)) != NULL) { if((ptno % 5UL) == 0UL) { if(ptno) { kw_out(os, 0); } kw_out(os, 14); } else { kw_out(os, 1); } put_long(os, x_to_fig_l(f, pt->x)); kw_out(os, 1); put_long(os, y_to_fig_l(f, pt->y)); ptno++; } kw_out(os, 0); ptno = 0UL; it = (o->det).pll.ipt; dksto_it_reset(it); while((pt = (dk_fig_sp_pt_t *)dksto_it_next(it)) != NULL) { if((ptno % 10UL) == 0UL) { if(ptno) { kw_out(os, 0); } kw_out(os, 14); } else { kw_out(os, 1); } put_double(os, pt->s); ptno++; } kw_out(os, 0); } /** Write start-of-polyline line to output stream. @param os Output stream. @param f Fig writer structure. @param o Current object. @param sty Fig style structure. @param np Number of points. @param afw Flag: Arrowhead forward. @param abw Flag: Arrowhead backward. */ static void polyline_start DK_P7(dk_stream_t *,os, dk_fig_writer_t *,f, dk_fig_object_t *,o, dk_fig_style_t *,sty, unsigned long,np, int,afw, int,abw) { long rcorner; /* 2 (type) */ put_int(os, o->otp); kw_out(os, 1); /* subtype */ put_int(os, o->stp); kw_out(os, 1); /* line style */ put_int_range(os, uc_to_int(sty->lst),-1,FIG_LS_DASH_TRIPLE_DOTTED); kw_out(os, 1); /* thickness */ put_int(os, (int)(sty->liw)); kw_out(os, 1); /* pen color */ put_int(os, (int)(sty->pco)); kw_out(os, 1); /* fill color */ put_int(os, (int)(sty->fco)); kw_out(os, 1); /* layer */ put_unsigned(os, (unsigned)(sty->lay)); kw_out(os, 1); /* penstyle */ put_unsigned(os, 0); kw_out(os, 1); /* area fill */ put_int(os, uc_to_int(sty->fil)); kw_out(os, 1); /* style value */ put_double(os, sty->sva); kw_out(os, 1); /* join style */ put_int(os, uc_to_int(sty->ljn)); kw_out(os, 1); /* cap style */ put_int(os, uc_to_int(sty->lcp)); kw_out(os, 1); /* radius */ switch(o->stp) { case FIG_SUB_ARC_BOX: { rcorner = d_to_fig_l(f, (o->det).pll.cr); if(rcorner < 0L) rcorner = 0L; rcorner = rcorner / 15L; put_long(os, rcorner); } break; default: { put_int(os, 0); } break; } kw_out(os, 1); /* flag: forward arrow */ put_int(os, (afw ? 1 : 0)); kw_out(os, 1); /* flag: backward arrow */ put_int(os, (abw ? 1 : 0)); kw_out(os, 1); /* number of points */ put_long(os, (long)np); kw_out(os, 0); } /** Write polyline points coordinates to output stream. @param os Output stream. @param f Fig writer structure. @param o Current object. @param flcl Flag: Closed polygon (repeat first point at end). */ static void polyline_points DK_P4(dk_stream_t *,os, dk_fig_writer_t *,f, dk_fig_object_t *,o, int,flcl) { dk_storage_iterator_t *it; dk_fig_pl_pt_t *pt; unsigned long ptno; ptno = 0UL; it = (o->det).pll.ipt; dksto_it_reset(it); while((pt = (dk_fig_pl_pt_t *)dksto_it_next(it)) != NULL) { if((ptno % 5UL) == 0UL) { if(ptno) { kw_out(os, 0); } kw_out(os, 14); } else { kw_out(os, 1); } put_long(os, x_to_fig_l(f, pt->x)); kw_out(os, 1); put_long(os, y_to_fig_l(f, pt->y)); ptno++; } if(flcl) { dksto_it_reset(it); pt = (dk_fig_pl_pt_t *)dksto_it_next(it); if(pt) { if((ptno % 5UL) == 0UL) { if(ptno) { kw_out(os, 0); } kw_out(os, 14); } else { kw_out(os, 1); } put_long(os, x_to_fig_l(f, pt->x)); kw_out(os, 1); put_long(os, y_to_fig_l(f, pt->y)); } } kw_out(os, 0); } /** Write points coordinates for box (rectangle, image or arc box). @param os Output stream. @param f Fig writer structure. @param o Current object. */ static void box_points DK_P3(dk_stream_t *,os, dk_fig_writer_t *,f, dk_fig_object_t *,o) { long x0; long y0; long x1; long y1; long t; x0 = x_to_fig_l(f, (o->det).pll.x0); y0 = y_to_fig_l(f, (o->det).pll.y0); x1 = x_to_fig_l(f, (o->det).pll.x1); y1 = y_to_fig_l(f, (o->det).pll.y1); if(x0 > x1) { t = x1; x1 = x0; x0 = t; } if(y0 > y1) { t = y1; y1 = y0; y0 = t; } kw_out(os, 14); /* x0 y0 */ put_long(os, x0); kw_out(os, 1); put_long(os, y0); kw_out(os, 1); /* x1 y0 */ put_long(os, x1); kw_out(os, 1); put_long(os, y0); kw_out(os, 1); /* x1 y1 */ put_long(os, x1); kw_out(os, 1); put_long(os, y1); kw_out(os, 1); /* x0 y1 */ put_long(os, x0); kw_out(os, 1); put_long(os, y1); kw_out(os, 1); /* x0 y0 */ put_long(os, x0); kw_out(os, 1); put_long(os, y0); kw_out(os, 0); } /** Put single character to stream. @param os Output stream. @param c Character to write. */ static void stream_putc DK_P2(dk_stream_t *,os, char,c) { char buffer[2]; buffer[0] = c; buffer[1] = '\0'; dkstream_write(os, buffer, 1); } /** Write text contents to output stream, apply conversion if necessary. @param os Output stream. @param txt Text to write. */ static void put_text DK_P2(dk_stream_t *,os, char *,txt) { char buffer[32]; char c; char *ptr; ptr = txt; while(*ptr) { c = *ptr; if((c >= 'a') && (c <= 'z')) { stream_putc(os, c); } else { if((c >= 'A') && (c <= 'Z')) { stream_putc(os, c); } else { if((c >= '1') && (c <= '9')) { stream_putc(os, c); } else { switch(c) { case '0': case '^': case '!': case '\"': case '$': case '%': case '&': case '/': case '(': case ')': case '=': case '?': case '\'': case '`': case '#': case '+': case '*': case '-': case '.': case ',': case '_': case ':': case ';': case '<': case '>': case '|': { stream_putc(os, c); } break; case '\\': { dkstream_puts(os, kw[19]); } break; default: { sprintf(buffer, "\\%03o", c); dkstream_puts(os, buffer); } break; } } } } ptr++; } dkstream_puts(os, kw[18]); } /** Print one object to output stream. @param os Output stream. @param f Fig writer structure. @param o Object to print. */ static void print_object DK_P3(dk_stream_t *,os, dk_fig_writer_t *,f, dk_fig_object_t *,o) { dk_fig_style_t sty; unsigned char afw; unsigned char abw; double alpha; double v; unsigned long npoints; int textflags; double tw; double th; afw = abw = 0x00; DK_MEMCPY(&sty,&(o->sty),sizeof(dk_fig_style_t)); if((o->sty).ahs & 0x01) { afw = 0x01; } if((o->sty).ahs & 0x02) { abw = 0x01; } switch(o->otp) { case FIG_OBJECT_ARC: { switch(o->stp) { case FIG_SUB_ARC_OPEN: { sty.fco = FIG_COLOR_DEFAULT; sty.fil = FIG_FILL_NONE; } break; case FIG_SUB_ARC_CLOSED: { afw = abw = 0x00; } break; } /* object code */ put_int(os, 5); kw_out(os, 1); /* sub type */ put_int(os, o->stp); kw_out(os, 1); /* line style */ put_int_range(os,uc_to_int(sty.lst),-1,FIG_LS_DASH_TRIPLE_DOTTED); kw_out(os, 1); /* line width */ put_int(os, (int)(sty.liw)); kw_out(os, 1); /* pen color */ put_int(os, (int)(sty.pco)); kw_out(os, 1); /* fill color */ put_int(os, (int)(sty.fco)); kw_out(os, 1); /* layer */ put_unsigned(os, (unsigned)(sty.lay)); kw_out(os, 1); /* pen_style */ put_unsigned(os, 0); kw_out(os, 1); /* area fill */ put_int(os, uc_to_int(sty.fil)); kw_out(os, 1); /* float styleval */ put_double(os, sty.sva); kw_out(os, 1); /* cap style */ put_int(os, uc_to_int(sty.lcp)); kw_out(os, 1); /* direction (0) */ put_unsigned(os, 0); kw_out(os, 1); /* forward arrow */ put_int(os, (afw ? 1 : 0)); kw_out(os, 1); /* backward arrow */ put_int(os, (abw ? 1 : 0)); kw_out(os, 1); /* float center x */ put_double(os, x_to_fig_d(f, (o->det).arc.xm)); kw_out(os, 1); /* float center y */ put_double(os, y_to_fig_d(f, (o->det).arc.ym)); kw_out(os, 1); /* x1 */ alpha = (o->det).arc.a0; if(f->ang) alpha = alpha * M_PI / 180.0; v = (o->det).arc.xm + (o->det).arc.ra * cos(alpha); put_long(os, x_to_fig_l(f, v)); kw_out(os, 1); /* y1 */ v = (o->det).arc.ym + (o->det).arc.ra * sin(alpha); put_long(os, y_to_fig_l(f, v)); kw_out(os, 1); /* x2 */ alpha = 0.5 * ((o->det).arc.a0 + (o->det).arc.a1); if(f->ang) alpha = alpha * M_PI / 180.0; v = (o->det).arc.xm + (o->det).arc.ra * cos(alpha); put_long(os, x_to_fig_l(f, v)); kw_out(os, 1); /* y2 */ v = (o->det).arc.ym + (o->det).arc.ra * sin(alpha); put_long(os, y_to_fig_l(f, v)); kw_out(os, 1); /* x3 */ alpha = (o->det).arc.a1; if(f->ang) alpha = alpha * M_PI / 180.0; v = (o->det).arc.xm + (o->det).arc.ra * cos(alpha); put_long(os, x_to_fig_l(f, v)); kw_out(os, 1); /* y3 */ v = (o->det).arc.ym + (o->det).arc.ra * sin(alpha); put_long(os, y_to_fig_l(f, v)); kw_out(os, 0); if(afw) { put_arrow(os, f, &sty, &(sty.fwa), o); } if(abw) { put_arrow(os, f, &sty, &(sty.bwa), o); } } break; case FIG_OBJECT_ELLIPSE: { long cx, cy, rx, ry; switch(o->stp) { case FIG_SUB_ELLIPSE_RADII: { afw = abw = 0x00; } break; case FIG_SUB_CIRCLE_RADIUS: { afw = abw = 0x00; } break; } /* object type (1) */ put_int(os, 1); kw_out(os, 1); /* sub type (1 or 3) */ put_int(os, o->stp); kw_out(os, 1); /* line style */ put_int(os, uc_to_int((o->sty).lst)); kw_out(os, 1); /* thickness */ put_int(os, (int)((o->sty).liw)); kw_out(os, 1); /* pen color */ put_int(os, (int)((o->sty).pco)); kw_out(os, 1); /* fill color */ put_int(os, (int)((o->sty).fco)); kw_out(os, 1); /* layer (depth) */ put_unsigned(os, (o->sty).lay); kw_out(os, 1); /* pen style */ put_int(os, 0); kw_out(os, 1); /* area fill */ put_int(os, uc_to_int((o->sty).fil)); kw_out(os, 1); /* float style value */ put_double(os, (o->sty).sva); kw_out(os, 1); /* direction (always 1) */ put_int(os, 1); kw_out(os, 1); /* float angle (rotation) */ alpha = (o->det).ell.ro; if(f->ang) { alpha = alpha * M_PI / 180.0; } put_long_double(os, alpha); kw_out(os, 1); /* center x */ cx = x_to_fig_l(f, (o->det).ell.xm); put_long(os, cx); kw_out(os, 1); /* center y */ cy = y_to_fig_l(f, (o->det).ell.ym); put_long(os, cy); kw_out(os, 1); /* radius x */ rx = d_to_fig_l(f, (o->det).ell.rx); put_long(os, rx); kw_out(os, 1); /* radiux y */ ry = d_to_fig_l(f, (o->det).ell.ry); put_long(os, ry); kw_out(os, 1); /* start x */ put_long(os, (cx - rx)); kw_out(os, 1); /* start y */ put_long(os, (cy - ry)); kw_out(os, 1); /* end x */ put_long(os, (cx + rx)); kw_out(os, 1); /* end y */ put_long(os, (cy + ry)); kw_out(os, 0); } break; case FIG_OBJECT_POLYLINE: { switch(o->stp) { case FIG_SUB_POLYLINE: { sty.fco = FIG_COLOR_DEFAULT; sty.fil = FIG_FILL_NONE; npoints = 0UL; if((o->det).pll.spt) { if((o->det).pll.ipt) { dksto_it_reset((o->det).pll.ipt); while(dksto_it_next((o->det).pll.ipt)) npoints++; if(npoints > 1UL) { polyline_start(os, f, o, &sty, npoints, afw, abw); if(afw) { put_arrow(os, f, &sty, &(sty.fwa), o); } if(abw) { put_arrow(os, f, &sty, &(sty.bwa), o); } polyline_points(os, f, o, 0); } } } } break; case FIG_SUB_BOX: { afw = abw = 0x00; polyline_start(os, f, o, &sty, 5UL, afw, abw); /* Points line. */ box_points(os, f, o); } break; case FIG_SUB_POLYGON: { afw = abw = 0x00; npoints = 1UL; if((o->det).pll.spt) { if((o->det).pll.ipt) { dksto_it_reset((o->det).pll.ipt); while(dksto_it_next((o->det).pll.ipt)) npoints++; if(npoints > 2UL) { polyline_start(os, f, o, &sty, npoints, afw, abw); polyline_points(os, f, o, 1); } } } } break; case FIG_SUB_ARC_BOX: { afw = abw = 0x00; polyline_start(os, f, o, &sty, 5UL, afw, abw); /* Points line */ box_points(os, f, o); } break; case FIG_SUB_IMAGE: { if((o->det).pll.fn) { sty.fco = FIG_COLOR_DEFAULT; sty.fil = FIG_FILL_NONE; afw = abw = 0x00; polyline_start(os, f, o, &sty, 5UL, afw, abw); /* file name line */ kw_out(os, 1); put_int(os, 0); kw_out(os, 1); dkstream_puts(os, (o->det).pll.fn); kw_out(os, 0); /* Points line */ box_points(os, f, o); } } break; } } break; case FIG_OBJECT_SPLINE: { switch(o->stp) { case FIG_SUB_SPLINE_OPEN_X: { sty.fco = FIG_COLOR_DEFAULT; sty.fil = FIG_FILL_NONE; } break; case FIG_SUB_SPLINE_CLOSED_X: { afw = abw = 0x00; } break; } npoints = 0UL; if((o->det).pll.spt) { if((o->det).pll.ipt) { dksto_it_reset((o->det).pll.ipt); while(dksto_it_next((o->det).pll.ipt)) { npoints++; } if(npoints > 1UL) { spline_start(os, f, o, &sty, npoints, afw, abw); if(afw) { put_arrow(os, f, &sty, &(sty.fwa), o); } if(abw) { put_arrow(os, f, &sty, &(sty.bwa), o); } spline_points(os, f, o); } } } } break; case FIG_OBJECT_TEXT: { sty.fco = FIG_COLOR_DEFAULT; sty.fil = FIG_FILL_NONE; afw = abw = 0x00; if((o->det).txt.txt) { alpha = (o->det).ell.ro; if(f->ang) { alpha = alpha * M_PI / 180.0; } textflags = uc_to_int(sty.ffl) & 15; /* 4 (type) */ put_int(os, 4); kw_out(os, 1); /* sub type */ put_int(os, (o->stp)); kw_out(os, 1); /* color */ put_int(os, (int)(sty.pco)); kw_out(os, 1); /* layer */ put_unsigned(os, (unsigned)(sty.lay)); kw_out(os, 1); /* pen style */ put_unsigned(os, 1); kw_out(os, 1); /* font number */ put_int(os, uc_to_int(sty.fno)); kw_out(os, 1); /* float: font size */ put_double(os, sty.fsz); kw_out(os, 1); th = 250.0 * sty.fsz / 12.0; tw = strlen((o->det).txt.txt) * 833.0 / 5.0; /* float: rotation */ put_double(os, alpha); kw_out(os, 1); /* font flags */ put_int(os, textflags); kw_out(os, 1); /* float: height (Fig units) */ put_double(os, th); kw_out(os, 1); /* float: length (Fig units) */ put_double(os, tw); kw_out(os, 1); /* x */ put_long(os, x_to_fig_l(f, (o->det).txt.x)); kw_out(os, 1); /* y */ put_long(os, y_to_fig_l(f, (o->det).txt.y)); kw_out(os, 1); /* text */ put_text(os, (o->det).txt.txt); kw_out(os, 0); } } break; } } /** Write Fig file to stream. @param os Output stream. @param fwp Fig structure. @return 1 on success, 0 on error. */ int dkfigw_write DK_P2(dk_stream_t *,os, dk_fig_writer_t *,fwp) { int back = 1; unsigned u; char buffer[64]; dk_fig_cc_t *ccptr; dk_fig_object_t *objptr; switch(fwp->uni) { case 1: { /* inches */ fwp->iwf = in_to_fig * fwp->imw; fwp->ihf = in_to_fig * fwp->imh; fwp->xsh = 0.5 * (ceil(fwp->iwf) - fwp->iwf); fwp->ysh = 0.5 * (ceil(fwp->ihf) - fwp->ihf); fwp->iwf = ceil(fwp->iwf); fwp->ihf = ceil(fwp->ihf); } break; case 2: { /* cm */ fwp->iwf = cm_to_fig * fwp->imw; fwp->ihf = cm_to_fig * fwp->imh; fwp->xsh = 0.5 * (ceil(fwp->iwf) - fwp->iwf); fwp->ysh = 0.5 * (ceil(fwp->ihf) - fwp->ihf); fwp->iwf = ceil(fwp->iwf); fwp->ihf = ceil(fwp->ihf); } break; default: { /* Fig units */ fwp->iwf = fwp->imw; fwp->xsh = 0.0; fwp->ihf = fwp->imh; fwp->ysh = 0.0; } break; } kw_out(os, 3); kw_out(os, 0); /* Portrait/Landscape */ kw_out(os, ((fwp->ori) ? 4 : 5)); kw_out(os, 0); /* Center */ kw_out(os, ((fwp->jus) ? 7 : 6)); kw_out(os, 0); /* Metric */ kw_out(os, ((fwp->fun) ? 9 : 8)); kw_out(os, 0); /* A4 */ u = (unsigned)(fwp->pap); u = TO_RANGE(u,0,14); dkstream_puts(os, paper_sizes[u]); kw_out(os, 0); /* 100.0 */ kw_out(os, 10); kw_out(os, 0); /* Single */ kw_out(os, 11); kw_out(os, 0); /* -2 */ sprintf(buffer, "%d", (int)(fwp->tco)); dkstream_puts(os, buffer); kw_out(os, 0); /* Control comments on file level. */ kw_out(os, 16); kw_out(os, 0); kw_out(os, 17); kw_out(os, 0); if(fwp->utf) { kw_out(os, 20); kw_out(os, 0); } /* 1200 2 */ kw_out(os, 13); kw_out(os, 0); /* Color cells */ if((fwp->ccs) && (fwp->cci)) { dksto_it_reset(fwp->cci); while((ccptr = (dk_fig_cc_t *)dksto_it_next(fwp->cci)) != NULL) { if((ccptr->ccn >= 32) && (ccptr->ccn <=543)) { put_int(os, 0), kw_out(os, 1); put_unsigned(os, (unsigned)(ccptr->ccn)); kw_out(os, 1); sprintf( buffer, "#%02x%02x%02x", TO_RANGE(ccptr->r,0,255), TO_RANGE(ccptr->g,0,255), TO_RANGE(ccptr->b,0,255) ); dkstream_puts(os, buffer); kw_out(os, 0); } } } /* Background rectangle */ kw_out(os, 15); kw_out(os, 0); kw_out(os, 14); /* 0 0 */ put_int(os, 0); kw_out(os, 1); put_int(os, 0); kw_out(os, 1); /* w 0 */ put_long(os, dkma_double_to_l(fwp->iwf)); kw_out(os, 1); put_int(os, 0); kw_out(os, 1); /* w h */ put_long(os, dkma_double_to_l(fwp->iwf)); kw_out(os, 1); put_long(os, dkma_double_to_l(fwp->ihf)); kw_out(os, 1); /* 0 h */ put_int(os, 0); kw_out(os, 1); put_long(os, dkma_double_to_l(fwp->ihf)); kw_out(os, 1); /* 0 0 */ put_int(os, 0); kw_out(os, 1); put_int(os, 0); kw_out(os, 0); /* Graphics elements */ if((fwp->ost) && (fwp->osi)) { dksto_it_reset(fwp->osi); while((objptr = (dk_fig_object_t *)dksto_it_next(fwp->osi)) != NULL) { print_object(os, fwp, objptr); } } return back; } /** Write Fig file to named file. @param fn File name to write to. @param fwp Fig structure. @return 1 on success, 0 on error. */ int dkfigw_file DK_P2(char *,fn, dk_fig_writer_t *,fwp) { int back = 0; char *sf = NULL; dk_stream_t *os = NULL; if(fn) { if(fwp) { sf = dksf_get_file_type_dot(fn); if(sf) { switch(dkstr_array_index(suffixes, sf, 0)) { case 0: { os = dkstream_opengz(fn, kw[2], 0, NULL); } break; case 1: { os = dkstream_openbz2(fn, kw[2], 0, NULL); } break; default: { os = dkstream_openfile(fn, kw[2], 0, NULL); } break; } } else { os = dkstream_openfile(fn, kw[2], 0, NULL); } if(os) { back = dkfigw_write(os, fwp); dkstream_close(os); } } } return back; } /** Define a new color. @param fwp Fig writer structure. @param r Red. @param g Green. @param b Blue. @return The new color cell number on success, 0 on error. */ int dkfigw_define_color DK_P4(dk_fig_writer_t *,fwp, int,r, int,g, int,b) { int back = 0; dk_fig_cc_t *cc; if((fwp->ccs) && (fwp->cci)) { cc = dk_new(dk_fig_cc_t,1); if(cc) { cc->ccn = fwp->ncc; fwp->ncc += 1; cc->r = r; cc->g = g; cc->b = b; if(cc->r < 0) cc->r = 0; if(cc->r > 255) cc->r = 255; if(cc->g < 0) cc->g = 0; if(cc->g > 255) cc->g = 255; if(cc->b < 0) cc->b = 0; if(cc->b > 255) cc->b = 255; if(dksto_add(fwp->ccs, (void *)cc)) { back = cc->ccn; } else { dk_delete(cc); cc = NULL; } } } return back; } /** Enable/disable usage of UTF-8. When creating a new Fig writer structure the LANG environment variable is inspected to set the default value. @param fwp Fig writer structure. @param fl Flag to enable/disable. */ void dkfigw_set_utf8 DK_P2(dk_fig_writer_t *,fwp, int,fl) { if(fwp) { fwp->utf = (fl ? 0x01 : 0x00); } } /** Enable/disable verbose mode. In verbose mode the module prints warnings to stderr for illegal names in dkfigw_set_xxx_by_name() functions and suggests correct value. Verbose mode is turned off by default for new Fig writer structures. @param fwp Fig writer structure. @param fl Flag to enable/disable. */ void dkfigw_set_verbose DK_P2(dk_fig_writer_t *,fwp, int,fl) { if(fwp) { fwp->ver = (fl ? 0x01 : 0x00); } }