%% options copyright owner = Dirk Krause copyright year = 2012-2014 license = bsd %% header #ifdef __cplusplus extern "C" { #endif /** Produce output. @param job Job structure. */ void f2lsvg_output(f2l_job_t *job); #ifdef __cplusplus } #endif %% module #include "dk3all.h" #include "dk3bezcu.h" #include "dk3font.h" #include "fig2lat.h" #include "f2lud.h" #include "f2lsvg.h" #include "f2lsvgst.h" #include "f2lpara.h" #include "dk3figto.h" #include "dkt-version.h" #include "dk3xsp.h" #include "dk3font.h" #include "dk3bif.h" $!trace-include /** Keywords used by the module. */ static char const * const f2lsvg_c8_kw[] = { $!string-table # # 0: Newline # \n # # 1: Space # # # 2 3 4 5: XML header line. # \n \n # # 6: Opening a tag. # < # # 7: Tag start for fragments # svg: # # 8: Closing a tag. # / # # 9: End of a tag. # > # # 10: Tag name svg # svg # # 11: Arguments for svg tag # width="%lgin" height="%lgin" viewBox="0 0 %ld %ld" # # 12 13: Attributes of complete svg tag. # xmlns="http://www.w3.org/2000/svg"\n xmlns:xlink="http://www.w3.org/1999/xlink"\n # # 14: Title tag # title # # 15: Desc tag # desc # # 16: Description # Fig file converted by fig2lat # # 17: Additional comment after description # http://dktools.sourceforge.net/fig2lat.html # # 18: defs # defs # # 19: style # style # # 20: Style type # type="text/css" # # 21: Start CDATA # # # 23 24: Start and end of font face # @font-face {\n }\n # # 25: Font family # font-family: " # # 26: End of original font family # ";\n # # 27: Oblique # font-style: oblique;\n # # 28: Italic # font-style: italic;\n # # 29: Normal # font-style: normal;\n # # 30: Font weight # font-weight: %d;\n # # 31 32 33: Font source # src: url(" .ttf ");\n # # 34 Prefix (no longer used) # file:// # # 35 # g # # 36 # />\n # # 37 38 39 # rect x="%lg" y="%lg" width="%lg" height="%lg" rx="%lg" ry="%lg" # # 40 41 42 43 # polygon points=" "\n %lg,%lg # # 44 # polyline # # 45 46 47 48 49 # circle ellipse \ncx="%lg" cy="%lg" r="%lg"\n \ntransform="translate(%lg %lg) rotate(%lg)" rx="%lg" ry="%lg"\n \ncx="%lg" cy="%lg" rx="%lg" ry="%lg"\n # # 50 51 52 53 # text > \nx="%lg" y="%lg" \ntransform="translate(%lg %lg) rotate(%lg)" x="0" y="0"\n # # 54 55 56 57 58 59 # path \nd=" M%lg,%lg\n C%lg,%lg %lg,%lg %lg,%lg L%lg,%lg\n Z # # 60 61 62 63 64 65 # \ntransform="translate(%lg %lg) rotate(%d) scale( 1 -1 ) # # 66 67 # image \nx="0" y="0" width="%lg" height="%lg"\nxlink:href=" $!end }; /** Translation table for ASCII characters. */ static char const * const f2lsvg_html_translation_table[] = { /* 0 00 */ NULL, /* 1 01 */ NULL, /* 2 02 */ NULL, /* 3 03 */ NULL, /* 4 04 */ NULL, /* 5 05 */ NULL, /* 6 06 */ NULL, /* 7 07 */ NULL, /* 8 08 */ NULL, /* 9 09 */ "\t", /* 10 0a */ NULL, /* 11 0b */ NULL, /* 12 0c */ NULL, /* 13 0d */ NULL, /* 14 0e */ NULL, /* 15 0f */ NULL, /* 16 10 */ NULL, /* 17 11 */ NULL, /* 18 12 */ NULL, /* 19 13 */ NULL, /* 20 14 */ NULL, /* 21 15 */ NULL, /* 22 16 */ NULL, /* 23 17 */ NULL, /* 24 18 */ NULL, /* 25 19 */ NULL, /* 26 1a */ NULL, /* 27 1b */ NULL, /* 28 1c */ NULL, /* 29 1d */ NULL, /* 30 1e */ NULL, /* 31 1f */ NULL, /* 32 20 */ " ", /* 33 21 */ "!", /* 34 22 */ "\"", /* 35 23 */ "#", /* 36 24 */ "$", /* 37 25 */ "%", /* 38 26 */ "&", /* 39 27 */ "'", /* 40 28 */ "(", /* 41 29 */ ")", /* 42 2a */ "*", /* 43 2b */ "+", /* 44 2c */ ",", /* 45 2d */ "-", /* 46 2e */ ".", /* 47 2f */ "/", /* 48 30 */ "0", /* 49 31 */ "1", /* 50 32 */ "2", /* 51 33 */ "3", /* 52 34 */ "4", /* 53 35 */ "5", /* 54 36 */ "6", /* 55 37 */ "7", /* 56 38 */ "8", /* 57 39 */ "9", /* 58 3a */ ":", /* 59 3b */ ";", /* 60 3c */ "<", /* 61 3d */ "=", /* 62 3e */ ">", /* 63 3f */ "?", /* 64 40 */ "@", /* 65 41 */ "A", /* 66 42 */ "B", /* 67 43 */ "C", /* 68 44 */ "D", /* 69 45 */ "E", /* 70 46 */ "F", /* 71 47 */ "G", /* 72 48 */ "H", /* 73 49 */ "I", /* 74 4a */ "J", /* 75 4b */ "K", /* 76 4c */ "L", /* 77 4d */ "M", /* 78 4e */ "N", /* 79 4f */ "O", /* 80 50 */ "P", /* 81 51 */ "Q", /* 82 52 */ "R", /* 83 53 */ "S", /* 84 54 */ "T", /* 85 55 */ "U", /* 86 56 */ "V", /* 87 57 */ "W", /* 88 58 */ "X", /* 89 59 */ "Y", /* 90 5a */ "Z", /* 91 5b */ "[", /* 92 5c */ "\\", /* 93 5d */ "]", /* 94 5e */ "^", /* 95 5f */ "_", /* 96 60 */ "`", /* 97 61 */ "a", /* 98 62 */ "b", /* 99 63 */ "c", /* 100 64 */ "d", /* 101 65 */ "e", /* 102 66 */ "f", /* 103 67 */ "g", /* 104 68 */ "h", /* 105 69 */ "i", /* 106 6a */ "j", /* 107 6b */ "k", /* 108 6c */ "l", /* 109 6d */ "m", /* 110 6e */ "n", /* 111 6f */ "o", /* 112 70 */ "p", /* 113 71 */ "q", /* 114 72 */ "r", /* 115 73 */ "s", /* 116 74 */ "t", /* 117 75 */ "u", /* 118 76 */ "v", /* 119 77 */ "w", /* 120 78 */ "x", /* 121 79 */ "y", /* 122 7a */ "z", /* 123 7b */ "{", /* 124 7c */ "|", /* 125 7d */ "}", /* 126 7e */ "~", /* 127 7f */ NULL, /* 128 80 */ NULL, /* 129 81 */ NULL, /* 130 82 */ NULL, /* 131 83 */ NULL, /* 132 84 */ NULL, /* 133 85 */ NULL, /* 134 86 */ NULL, /* 135 87 */ NULL, /* 136 88 */ NULL, /* 137 89 */ NULL, /* 138 8a */ NULL, /* 139 8b */ NULL, /* 140 8c */ NULL, /* 141 8d */ NULL, /* 142 8e */ NULL, /* 143 8f */ NULL, /* 144 90 */ NULL, /* 145 91 */ NULL, /* 146 92 */ NULL, /* 147 93 */ NULL, /* 148 94 */ NULL, /* 149 95 */ NULL, /* 150 96 */ NULL, /* 151 97 */ NULL, /* 152 98 */ NULL, /* 153 99 */ NULL, /* 154 9a */ NULL, /* 155 9b */ NULL, /* 156 9c */ NULL, /* 157 9d */ NULL, /* 158 9e */ NULL, /* 159 9f */ NULL, /* 160 a0 */ " ", /* 161 a1 */ "¡", /* 162 a2 */ "¢", /* 163 a3 */ "£", /* 164 a4 */ "¤", /* 165 a5 */ "¥", /* 166 a6 */ "¦", /* 167 a7 */ "§", /* 168 a8 */ "¨", /* 169 a9 */ "©", /* 170 aa */ "ª", /* 171 ab */ "«", /* 172 ac */ "¬", /* 173 ad */ "­", /* 174 ae */ "®", /* 175 af */ "¯", /* 176 b0 */ "°", /* 177 b1 */ "±", /* 178 b2 */ "²", /* 179 b3 */ "³", /* 180 b4 */ "´", /* 181 b5 */ "µ", /* 182 b6 */ "¶", /* 183 b7 */ "·", /* 184 b8 */ "¸", /* 185 b9 */ "¹", /* 186 ba */ "º", /* 187 bb */ "»", /* 188 bc */ "¼", /* 189 bd */ "½", /* 190 be */ "¾", /* 191 bf */ "¿", /* 192 c0 */ "À", /* 193 c1 */ "Á", /* 194 c2 */ "Â", /* 195 c3 */ "Ã", /* 196 c4 */ "Ä", /* 197 c5 */ "Å", /* 198 c6 */ "Æ", /* 199 c7 */ "Ç", /* 200 c8 */ "È", /* 201 c9 */ "É", /* 202 ca */ "Ê", /* 203 cb */ "Ë", /* 204 cc */ "/Igrave;", /* 205 cd */ "Í", /* 206 ce */ "Î", /* 207 cf */ "Ï", /* 208 d0 */ "Ð", /* 209 d1 */ "Ñ", /* 210 d2 */ "Ò", /* 211 d3 */ "Ó", /* 212 d4 */ "Ô", /* 213 d5 */ "Õ", /* 214 d6 */ "Ö", /* 215 d7 */ "×", /* 216 d8 */ "Ø", /* 217 d9 */ "Ù", /* 218 da */ "Ú", /* 219 db */ "Û", /* 220 dc */ "Ü", /* 221 dd */ "Ý", /* 222 de */ "Þ", /* 223 df */ "ß", /* 224 e0 */ "à", /* 225 e1 */ "á", /* 226 e2 */ "â", /* 227 e3 */ "ã", /* 228 e4 */ "ä", /* 229 e5 */ "å", /* 230 e6 */ "æ", /* 231 e7 */ "ç", /* 232 e8 */ "è", /* 233 e9 */ "é", /* 234 ea */ "ê", /* 235 eb */ "ë", /* 236 ec */ "ì", /* 237 ed */ "í", /* 238 ee */ "î", /* 239 ef */ "ï", /* 240 f0 */ "ð", /* 241 f1 */ "ñ", /* 242 f2 */ "ò", /* 243 f3 */ "ó", /* 244 f4 */ "ô", /* 245 f5 */ "õ", /* 246 f6 */ "ö", /* 247 f7 */ "÷", /* 248 f8 */ "ø", /* 249 f9 */ "ù", /* 250 fa */ "ú", /* 251 fb */ "û", /* 252 fc */ "ü", /* 253 fd */ "ý", /* 254 fe */ "þ", /* 255 ff */ "ÿ" }; $* Tool functions $* /** Write one text line, use special HTML notation for characters if necessary. @param str String to write. @param of Output file. */ static void f2lsvg_fputs_translate(char const *str, FILE *of) { char const *ptr; char const *opt; char c; unsigned char uc; unsigned u; ptr = str; while(*ptr) { c = *(ptr++); uc = (unsigned char)c; u = (unsigned)uc; while(255 < u) { u -= 256; } opt = f2lsvg_html_translation_table[u]; if(opt) { fputs(opt, of); } else { fputc(c, of); } } } /** Write SVG tag name. For full SVG write the tag name directly, when producing an SVG fragment we prepend svg:. @param job Job structure. @param ind Index of tag name in f2lsvg_c8_kw. */ static void f2lsvg_tag_name(f2l_job_t *job, size_t ind) { if(job->fragment) { fputs(f2lsvg_c8_kw[7], job->of1); } fputs(f2lsvg_c8_kw[ind], job->of1); } /** Start opening tag. @param job Job structure. @param ind Index of tag name in f2lsvg_c8_kw. */ static void f2lsvg_tag_open_start(f2l_job_t *job, size_t ind) { fputs(f2lsvg_c8_kw[6], job->of1); if(job->fragment) { fputs(f2lsvg_c8_kw[7], job->of1); } fputs(f2lsvg_c8_kw[ind], job->of1); fputs(f2lsvg_c8_kw[1], job->of1); } /** End a tag. @param job Job structure. */ static void f2lsvg_tag_end(f2l_job_t *job) { fputs(f2lsvg_c8_kw[9], job->of1); } /** Opening tag. @param job Job structure. @param ind Index of tag name in f2lsvg_c8_kw. */ static void f2lsvg_tag_open(f2l_job_t *job, size_t ind) { fputs(f2lsvg_c8_kw[6], job->of1); if(job->fragment) { fputs(f2lsvg_c8_kw[7], job->of1); } fputs(f2lsvg_c8_kw[ind], job->of1); f2lsvg_tag_end(job); } /** Write a closing tag. @param job Job structure. @param ind Index of tag name in f2lsvg_c8_kw. */ static void f2lsvg_tag_close(f2l_job_t *job, size_t ind) { fputs(f2lsvg_c8_kw[6], job->of1); fputs(f2lsvg_c8_kw[8], job->of1); if(job->fragment) { fputs(f2lsvg_c8_kw[7], job->of1); } fputs(f2lsvg_c8_kw[ind], job->of1); fputs(f2lsvg_c8_kw[9], job->of1); fputs(f2lsvg_c8_kw[0], job->of1); } /** Calculate factors for coordinates transformations. @param job Job structure. @param drw Drawing structure. @return 1 on success, 0 on error. */ static int f2lsvg_coordinates_transformation(f2l_job_t *job, dk3_fig_drawing_t *drw) { double xmin; double xmax; double ymin; double ymax; int back = 1; int mec = 0; $? "+ f2lsvg_coordinates_transformation" (job->ct2d).mx = (job->ct2d).my = dk3ma_d_div_ok(72.0, drw->res, &mec); xmin = dk3ma_d_mul_ok((job->ct2d).mx, (drw->bb).xmin, &mec); xmax = dk3ma_d_mul_ok((job->ct2d).mx, (drw->bb).xmax, &mec); ymin = dk3ma_d_mul_ok((job->ct2d).my, (drw->bb).ymin, &mec); ymax = dk3ma_d_mul_ok((job->ct2d).my, (drw->bb).ymax, &mec); /* Align to 1/8 inch grid. */ xmin = xmin / 9.0; xmin = floor(xmin); xmin = dk3ma_d_mul_ok(9.0, xmin, &mec); xmax = xmax / 9.0; xmax = ceil(xmax); xmax = dk3ma_d_mul_ok(9.0, xmax, &mec); ymin = ymin / 9.0; ymin = floor(ymin); ymin = dk3ma_d_mul_ok(9.0, ymin, &mec); ymax = ymax / 9.0; ymax = ceil(ymax); ymax = dk3ma_d_mul_ok(9.0, ymax, &mec); (job->ct2d).nx = -1.0 * xmin; (job->ct2d).ny = -1.0 * ymin; job->width = dk3ma_d_sub_ok(xmax, xmin, &mec); job->height = dk3ma_d_sub_ok(ymax, ymin, &mec); job->lwidth = dk3ma_d_to_l_ok(job->width, &mec); job->lheight = dk3ma_d_to_l_ok(job->height, &mec); $? ". mx=%lg nx=%lg my=%lg ny=%lg", (job->ct2d).mx, (job->ct2d).nx, (job->ct2d).my, (job->ct2d).ny $? ". bb=%ld %ld (%lg %lg)", job->lwidth, job->lheight, (job->width / 72.0), (job->height / 72.0) if(mec) { back = 0; /* ERROR: Math problem */ dk3app_log_1(job->app, DK3_LL_ERROR, job->msg, 38); f2l_tool_set_exit_status(job, FIG2LAT_EXIT_ERROR_MATH); $? ". exitcode" } $? "- f2lsvg_coordinates_transformation %d", back return back; } /** Collect style information for a text object, add to SVG style collection if necessary. @param job Job structure. @param drw Fig drawing. @param psvg SVG style collection. @param pobj Object to add. @return 1 on success, 0 on error. */ static int f2lsvg_text_object_style( f2l_job_t *job, dk3_fig_drawing_t *drw, f2l_svg_t *psvg, dk3_fig_obj_t *pobj ) { f2l_svg_style_t sty; /* Style. */ dk3_fig_color_t fc; /* Fill color. */ int back = 1; $? "+ f2lsvg_text_object_style %lu", pobj->li if(!(DK3_FIG_FONT_FLAG_HIDDEN & ((pobj->dt).txt.ff))) { f2lsvgst_style_initialize(&sty); /* Fill color. */ dk3fig_tool_find_int_color(&fc, drw, pobj->pc, 20); f2lsvgst_style_set_fill_color(&sty, fc.r, fc.g, fc.b); /* Text font. */ f2lsvgst_style_set_text( psvg, &sty, ((((pobj->dt).txt.ff) & DK3_FIG_FONT_FLAG_PS) ? 1 : 0), (pobj->dt).txt.fo, (pobj->dt).txt.fs ); /* Text alignment. */ f2lsvgst_style_set_text_align(&sty, pobj->st); pobj->dsd = (void *)f2lsvgst_style_add(psvg, &sty); if(!(pobj->dsd)) { back = 0; f2l_tool_set_exit_status(job, FIG2LAT_EXIT_ERROR_SYSTEM); $? ". exitcode" } } $? "- f2lsvg_text_object_style %d", back return back; } /** Collect style information for a non-text object, add to SVG style collection if necessary. @param job Job structure. @param drw Fig drawing. @param psvg SVG style collection. @param pobj Object to add. @return 1 on success, 0 on error. */ static int f2lsvg_path_object_style( f2l_job_t *job, dk3_fig_drawing_t *drw, f2l_svg_t *psvg, dk3_fig_obj_t *pobj ) { f2l_svg_style_t sty; /* Style. */ f2l_svg_fill_pattern_t pat; /* Pattern. */ dk3_fig_color_t fc; /* Fill color. */ dk3_fig_color_t sc; /* Stroke color. */ double lw; /* Line width in SVG units. */ double lsv; /* Line style value in SVG units. */ int res; /* Operation result. */ int mec = 0; /* Mathematical error code. */ int any = 0; /* Flag: Any settings applied to style. */ int op = 0; /* Draw operation. */ int back = 1 ; $? "+ f2lsvg_path_object_style %lu", pobj->li op = dk3fig_tool_get_operation(drw, pobj); f2lsvgst_style_initialize(&sty); if(op & DK3_FIG_OP_PATTERN) { /* Fill pattern. */ any = 1; dk3fig_tool_find_int_color(&fc, drw, pobj->fc, 20); dk3fig_tool_find_int_color(&sc, drw, pobj->pc, 20); pat.pn = 0UL; pat.fn = pobj->fi; pat.sr = sc.r; pat.sg = sc.g; pat.sb = sc.b; pat.fr = fc.r; pat.fg = fc.g; pat.fb = fc.b; res = f2lsvgst_style_set_pattern(psvg, &sty, &pat); if(!(res)) { back = 0; switch(psvg->ec) { case DK3_ERROR_MEMORY: { dk3app_log_i1(job->app, DK3_LL_ERROR, 9); f2l_tool_set_exit_status(job, FIG2LAT_EXIT_ERROR_SYSTEM); $? ". exitcode" } break; default: { /* ERROR: Mathematical error. */ dk3app_log_1(job->app, DK3_LL_ERROR, job->msg, 38); f2l_tool_set_exit_status(job, FIG2LAT_EXIT_ERROR_MATH); $? ". exitcode" } break; } } } else { if(op & DK3_FIG_OP_FILL) { /* Fill color. */ dk3fig_tool_find_int_color(&fc, drw, pobj->fc, pobj->fi); f2lsvgst_style_set_fill_color(&sty, fc.r, fc.g, fc.b); any = 1; } } if(op & DK3_FIG_OP_STROKE) { any = 1; /* Line width. */ lw = dk3fig_tool_get_lw(drw, pobj, &mec); lw = dk3ct_2d_r(&(job->ct2d), lw, &mec); f2lsvgst_style_set_line_width(&sty, lw); if(mec) { back = 0; /* ERROR: Mathematical error. */ dk3app_log_1(job->app, DK3_LL_ERROR, job->msg, 38); mec = 0; f2l_tool_set_exit_status(job, FIG2LAT_EXIT_ERROR_MATH); $? ". exitcode" } /* Line style. */ /* lsv = dk3ct_2d_r(&(job->ct2d), pobj->sv, &mec); */ lsv = 0.9 * pobj->sv; f2lsvgst_style_set_line_style(&sty, pobj->ls, lsv); /* Stroke color. */ dk3fig_tool_find_int_color(&sc, drw, pobj->pc, 20); f2lsvgst_style_set_line_color(&sty, sc.r, sc.g, sc.b); if(!(pobj->cl)) { /* Line cap. */ f2lsvgst_style_set_text_line_cap(&sty, pobj->cs); } } if(op) { if(DK3_FIG_OBJ_ELLIPSE != pobj->ot) { if(!((DK3_FIG_OBJ_ARC == pobj->ot) && (1 == pobj->st))) { /* Line join. */ any = 1; f2lsvgst_style_set_text_line_join(&sty, pobj->js); } } } if(any) { pobj->dsd = (void *)f2lsvgst_style_add(psvg, &sty); if(!(pobj->dsd)) { back = 0; f2l_tool_set_exit_status(job, FIG2LAT_EXIT_ERROR_SYSTEM); $? ". exitcode" } } $? "- f2lsvg_path_object_style %d", back return back; } /** Collect style information for one object. @param job Job structure. @param drw Drawing structure. @param psvg SVG style collection. @param pobj Current object. @return 1 on success, 0 on error. */ static int f2lsvg_object_style_collection( f2l_job_t *job, dk3_fig_drawing_t *drw, f2l_svg_t *psvg, dk3_fig_obj_t *pobj ) { int back = 1; switch(pobj->ot) { case DK3_FIG_OBJ_PSEUDO_HALF_CIRCLE: { if(!f2lsvg_path_object_style(job, drw, psvg, pobj)) { back = 0; } } break; case DK3_FIG_OBJ_ELLIPSE: { if(!f2lsvg_path_object_style(job, drw, psvg, pobj)) { back = 0; } } break; case DK3_FIG_OBJ_POLYLINE: { if(5 != pobj->st) { if(!f2lsvg_path_object_style(job, drw, psvg, pobj)) { back = 0; } } } break; case DK3_FIG_OBJ_SPLINE: { if(!f2lsvg_path_object_style(job, drw, psvg, pobj)) { back = 0; } } break; case DK3_FIG_OBJ_ARC: { if(!f2lsvg_path_object_style(job, drw, psvg, pobj)) { back = 0; } } break; case DK3_FIG_OBJ_TEXT: { if(!f2lsvg_text_object_style(job, drw, psvg, pobj)) { back = 0; } } break; } if(!(back)) { f2l_tool_set_exit_status(job, FIG2LAT_EXIT_ERROR_UNKNOWN); $? ". exitcode" } return back; } /** Collect style information for all objects in drawing, add styles to style collection. @param job Job structure. @param drw Fig drawing. @param psvg SVG style collection. @return 1 on success, 0 on error. */ static int f2lsvg_collect_styles(f2l_job_t *job, dk3_fig_drawing_t *drw, f2l_svg_t *psvg) { dk3_fig_obj_t *pobj; unsigned long objno = 0UL; unsigned long oldsourceline; int res; int back = 1; $? "+ f2lsvg_collect_styles" oldsourceline = dk3app_get_source_line(job->app); dk3sto_it_reset(drw->iobj); while(NULL != (pobj = (dk3_fig_obj_t *)dk3sto_it_next(drw->iobj))) { if(!dk3fig_tool_is_bgrect(pobj, objno)) { dk3app_set_source_line(job->app, pobj->li); if(!f2lsvg_object_style_collection(job, drw, psvg, pobj)) { back = 0; } if(pobj->af) { if((pobj->af)->o1) { res = f2lsvg_object_style_collection( job, drw, psvg, (dk3_fig_obj_t *)((pobj->af)->o1) ); if(!(res)) { back = 0; } } if((pobj->af)->o2) { res = f2lsvg_object_style_collection( job, drw, psvg, (dk3_fig_obj_t *)((pobj->af)->o2) ); if(!(res)) { back = 0; } } } if(pobj->ab) { if((pobj->ab)->o1) { res = f2lsvg_object_style_collection( job, drw, psvg, (dk3_fig_obj_t *)((pobj->ab)->o1) ); if(!(res)) { back = 0; } } if((pobj->ab)->o2) { res = f2lsvg_object_style_collection( job, drw, psvg, (dk3_fig_obj_t *)((pobj->ab)->o2) ); if(!(res)) { back = 0; } } } } objno++; } dk3app_set_source_line(job->app, oldsourceline); $? "- f2lsvg_collect_styles %d", back return back; } /** Check whether or not we must append a slash to the font base directory. @param bn Font base directory name. @return 1 to add a slash, 0 for no slash needed. */ static int f2lsvg_must_add_slash_to_font_base(char const *bn) { char const *ptr; int back = 1; ptr = bn; while(*ptr) { if('/' == *ptr) { back = 0; } else { back = 1; } ptr++; } return back; } /** Write font face definitions. @param job Job structure. @param drw Drawing structure. @param psvg SVG style collection. */ static void f2lsvg_write_font_faces( f2l_job_t *job, dk3_fig_drawing_t *drw, f2l_svg_t *psvg ) { dkChar dkb[DK3_MAX_PATH]; /* Font base (dkChars). */ char chb[DK3_MAX_PATH]; /* Font base (8-bit chars). */ size_t i; /* Walk through the 35 fonts. */ int fs; /* Font style. */ int res = 0; $? "+ f2lsvg_write_font_faces" if(0 < job->svgfontbase) { $? ". fontbase" switch(job->svgfontbase) { case 2: { res = dk3font_gs_base_web(job->app, dkb, DK3_SIZEOF(dkb,dkChar)); } break; default: { res = dk3font_gs_base_local(job->app, dkb, DK3_SIZEOF(dkb,dkChar)); } break; } if(res) { $? ". res (1) = 1" res = dk3str_to_c8p_app( chb, sizeof(chb), dkb, dk3app_get_encoding(job->app), job->app ); $? ". res (2) = %d", res } for(i = 0; i < 35; i++) { $? ". font %u", (unsigned)i if((psvg->psFontsUsed)[i]) { fputs(f2lsvg_c8_kw[23], job->of1); /* Font family. */ fputs(f2lsvg_c8_kw[25], job->of1); fputs(dk3font_get_svg_family((int)i), job->of1); fputs(f2lsvg_c8_kw[26], job->of1); $? ". font family finished" /* Font style */ fs = dk3font_get_svg_features((int)i); if(fs & DK3_FONT_OBLIQUE) { fputs(f2lsvg_c8_kw[27], job->of1); } else { if(fs & DK3_FONT_ITALIC) { fputs(f2lsvg_c8_kw[28], job->of1); } else { fputs(f2lsvg_c8_kw[29], job->of1); } } $? ". font style finished" /* Font weight */ fprintf(job->of1,f2lsvg_c8_kw[30],dk3font_get_svg_font_weight((int)i)); $? ". font weight finished" /* Source */ fputs(f2lsvg_c8_kw[31], job->of1); if(res) { #if 0 /* 2013-01-30 No file:// prefix */ if(1 == job->svgfontbase) { fputs(f2lsvg_c8_kw[34], job->of1); } #endif fputs(chb, job->of1); if(f2lsvg_must_add_slash_to_font_base(chb)) { fputs(f2lsvg_c8_kw[8], job->of1); } } $? ". chb" fputs(dk3font_get_gs_old_file((int)i), job->of1); $? ". old file" fputs(f2lsvg_c8_kw[32], job->of1); #if 0 /* 2013-01-30 No font id for TTF fonts */ fputs(dk3font_get_svg_fontid((int)i), job->of1); $? ". font id" #endif fputs(f2lsvg_c8_kw[33], job->of1); $? ". 1" fputs(f2lsvg_c8_kw[24], job->of1); $? ". 2" } $? ". 3" } $? ". 4" } $? "- f2lsvg_write_font_faces" } $* Driver functions $* /** Driver-specific initialization. @param job Job structure. @param drw Drawing structure. @return 1 on success, 0 on error. */ static int f2lsvg_driver_initialize(f2l_job_t *job, dk3_fig_drawing_t *drw) { f2l_svg_t *psvg; int back = 0; $? "+ f2lsvg_driver_initialize" if(f2lsvg_coordinates_transformation(job, drw)) { psvg = f2lsvgst_new_app(job->app); if(psvg) { drw->dsd = (void *)psvg; back = f2lsvg_collect_styles(job, drw, psvg); } } $? "- f2lsvg_driver_initialize %d", back return back; } /** Release resources allocated by f2lud_driver_initialize(). @param job Job structure. @param drw Drawing structure. */ static void f2lsvg_driver_end(f2l_job_t *job, dk3_fig_drawing_t *drw) { $? "+ f2lsvg_driver_end" if(drw->dsd) { f2lsvgst_delete((f2l_svg_t *)(drw->dsd)); } drw->dsd = NULL; $? "- f2lsvg_driver_end" } /** Open output file. @param job Jobs structure. @return 1 on success, 0 on error. */ static int f2lsvg_open_output_files(f2l_job_t *job) { int back = 0; job->of1 = dk3sf_fopen_app(job->on1, dkT("w"), job->app); if(job->of1) { back = 1; } else { f2l_tool_set_exit_status(job, FIG2LAT_EXIT_ERROR_SYSTEM); $? ". exitcode" } return back; } /** Close output file. @param job Job structure. */ static void f2lsvg_close_output_files(f2l_job_t *job) { if(job->of1) { dk3sf_fclose_app(job->of1, job->app); } job->of1 = NULL; } /** Check whether we must write a style tag for font faces or style definitions. @param job Job structure. @param psvg SVG style collection structure. @return 1 to write a style tag, 0 otherwise. */ static int f2lsvg_must_write_style(f2l_job_t *job, f2l_svg_t *psvg) { int back = 0; if(job->css) { if(psvg->nStyles) { back = 1; } } if(0 < job->svgfontbase) { if(f2lsvgst_any_ps_font_used(psvg)) { back = 1; } } return back; } /** Check whether we must write a defs tag for fill patterns, font faces, or style definitions. @param job Job structure. @param psvg SVG style collection structure. @return 1 to write a defs tag, 0 otherwise. */ static int f2lsvg_must_write_defs(f2l_job_t *job, f2l_svg_t *psvg) { int back; back = f2lsvg_must_write_style(job, psvg); if(0 == back) { if(psvg->nPatterns) { back = 1; } } return back; } /** Write start of output file. @param job Job strucure. @param drw Drawing structure. @return 1 on success, 0 on error. */ static int f2lsvg_start_processing(f2l_job_t *job, dk3_fig_drawing_t *drw) { f2l_svg_t *psvg; int back = 1; $? "+ f2lsvg_start_processing" psvg = (f2l_svg_t *)(drw->dsd); /* XML header and doctype. */ if(!(job->fragment)) { fputs(f2lsvg_c8_kw[2], job->of1); fputs(f2lsvg_c8_kw[3], job->of1); fputs(f2lsvg_c8_kw[4], job->of1); fputs(f2lsvg_c8_kw[5], job->of1); } /* Opening svg tag. */ f2lsvg_tag_open_start(job, 10); fprintf( job->of1, f2lsvg_c8_kw[11], (job->width / 72.0), (job->height / 72.0), job->lwidth, job->lheight ); if(!(job->fragment)) { fputs(f2lsvg_c8_kw[0], job->of1); fputs(f2lsvg_c8_kw[12], job->of1); fputs(f2lsvg_c8_kw[13], job->of1); } f2lsvg_tag_end(job); fputs(f2lsvg_c8_kw[0], job->of1); /* Title. */ f2lsvg_tag_open(job, 14); fputs(f2lsvg_c8_kw[16], job->of1); f2lsvg_tag_close(job, 14); /* Description. */ f2lsvg_tag_open(job, 15); fputs(f2lsvg_c8_kw[17], job->of1); f2lsvg_tag_close(job, 15); /* Definitions and style. */ if(f2lsvg_must_write_defs(job, psvg)) { f2lsvg_tag_open(job, 18); fputs(f2lsvg_c8_kw[0], job->of1); /* Pattern definitions. */ f2lsvgst_write_patterns(job, drw, psvg); if(f2lsvg_must_write_style(job, psvg)) { f2lsvg_tag_open_start(job, 19); fputs(f2lsvg_c8_kw[20], job->of1); f2lsvg_tag_end(job); fputs(f2lsvg_c8_kw[21], job->of1); fputs(f2lsvg_c8_kw[0], job->of1); /* Font face definitions if any. */ f2lsvg_write_font_faces(job, drw, psvg); /* Style definitions. */ if(job->css) { f2lsvgst_write_styles(job, drw, psvg); } fputs(f2lsvg_c8_kw[22], job->of1); f2lsvg_tag_close(job, 19); } f2lsvg_tag_close(job, 18); } $? "- f2lsvg_start_processing %d", back return back; } /** Write end of output file. @param job Job structure. @param drw Drawing structure. */ static void f2lsvg_end_processing(f2l_job_t *job, dk3_fig_drawing_t *drw) { f2lsvg_tag_close(job, 10); } /** Process ellipse object. @param job Job structure. @param drw Drawing structure. @param psvg SVG style collection. @param obj Current object to process. @param ec Pointer to error code variable. */ static void f2lsvg_process_ellipse( f2l_job_t *job, dk3_fig_drawing_t *drw, f2l_svg_t *psvg, dk3_fig_obj_t *obj, int *ec ) { double rotation = 0.0; /* Rotation in degree. */ double irot; /* Rotation as integer. */ double x; /* Center X. */ double y; /* Center Y. */ double rx; /* Radius X. */ double ry; /* Radius Y. */ int isEllipse = 0; /* Flag: Is ellipse. */ int isRotated = 0; /* Flag: Is rotated. */ int mec = 0; /* Mathematical error code. */ switch(obj->st) { case 1: case 2: { if(fabs(dk3ma_d_sub_ok((obj->dt).ell.rx,(obj->dt).ell.ry,&mec)) > 1.0e-6) { isEllipse = 1; if(fabs((obj->dt).ell.an) > 1.0e-6) { isRotated = 1; rotation = dk3ma_d_mul_ok(180.0, ((obj->dt).ell.an / M_PI), &mec); irot = dk3ma_d_rint(rotation); if(1.0e-6 > fabs(dk3ma_d_sub_ok(rotation, irot, &mec))) { rotation = irot; } rotation = -1.0 * rotation; } } } break; } x = dk3ct_2d_x(&(job->ct2d), (obj->dt).ell.cx, &mec); y = dk3ct_2d_y(&(job->ct2d), (obj->dt).ell.cy, &mec); rx = ry = dk3ct_2d_r(&(job->ct2d), (obj->dt).ell.rx, &mec); fputs(f2lsvg_c8_kw[6], job->of1); if(isEllipse) { ry = dk3ct_2d_r(&(job->ct2d), (obj->dt).ell.ry, &mec); f2lsvg_tag_name(job, 46); if(isRotated) { fprintf(job->of1, f2lsvg_c8_kw[48], x, y, rotation, rx, ry); } else { fprintf(job->of1, f2lsvg_c8_kw[49], x, y, rx, ry); } } else { f2lsvg_tag_name(job, 45); fprintf(job->of1, f2lsvg_c8_kw[47], x, y, rx); } f2lsvgst_write_style_for_object(job, drw, psvg, obj); fputs(f2lsvg_c8_kw[36], job->of1); if(mec) { *ec = mec; } } /** Process box object. @param job Job structure. @param drw Drawing structure. @param psvg SVG style collection. @param obj Current object to process. @param arcbox Flag: Rounded corners. @param ec Pointer to error code variable. */ static void f2lsvg_process_box( f2l_job_t *job, dk3_fig_drawing_t *drw, f2l_svg_t *psvg, dk3_fig_obj_t *obj, int arcbox, int *ec ) { dk3_bb_t outbb; dk3_fig_poly_point_t *po; double x; double y; double w; double h; double r; size_t i; int mec = 0; $? "+ f2lsvg_process_box" po = (obj->dt).pol.po; if(po) { dk3bb_reset(&outbb); for(i = 0; i < (obj->dt).pol.np; i++) { dk3bb_add_x(&outbb, dk3ct_2d_x(&(job->ct2d), po->x, &mec)); dk3bb_add_y(&outbb, dk3ct_2d_y(&(job->ct2d), po->y, &mec)); po++; } x = outbb.xmin; y = outbb.ymin; w = fabs(dk3ma_d_sub_ok(outbb.xmax, outbb.xmin, &mec)); h = fabs(dk3ma_d_sub_ok(outbb.ymax, outbb.ymin, &mec)); r = -1.0; if(arcbox) { $? ". r=%lg", (obj->dt).pol.ra r = fabs(0.9 * (obj->dt).pol.ra); $? ". r=%lg", r if(r > (0.5 * w)) { r = 0.5 * w; } if(r > (0.5 * h)) { r = 0.5 * h; } $? ". r=%lg", r } if(0 == mec) { fputs(f2lsvg_c8_kw[6], job->of1); f2lsvg_tag_name(job, 37); fputs(f2lsvg_c8_kw[0], job->of1); fprintf(job->of1, f2lsvg_c8_kw[38], x, y, w, h); if(arcbox) { fprintf(job->of1, f2lsvg_c8_kw[39], r, r); } fputs(f2lsvg_c8_kw[0], job->of1); f2lsvgst_write_style_for_object(job, drw, psvg, obj); fputs(f2lsvg_c8_kw[36], job->of1); } } dk3bb_reset(&outbb); if(mec) { *ec = mec; } $? "- f2lsvg_process_box" } /** Process polygon object. @param job Job structure. @param drw Drawing structure. @param psvg SVG style collection. @param obj Current object to process. @param primary Flag: Primary object. @param ec Pointer to error code variable. */ static void f2lsvg_process_pl_polygon( f2l_job_t *job, dk3_fig_drawing_t *drw, f2l_svg_t *psvg, dk3_fig_obj_t *obj, int primary, int *ec ) { dk3_fig_poly_point_t *po; size_t np; size_t i; int mec = 0; fputs(f2lsvg_c8_kw[6], job->of1); f2lsvg_tag_name(job, 40); fputs(f2lsvg_c8_kw[0], job->of1); fputs(f2lsvg_c8_kw[41], job->of1); po = (obj->dt).pol.po; np = (obj->dt).pol.np; if(primary) { if(1.0e-6 > fabs(dk3ma_d_sub_ok(po[0].x, po[np - 1].x, &mec))) { if(1.0e-6 > fabs(dk3ma_d_sub_ok(po[0].y, po[np - 1].y, &mec))) { np--; } } } for(i = 0; i < np; i++) { fprintf( job->of1, f2lsvg_c8_kw[43], dk3ct_2d_x(&(job->ct2d), po->x, &mec), dk3ct_2d_y(&(job->ct2d), po->y, &mec) ); if(i != (np - 1)) { fputs(f2lsvg_c8_kw[0], job->of1); } po++; } fputs(f2lsvg_c8_kw[42], job->of1); f2lsvgst_write_style_for_object(job, drw, psvg, obj); fputs(f2lsvg_c8_kw[36], job->of1); if(mec) { *ec = mec; } } /** Process polygon object. @param job Job structure. @param drw Drawing structure. @param psvg SVG style collection. @param obj Current object to process. @param ec Pointer to error code variable. */ static void f2lsvg_process_pl_polyline( f2l_job_t *job, dk3_fig_drawing_t *drw, f2l_svg_t *psvg, dk3_fig_obj_t *obj, int *ec ) { dk3_fig_poly_point_t *po; size_t np; size_t i; int mec = 0; fputs(f2lsvg_c8_kw[6], job->of1); f2lsvg_tag_name(job, 44); fputs(f2lsvg_c8_kw[0], job->of1); fputs(f2lsvg_c8_kw[41], job->of1); po = (obj->dt).pol.po; np = (obj->dt).pol.np; for(i = 0; i < np; i++) { fprintf( job->of1, f2lsvg_c8_kw[43], dk3ct_2d_x(&(job->ct2d), po->x, &mec), dk3ct_2d_y(&(job->ct2d), po->y, &mec) ); if(i != (np - 1)) { fputs(f2lsvg_c8_kw[0], job->of1); } po++; } fputs(f2lsvg_c8_kw[42], job->of1); f2lsvgst_write_style_for_object(job, drw, psvg, obj); fputs(f2lsvg_c8_kw[36], job->of1); if(mec) { *ec = mec; } } /** Process image object. @param job Job structure. @param drw Drawing structure. @param psvg SVG style collection. @param obj Current object to process. @param ec Pointer to error code variable. */ static void f2lsvg_process_image( f2l_job_t *job, dk3_fig_drawing_t *drw, f2l_svg_t *psvg, dk3_fig_obj_t *obj, int *ec ) { dk3_bb_t outbb; /* Output range. */ dk3_bif_t *bif; /* Image to process. */ dk3_fig_poly_point_t *po; /* Coordinates points. */ double tx; /* X translation. */ double ty; /* Y translation. */ double xres; /* Image resolution in x direction. */ double yres; /* Image resolution in y direction. */ double w; /* Image width (resolution used). */ double h; /* Image height (resolution used). */ double qx; /* Usable stretch factor for x. */ double qy; /* Usable stretch factor for y. */ double ow; /* Output width. */ double oh; /* Output height. */ double x1; /* Smallest x value. */ double x2; /* Largest x value. */ double y1; /* Smallest y value. */ double y2; /* Largest y value. */ dk3_bif_coord_t imw; /* Image width (number of pixels). */ dk3_bif_coord_t imh; /* Image height (number of pixels). */ size_t np; /* Number of coordinates points. */ size_t i; /* Traverse coordinates points. */ int drawdir; /* Drawing direction. */ int rotation = 0; /* Rotation in degree. */ int doScaleX = 0; /* Flag: Scale x=-1. */ int doScaleY = 0; /* Flag: Sclae y=-1. */ if((obj->dt).pol.fn) { bif = dk3bif_open_c8_filename_app( (obj->dt).pol.fn, DK3_BIF_IMAGE_TYPE_UNKNOWN, job->app ); if(bif) { /* Find image dimensions. */ imw = dk3bif_get_width(bif); imh = dk3bif_get_height(bif); xres = dk3bif_get_xres(bif); yres = dk3bif_get_yres(bif); dk3bif_close(bif); /* Find output area. */ dk3bb_reset(&outbb); po = (obj->dt).pol.po; np = (obj->dt).pol.np; for(i = 0; i < np; i++) { dk3bb_add_x(&outbb, dk3ct_2d_x(&(job->ct2d), po->x, ec)); dk3bb_add_y(&outbb, dk3ct_2d_y(&(job->ct2d), po->y, ec)); po++; } x1 = outbb.xmin; x2 = outbb.xmax; y1 = outbb.ymin; y2 = outbb.ymax; /* Find drawing direction. */ drawdir = f2lto_find_draw_direction(job, drw, obj, ec); /* Find real image width and height. */ if((xres > 0.0) && (yres > 0.0)) { switch(drawdir) { case DK3_IMAGE_ORIGIN_LEFT_BOTTOM: case DK3_IMAGE_ORIGIN_RIGHT_TOP: case DK3_IMAGE_ORIGIN_LEFT_TOP_FLIPPED: case DK3_IMAGE_ORIGIN_RIGHT_BOTTOM_FLIPPED: { w = dk3ma_d_div_ok((double)imh, yres, ec); h = dk3ma_d_div_ok((double)imw, xres, ec); } break; default: { w = dk3ma_d_div_ok((double)imw, xres, ec); h = dk3ma_d_div_ok((double)imh, yres, ec); } break; } } else { switch(drawdir) { case DK3_IMAGE_ORIGIN_LEFT_BOTTOM: case DK3_IMAGE_ORIGIN_RIGHT_TOP: case DK3_IMAGE_ORIGIN_LEFT_TOP_FLIPPED: case DK3_IMAGE_ORIGIN_RIGHT_BOTTOM_FLIPPED: { w = (double)imh; h = (double)imw; } break; default: { w = (double)imw; h = (double)imh; } break; } } /* Find the stretch factors and used regions. */ qx = dk3ma_d_div_ok(dk3ma_d_sub_ok(outbb.xmax, outbb.xmin, ec), w, ec); qy = dk3ma_d_div_ok(dk3ma_d_sub_ok(outbb.ymax, outbb.ymin, ec), h, ec); qx = fabs(qx); qy = fabs(qy); ow = oh = 0.0; if(qy >= qx) { /* Image too wide, can not use all height. */ ow = dk3ma_d_sub_ok(outbb.xmax, outbb.xmin, ec); oh = dk3ma_d_mul_ok(qx, h, ec); y1 = dk3ma_d_add_ok( outbb.ymin, ( 0.5 * dk3ma_d_sub_ok(dk3ma_d_sub_ok(outbb.ymax, outbb.ymin, ec), oh, ec) ), ec ); y2 = dk3ma_d_add_ok(y1, oh, ec); } else { /* Image too high, can not use all width. */ oh = dk3ma_d_sub_ok(outbb.ymax, outbb.ymin, ec); ow = dk3ma_d_mul_ok(qy, w, ec); x1 = dk3ma_d_add_ok( outbb.xmin, ( 0.5 * dk3ma_d_sub_ok(dk3ma_d_sub_ok(outbb.xmax, outbb.xmin, ec), ow, ec) ), ec ); x2 = dk3ma_d_add_ok(x1, ow, ec); } /* Find coordinates transformations. */ switch(drawdir) { case DK3_IMAGE_ORIGIN_RIGHT_BOTTOM_FLIPPED: { tx = x2; ty = y2; rotation = -90; doScaleY = 1; } break; case DK3_IMAGE_ORIGIN_RIGHT_TOP_FLIPPED: { tx = x2; ty = y1; doScaleX = 1; } break; case DK3_IMAGE_ORIGIN_LEFT_BOTTOM_FLIPPED: { tx = x1; ty = y2; doScaleY = 1; } break; case DK3_IMAGE_ORIGIN_LEFT_TOP_FLIPPED: { tx = x1; ty = y1; rotation = -90; doScaleX = 1; } break; case DK3_IMAGE_ORIGIN_RIGHT_BOTTOM: { tx = x2; ty = y2; rotation = 180; } break; case DK3_IMAGE_ORIGIN_RIGHT_TOP: { tx = x2; ty = y1; rotation = 90; } break; case DK3_IMAGE_ORIGIN_LEFT_BOTTOM: { tx = x1; ty = y2; rotation = -90; } break; default: { tx = x1; ty = y1; } break; } /* Write output. */ /* */ fputs(f2lsvg_c8_kw[6], job->of1); f2lsvg_tag_name(job, 35); fprintf(job->of1, f2lsvg_c8_kw[60], tx, ty); if(0 != rotation) { fprintf(job->of1, f2lsvg_c8_kw[61], rotation); } if((doScaleX) || (doScaleY)) { fputs(f2lsvg_c8_kw[62], job->of1); fputs(f2lsvg_c8_kw[(doScaleX) ? 64 : 63], job->of1); fputs(f2lsvg_c8_kw[1], job->of1); fputs(f2lsvg_c8_kw[(doScaleY) ? 64 : 63], job->of1); fputs(f2lsvg_c8_kw[65], job->of1); } fputs(f2lsvg_c8_kw[42], job->of1); fputs(f2lsvg_c8_kw[5], job->of1); /* */ fputs(f2lsvg_c8_kw[6], job->of1); f2lsvg_tag_name(job, 66); fprintf(job->of1, f2lsvg_c8_kw[67], ow, oh); fputs((obj->dt).pol.fn, job->of1); fputs(f2lsvg_c8_kw[42], job->of1); fputs(f2lsvg_c8_kw[36], job->of1); /* */ fputs(f2lsvg_c8_kw[6], job->of1); fputs(f2lsvg_c8_kw[8], job->of1); f2lsvg_tag_name(job, 35); fputs(f2lsvg_c8_kw[5], job->of1); } else { f2l_tool_set_exit_status(job, FIG2LAT_EXIT_ERROR_SYSTEM); $? ". exitcode" } } } /** Process polyline object. @param job Job structure. @param drw Drawing structure. @param psvg SVG style collection. @param obj Current object to process. @param primary Flag: Primary object. @param ec Pointer to error code variable. */ static void f2lsvg_process_polyline( f2l_job_t *job, dk3_fig_drawing_t *drw, f2l_svg_t *psvg, dk3_fig_obj_t *obj, int primary, int *ec ) { switch(obj->st) { case 5: { /* imported image */ f2lsvg_process_image(job, drw, psvg, obj, ec); } break; case 4: { /* arc box */ f2lsvg_process_box(job, drw, psvg, obj, 1, ec); } break; case 3: { /* polygon */ f2lsvg_process_pl_polygon(job, drw, psvg, obj, primary, ec); } break; case 2: { /* box */ f2lsvg_process_box(job, drw, psvg, obj, 0, ec); } break; default: { /* polyline */ f2lsvg_process_pl_polyline(job, drw, psvg, obj, ec); } break; } } /** Process open spline object. @param job Job structure. @param drw Drawing structure. @param obj Current object to process. @param sp Spline points. @param np Total number of points @param cp Current point/segment. @param isfirst Flag: Moveto needed. @param iscl Flag: Closed (1) or open (0) spline. @param primary Flag: Primary object (1=object, 0=arrowhead). @param ec Pointer to error code variable. */ static void f2lsvg_process_full_spline_segment( f2l_job_t *job, dk3_fig_drawing_t *drw, dk3_fig_obj_t *obj, dk3_fig_spline_point_t *sp, size_t np, size_t cp, int isfirst, int iscl, int primary, int *ec ) { dk3_xspline_segment_t seg; dk3_fig_spline_point_t *pa = NULL; dk3_fig_spline_point_t *pb = NULL; dk3_fig_spline_point_t *pc = NULL; dk3_fig_spline_point_t *pd = NULL; double factor; double t; double x; double y; double dxdt; double dydt; double lastx = 0.0; double lasty = 0.0; double lastdxdt = 0.0; double lastdydt = 0.0; size_t xsss; size_t iseg; size_t ic; size_t id; int res; int mec = 0; $? "+ f2lsvg_process_full_spline_segment %u / %u", (unsigned)cp, (unsigned)np if(cp < ((iscl) ? (np) : (np - 1))) { pb = &(sp[cp]); $? ". b = %u", (unsigned)cp ic = cp + 1; while(ic >= np) { ic = ic - np; } $? ". c = %u", (unsigned)ic pc = &(sp[ic]); if(cp > 0) { $? ". a = %u", (unsigned)(cp - 1) pa = &(sp[cp - 1]); } else { if(iscl) { $? ". a = %u", (unsigned)(np - 1) pa = &(sp[np - 1]); } } if(cp < (np - 2)) { $? ". d = %u", (unsigned)(cp + 2) pd = &(sp[cp + 2]); } else { if(iscl) { id = cp + 2; while(id >= np) { id = id - np; } $? ". d = %u", (unsigned)id pd = &(sp[id]); } } xsss = dk3fig_tool_xssbs(drw, primary); $? ". xsss = %u", (unsigned)xsss factor = 1.0 / (double)xsss; dk3xsp_reset(&seg); if(job->cosp) { dk3xsp_set_cb(&seg, 1); } dk3xsp_set(&seg, pa, pb, pc, pd); $? ". dk3xsp_set" if(dk3xsp_calculate(&seg, 0.0, 1)) { $? ". dk3xsp_calculate" lastx = dk3xsp_get_x(&seg); lasty = dk3xsp_get_y(&seg); lastdxdt = dk3xsp_get_dxdt(&seg); lastdydt = dk3xsp_get_dydt(&seg); lastdxdt = (factor * lastdxdt) / 3.0; lastdydt = (factor * lastdydt) / 3.0; if(isfirst) { $? ". M %lg %lg", lastx, lasty /* MOVETO lastx lasty */ fprintf( job->of1, f2lsvg_c8_kw[56], dk3ct_2d_x(&(job->ct2d), lastx, &mec), dk3ct_2d_y(&(job->ct2d), lasty, &mec) ); } for(iseg = 0; iseg < xsss; iseg++) { $? ", iseg = %u", (unsigned)iseg if(iseg < (xsss - 1)) { t = (double)(iseg + 1) / (double)xsss; } else { t = 1.0; } $? ". t = %lg", t res = dk3xsp_calculate(&seg, t, 1); $? ". res = %d", res if(!(res)) { mec = DK3_ERROR_MATH_OVERFLOW; } x = dk3xsp_get_x(&seg); y = dk3xsp_get_y(&seg); dxdt = dk3xsp_get_dxdt(&seg); dydt = dk3xsp_get_dydt(&seg); dxdt = (factor * dxdt) / 3.0; dydt = (factor * dydt) / 3.0; $? ". x=%lg y=%lg", x, y fprintf( job->of1, f2lsvg_c8_kw[57], dk3ct_2d_x(&(job->ct2d), dk3ma_d_add_ok(lastx, lastdxdt, &mec), &mec), dk3ct_2d_y(&(job->ct2d), dk3ma_d_add_ok(lasty, lastdydt, &mec), &mec), dk3ct_2d_x(&(job->ct2d), dk3ma_d_sub_ok(x, dxdt, &mec), &mec), dk3ct_2d_y(&(job->ct2d), dk3ma_d_sub_ok(y, dydt, &mec), &mec), dk3ct_2d_x(&(job->ct2d), x, &mec), dk3ct_2d_y(&(job->ct2d), y, &mec) ); lastx = x; lasty = y; lastdxdt = dxdt; lastdydt = dydt; if(iseg < (xsss - 1)) { fputs(f2lsvg_c8_kw[0], job->of1); } else { if(cp < (np - 1)) { fputs(f2lsvg_c8_kw[0], job->of1); } else { if(iscl) { fputs(f2lsvg_c8_kw[0], job->of1); } } } $? ". end of for loop" } } else { mec = DK3_ERROR_MATH_OVERFLOW; } } if(mec) { *ec = mec; } $? "- f2lsvg_process_full_spline_segment" } /** Create path for the first partial X-spline segment from closed X-spline. @param job Job structure. @param drw Fig drawing. @param obj Fig object. @param sp Spline points array. @param np Number of spline points. @param i Current segment index. @param ts Parameter t for start point. @param isfirst Flag: First segment. @param iscl Flag: Closed spline. @param primary Flag: Primary (1=primary object, 0=arrowhead). @param ec Pointer to error code variable, may be NULL. */ static void f2lsvg_first_spline_segment( f2l_job_t *job, dk3_fig_drawing_t *drw, dk3_fig_obj_t *obj, dk3_fig_spline_point_t *sp, size_t np, size_t i, double ts, int isfirst, int iscl, int primary, int *ec ) { dk3_xspline_segment_t seg; /* Segment for caluclation. */ dk3_fig_spline_point_t *pa = NULL; /* Left neighbour. */ dk3_fig_spline_point_t *pb = NULL; /* Start. */ dk3_fig_spline_point_t *pc = NULL; /* End. */ dk3_fig_spline_point_t *pd = NULL; /* Right neighbour. */ double myts; /* t for start. */ double dnumsegs; /* Number of segments. */ double factor; /* Scale factor for deriv. */ double t; /* Current t. */ double x; /* Bezier end x. */ double y; /* Bezier end y. */ double dxdt; /* Bezier dx/dt at end. */ double dydt; /* Bezier dy/dt at end. */ double lastx = 0.0; /* Bezier start x. */ double lasty = 0.0; /* Bezier start y. */ double lastdxdt = 0.0; /* dx/dt at start. */ double lastdydt = 0.0; /* dy/dt at end. */ size_t nsegs; /* Number of segments. */ size_t iseg; /* Current segment. */ int res; /* Calculation result. */ $? "+ f2lud_first_spline_segment ts=%lg", ts myts = dk3ma_d_sub_ok(ts, floor(ts), ec); $? ". myts = %lg", myts dnumsegs = (1.0 - myts) * dk3fig_tool_xssbs(drw, primary); dnumsegs = ceil(dnumsegs); $? ". dnumsegs = %lg", dnumsegs nsegs = dk3ma_d_to_sz_ok(dnumsegs, ec); $? ". nsegs = %u", (unsigned)nsegs pb = &(sp[i]); pc = &(sp[i + 1]); if(0 < i) { pa = &(sp[i - 1]); } if(i < (np - 2)) { pd = &(sp[i + 2]); } factor = (1.0 - myts) / (double)nsegs; $? ". factor = %lg", factor dk3xsp_reset(&seg); if(job->cosp) { dk3xsp_set_cb(&seg, 1); } dk3xsp_set(&seg, pa, pb, pc, pd); if(dk3xsp_calculate(&seg, myts, 1)) { /* If necessary move to the start point. */ lastx = dk3xsp_get_x(&seg); lasty = dk3xsp_get_y(&seg); lastdxdt = dk3xsp_get_dxdt(&seg); lastdydt = dk3xsp_get_dydt(&seg); lastdxdt = (factor * lastdxdt) / 3.0; lastdydt = (factor * lastdydt) / 3.0; if(isfirst) { fprintf( job->of1, f2lsvg_c8_kw[56], dk3ct_2d_x(&(job->ct2d), lastx, ec), dk3ct_2d_y(&(job->ct2d), lasty, ec) ); } if(1.0e-6 < (1.0 - myts)) { for(iseg = 0; iseg < nsegs; iseg++) { if(iseg < (nsegs - 1)) { t = myts + (((1.0 - myts) * ((double)(iseg + 1))) / ((double)nsegs)); } else { t = 1.0; } res = dk3xsp_calculate(&seg, t, 1); if(!(res)) { if(ec) { *ec = DK3_ERROR_MATH_OVERFLOW; } } x = dk3xsp_get_x(&seg); y = dk3xsp_get_y(&seg); dxdt = dk3xsp_get_dxdt(&seg); dydt = dk3xsp_get_dydt(&seg); dxdt = (factor * dxdt) / 3.0; dydt = (factor * dydt) / 3.0; fprintf( job->of1, f2lsvg_c8_kw[57], dk3ct_2d_x(&(job->ct2d), dk3ma_d_add_ok(lastx, lastdxdt, ec), ec), dk3ct_2d_y(&(job->ct2d), dk3ma_d_add_ok(lasty, lastdydt, ec), ec), dk3ct_2d_x(&(job->ct2d), dk3ma_d_sub_ok(x, dxdt, ec), ec), dk3ct_2d_y(&(job->ct2d), dk3ma_d_sub_ok(y, dydt, ec), ec), dk3ct_2d_x(&(job->ct2d), x, ec), dk3ct_2d_y(&(job->ct2d), y, ec) ); lastx = x; lasty = y; lastdxdt = dxdt; lastdydt = dydt; fputs(f2lsvg_c8_kw[0], job->of1); } } else { res = dk3xsp_calculate(&seg, 1.0, 0); if(!(res)) { if(ec) { *ec = DK3_ERROR_MATH_OVERFLOW; } /* ERROR: Math */ dk3app_log_1(job->app, DK3_LL_ERROR, job->msg, 36); f2l_tool_set_exit_status(job, FIG2LAT_EXIT_ERROR_MATH); $? ". exitcode" } x = dk3xsp_get_x(&seg); y = dk3xsp_get_y(&seg); fprintf( job->of1, f2lsvg_c8_kw[58], dk3ct_2d_x(&(job->ct2d), x, ec), dk3ct_2d_y(&(job->ct2d), y, ec) ); } } else { if(ec) { *ec = DK3_ERROR_MATH_OVERFLOW; } f2l_tool_set_exit_status(job, FIG2LAT_EXIT_ERROR_MATH); $? ". exitcode" } $? "- f2lud_first_spline_segment" } /** Create path for the last partial X-spline segment from closed X-spline. @param job Job structure. @param drw Fig drawing. @param obj Fig object. @param sp Spline points array. @param np Number of spline points. @param i Current segment index. @param te Parameter t for end point. @param isfirst Flag: First segment. @param iscl Flag: Closed spline. @param primary Flag: Primary (1=primary object, 0=arrowhead). @param ec Pointer to error code variable, may be NULL. */ static void f2lsvg_final_spline_segment( f2l_job_t *job, dk3_fig_drawing_t *drw, dk3_fig_obj_t *obj, dk3_fig_spline_point_t *sp, size_t np, size_t i, double te, int isfirst, int iscl, int primary, int *ec ) { dk3_xspline_segment_t seg; /* Segment for caluclation. */ dk3_fig_spline_point_t *pa = NULL; /* Left neighbour. */ dk3_fig_spline_point_t *pb = NULL; /* Start. */ dk3_fig_spline_point_t *pc = NULL; /* End. */ dk3_fig_spline_point_t *pd = NULL; /* Right neighbour. */ double myte; /* t for end. */ double dnumsegs; /* Number of segments. */ double factor; /* Scale factor for deriv. */ double t; /* Current t. */ double x; /* Bezier end x. */ double y; /* Bezier end y. */ double dxdt; /* Bezier dx/dt at end. */ double dydt; /* Bezier dy/dt at end. */ double lastx = 0.0; /* Bezier start x. */ double lasty = 0.0; /* Bezier start y. */ double lastdxdt = 0.0; /* dx/dt at start. */ double lastdydt = 0.0; /* dy/dt at end. */ size_t nsegs; /* Number of segments. */ size_t iseg; /* Current segment. */ int res; /* Calculation result. */ $? "+ f2lud_final_spline_segment %lg", te myte = dk3ma_d_sub_ok(te, floor(te), ec); $? ". myte = %lg", myte dnumsegs = myte * dk3fig_tool_xssbs(drw, primary); dnumsegs = ceil(dnumsegs); $? ". dnumsegs = %lg", dnumsegs nsegs = dk3ma_d_to_sz_ok(dnumsegs, ec); $? ". nsegs = %u", (unsigned)nsegs pb = &(sp[i]); pc = &(sp[i + 1]); if(0 < i) { pa = &(sp[i - 1]); } if(i < (np - 2)) { pd = &(sp[i + 2]); } factor = myte / (double)nsegs; $? ". factor = %lg", factor dk3xsp_reset(&seg); if(job->cosp) { dk3xsp_set_cb(&seg, 1); } dk3xsp_set(&seg, pa, pb, pc, pd); if(dk3xsp_calculate(&seg, 0.0, 1)) { lastx = dk3xsp_get_x(&seg); lasty = dk3xsp_get_y(&seg); lastdxdt = dk3xsp_get_dxdt(&seg); lastdydt = dk3xsp_get_dydt(&seg); lastdxdt = (factor * lastdxdt) / 3.0; lastdydt = (factor * lastdydt) / 3.0; /* Move to start point. */ if(isfirst) { fprintf( job->of1, f2lsvg_c8_kw[56], dk3ct_2d_x(&(job->ct2d), lastx, ec), dk3ct_2d_y(&(job->ct2d), lasty, ec) ); } /* Further curve only if te > 1.0e-6. For smaller te draw straight line. */ if(1.0e-6 < myte) { $? ". segments size ok" for(iseg = 0; iseg < nsegs; iseg++) { if(iseg < (nsegs - 1)) { $? ". not last sub-segment" t = (double)(iseg + 1) / (double)nsegs; t = t * myte; } else { $? ". last sub-segment" t = myte; } $? ". t = %lg", t res = dk3xsp_calculate(&seg, t, 1); if(!(res)) { if(ec) { *ec = DK3_ERROR_MATH_OVERFLOW; } } x = dk3xsp_get_x(&seg); y = dk3xsp_get_y(&seg); dxdt = dk3xsp_get_dxdt(&seg); dydt = dk3xsp_get_dydt(&seg); dxdt = (factor * dxdt) / 3.0; dydt = (factor * dydt) / 3.0; fprintf( job->of1, f2lsvg_c8_kw[57], dk3ct_2d_x(&(job->ct2d), dk3ma_d_add_ok(lastx, lastdxdt, ec), ec), dk3ct_2d_y(&(job->ct2d), dk3ma_d_add_ok(lasty, lastdydt, ec), ec), dk3ct_2d_x(&(job->ct2d), dk3ma_d_sub_ok(x, dxdt, ec), ec), dk3ct_2d_y(&(job->ct2d), dk3ma_d_sub_ok(y, dydt, ec), ec), dk3ct_2d_x(&(job->ct2d), x, ec), dk3ct_2d_y(&(job->ct2d), y, ec) ); lastx = x; lasty = y; lastdxdt = dxdt; lastdydt = dydt; if(iseg < (nsegs - 1)) { fputs(f2lsvg_c8_kw[0], job->of1); } } } else { $? ". very small segment" res = dk3xsp_calculate(&seg, myte, 0); if(!(res)) { if(ec) { *ec = DK3_ERROR_MATH_OVERFLOW; } /* ERROR: Math */ dk3app_log_1(job->app, DK3_LL_ERROR, job->msg, 36); f2l_tool_set_exit_status(job, FIG2LAT_EXIT_ERROR_MATH); $? ". exitcode" } x = dk3xsp_get_x(&seg); y = dk3xsp_get_y(&seg); fprintf( job->of1, f2lsvg_c8_kw[58], dk3ct_2d_x(&(job->ct2d), x, ec), dk3ct_2d_y(&(job->ct2d), y, ec) ); } } else { if(ec) { *ec = DK3_ERROR_MATH_OVERFLOW; } f2l_tool_set_exit_status(job, FIG2LAT_EXIT_ERROR_MATH); $? ". exitcode" } $? "- f2lud_final_spline_segment" } /** Create path for the single partial X-spline segment cutted on both ends from closed X-spline. @param job Job structure. @param drw Fig drawing. @param obj Fig object. @param sp Spline points array. @param np Number of spline points. @param i Current segment index. @param ts Parameter t for start point. @param te Parameter t for end point. @param isfirst Flag: First segment. @param iscl Flag: Closed spline. @param primary Flag: Primary (1=primary object, 0=arrowhead). @param ec Pointer to error code variable, may be NULL. */ static void f2lsvg_single_spline_segment( f2l_job_t *job, dk3_fig_drawing_t *drw, dk3_fig_obj_t *obj, dk3_fig_spline_point_t *sp, size_t np, size_t i, double ts, double te, int isfirst, int iscl, int primary, int *ec ) { dk3_xspline_segment_t seg; /* Segment for caluclation. */ dk3_fig_spline_point_t *pa = NULL; /* Left neighbour. */ dk3_fig_spline_point_t *pb = NULL; /* Start. */ dk3_fig_spline_point_t *pc = NULL; /* End. */ dk3_fig_spline_point_t *pd = NULL; /* Right neighbour. */ double myte; /* t for end. */ double myts; /* t for start. */ double dnumsegs; /* Number of segments. */ double factor; /* Scale factor for deriv. */ double t; /* Current t. */ double x; /* Bezier end x. */ double y; /* Bezier end y. */ double dxdt; /* Bezier dx/dt at end. */ double dydt; /* Bezier dy/dt at end. */ double lastx = 0.0; /* Bezier start x. */ double lasty = 0.0; /* Bezier start y. */ double lastdxdt = 0.0; /* dx/dt at start. */ double lastdydt = 0.0; /* dy/dt at end. */ size_t nsegs; /* Number of segments. */ size_t iseg; /* Current segment. */ int res; /* Calculation result. */ $? "+ f2lud_single_spline_segment" myte = dk3ma_d_sub_ok(te, floor(te), ec); myts = dk3ma_d_sub_ok(ts, floor(ts), ec); dnumsegs = (myte - myts) * dk3fig_tool_xssbs(drw, primary); dnumsegs = ceil(dnumsegs); nsegs = dk3ma_d_to_sz_ok(dnumsegs, ec); pb = &(sp[i]); pc = &(sp[i + 1]); if(0 < i) { pa = &(sp[i - 1]); } if(i < (np - 2)) { pd = &(sp[i + 2]); } factor = (myte - myts) / ((double)nsegs); dk3xsp_reset(&seg); if(job->cosp) { dk3xsp_set_cb(&seg, 1); } dk3xsp_set(&seg, pa, pb, pc, pd); if(dk3xsp_calculate(&seg, myts, 1)) { lastx = dk3xsp_get_x(&seg); lasty = dk3xsp_get_y(&seg); lastdxdt = dk3xsp_get_dxdt(&seg); lastdydt = dk3xsp_get_dydt(&seg); lastdxdt = (factor * lastdxdt) / 3.0; lastdydt = (factor * lastdydt) / 3.0; if(isfirst) { fprintf( job->of1, f2lsvg_c8_kw[56], dk3ct_2d_x(&(job->ct2d), lastx, ec), dk3ct_2d_y(&(job->ct2d), lasty, ec) ); } if(1.0e-6 < (myte - myts)) { for(iseg = 0; iseg < nsegs; iseg++) { if(iseg < (nsegs - 1)) { t = myts + (((myte - myts) * ((double)(iseg + 1))) / ((double)nsegs)); } else { t = myte; } res = dk3xsp_calculate(&seg, t, 1); if(!(res)) { if(ec) { *ec = DK3_ERROR_MATH_OVERFLOW; } } x = dk3xsp_get_x(&seg); y = dk3xsp_get_y(&seg); dxdt = dk3xsp_get_dxdt(&seg); dydt = dk3xsp_get_dydt(&seg); dxdt = (factor * dxdt) / 3.0; dydt = (factor * dydt) / 3.0; fprintf( job->of1, f2lsvg_c8_kw[57], dk3ct_2d_x(&(job->ct2d), dk3ma_d_add_ok(lastx, lastdxdt, ec), ec), dk3ct_2d_y(&(job->ct2d), dk3ma_d_add_ok(lasty, lastdydt, ec), ec), dk3ct_2d_x(&(job->ct2d), dk3ma_d_sub_ok(x, dxdt, ec), ec), dk3ct_2d_y(&(job->ct2d), dk3ma_d_sub_ok(y, dydt, ec), ec), dk3ct_2d_x(&(job->ct2d), x, ec), dk3ct_2d_y(&(job->ct2d), y, ec) ); lastx = x; lasty = y; lastdxdt = dxdt; lastdydt = dydt; if(iseg < (nsegs - 1)) { fputs(f2lsvg_c8_kw[0], job->of1); } } } else { res = dk3xsp_calculate(&seg, myte, 0); if(!(res)) { if(ec) { *ec = DK3_ERROR_MATH_OVERFLOW; } /* ERROR: Calculation failed! */ dk3app_log_1(job->app, DK3_LL_ERROR, job->msg, 36); f2l_tool_set_exit_status(job, FIG2LAT_EXIT_ERROR_MATH); $? ". exitcode" } x = dk3xsp_get_x(&seg); y = dk3xsp_get_y(&seg); fprintf( job->of1, f2lsvg_c8_kw[58], dk3ct_2d_x(&(job->ct2d), x, ec), dk3ct_2d_y(&(job->ct2d), y, ec) ); } } else { if(ec) { *ec = DK3_ERROR_MATH_OVERFLOW; } /* ERROR: Calculation failed! */ dk3app_log_1(job->app, DK3_LL_ERROR, job->msg, 36); f2l_tool_set_exit_status(job, FIG2LAT_EXIT_ERROR_MATH); $? ". exitcode" } $? "- f2lud_single_spline_segment" } /** Process open spline object. @param job Job structure. @param drw Drawing structure. @param psvg SVG style collection. @param obj Current object to process. @param primary Flag: Primary object (1=object, 0=arrowhead). @param ec Pointer to error code variable. */ static void f2lsvg_process_open_spline( f2l_job_t *job, dk3_fig_drawing_t *drw, f2l_svg_t *psvg, dk3_fig_obj_t *obj, int primary, int *ec ) { dk3_fig_spline_point_t *sp; size_t np; size_t i; size_t min; size_t max; sp = (obj->dt).spl.po; np = (obj->dt).spl.np; fputs(f2lsvg_c8_kw[6], job->of1); f2lsvg_tag_name(job, 54); fputs(f2lsvg_c8_kw[55], job->of1); if(job->coah) { for(i = 0; i < (np - 1); i++) { f2lsvg_process_full_spline_segment( job, drw, obj, sp, np, i, ((0 == i) ? 1 : 0), 0, primary, ec ); } } else { if(obj->ab) { $? ". have backward arrow" /* 2013-11-23 ROUNDING DOWNWARDS INTENDED. We want to find the start segment. */ min = dk3ma_d_to_sz_ok(floor((obj->dt).spl.ts), ec); if(obj->af) { $? ". have forward arrow" if((obj->dt).spl.te >= (obj->dt).spl.ts) { /* 2013-11-23 ROUNDING DOWNWARDS INTENDED. We want to find the last full segment to draw. */ max = dk3ma_d_to_sz_ok(floor((obj->dt).spl.te), ec); if(max > min) { f2lsvg_first_spline_segment( job, drw, obj, sp, np, min, (obj->dt).spl.ts, 1, 0, primary, ec ); for(i = (min + 1); i < max; i++) { f2lsvg_process_full_spline_segment( job, drw, obj, sp, np, i, 0, 0, primary, ec ); } f2lsvg_final_spline_segment( job, drw, obj, sp, np, max, (obj->dt).spl.te, 0, 0, primary, ec ); } else { f2lsvg_single_spline_segment( job, drw, obj, sp, np, min, (obj->dt).spl.ts, (obj->dt).spl.te, 1, 0, primary, ec ); } } else { /* ERROR: Arrowheads in summary too long for spline */ dk3app_log_1(job->app, DK3_LL_ERROR, job->msg, 37); f2l_tool_set_exit_status(job, FIG2LAT_EXIT_ERROR_SYNTAX); $? ". exitcode" } } else { $? ". no forward arrow" f2lsvg_first_spline_segment( job, drw, obj, sp, np, min, (obj->dt).spl.ts, 1, 0, primary, ec ); for(i = (min + 1); i < (np - 1); i++) { f2lsvg_process_full_spline_segment( job, drw, obj, sp, np, i, 0, 0, primary, ec ); } } } else { $? ". no backward arrow" if(obj->af) { $? ". have forward arrow" /* 2013-11-23 ROUNDING DOWNWARDS INTENDED. We want to find the last full segment to draw. */ max = dk3ma_d_to_sz_ok(floor((obj->dt).spl.te), ec); if(max < (np - 1)) { if(max > 0) { for(i = 0; i < max; i++) { f2lsvg_process_full_spline_segment( job, drw, obj, sp, np, i, ((0 == i) ? 1 : 0), 0, primary, ec ); } f2lsvg_final_spline_segment( job, drw, obj, sp, np, max, (obj->dt).spl.te, 0, 0, primary, ec ); } else { f2lsvg_final_spline_segment( job, drw, obj, sp, np, max, (obj->dt).spl.te, 1, 0, primary, ec ); } } else { /* ERROR: Illegal max value! */ dk3app_log_1(job->app, DK3_LL_ERROR, job->msg, 39); f2l_tool_set_exit_status(job, FIG2LAT_EXIT_ERROR_UNKNOWN); $? ". exitcode" } } else { $? ". no forward arrow" for(i = 0; i < (np - 1); i++) { f2lsvg_process_full_spline_segment( job, drw, obj, sp, np, i, ((0 == i) ? 1 : 0), 0, primary, ec ); } } } } fputs(f2lsvg_c8_kw[42], job->of1); f2lsvgst_write_style_for_object(job, drw, psvg, obj); fputs(f2lsvg_c8_kw[36], job->of1); } /** Process fast open spline object. @param job Job structure. @param drw Drawing structure. @param psvg SVG style collection. @param obj Current object to process. @param ec Pointer to error code variable. */ static void f2lsvg_process_fast_open_spline( f2l_job_t *job, dk3_fig_drawing_t *drw, f2l_svg_t *psvg, dk3_fig_obj_t *obj, int *ec ) { dk3_fig_spline_point_t *po; double dxdtb; double dydtb; double dxdtc; double dydtc; size_t np; size_t ib; size_t ic; $? "+ f2lsvg_process_fast_open_spline %lu", obj->li po = (obj->dt).spl.po; np = (obj->dt).spl.np; fputs(f2lsvg_c8_kw[6], job->of1); f2lsvg_tag_name(job, 54); fputs(f2lsvg_c8_kw[55], job->of1); if (1 < np) { for (ib = 0; ib < (np - 1); ib++) { ic = ib + 1; if (0 == ib) { /* MOVETO */ fprintf( job->of1, f2lsvg_c8_kw[56], dk3ct_2d_x(&(job->ct2d), po[ib].x, ec), dk3ct_2d_y(&(job->ct2d), po[ib].y, ec) ); } if ((fabs(po[ib].s) < 1.0e-6) && (fabs(po[ic].s) < 1.0e-6)) { /* LINETO */ fprintf( job->of1, f2lsvg_c8_kw[58], dk3ct_2d_x(&(job->ct2d), po[ib].x, ec), dk3ct_2d_y(&(job->ct2d), po[ib].y, ec) ); } else { dxdtb = dxdtc = dk3ma_d_sub_ok(po[ic].x, po[ib].x, ec); dydtb = dydtc = dk3ma_d_sub_ok(po[ic].y, po[ib].y, ec); if ((0 < ib) && (fabs(1.0 + po[ib].s) < 1.0e-6)) { dxdtb = f2lpara_derived_center(po[ib-1].x, po[ib].x, po[ic].x, ec); dydtb = f2lpara_derived_center(po[ib-1].y, po[ib].y, po[ic].y, ec); } else { if ((ic < (np - 1)) && (fabs(1.0 + po[ic].s) < 1.0e-6)) { dxdtb = f2lpara_derived_left(po[ib].x, po[ic].x, po[ic+1].x, ec); dydtb = f2lpara_derived_left(po[ib].y, po[ic].y, po[ic+1].y, ec); } } if ((ic < (np - 1)) && (fabs(1.0 + po[ic].s) < 1.0e-6)) { dxdtc = f2lpara_derived_center(po[ib].x, po[ic].x, po[ic+1].x, ec); dydtc = f2lpara_derived_center(po[ib].y, po[ic].y, po[ic+1].y, ec); } else { if ((0 < ib) && (fabs(1.0 + po[ib].s) < 1.0e-6)) { dxdtc = f2lpara_derived_right(po[ib-1].x, po[ib].x, po[ic].x, ec); dydtc = f2lpara_derived_right(po[ib-1].y, po[ib].y, po[ic].y, ec); } } /* CURVETO */ fprintf( job->of1, f2lsvg_c8_kw[57], dk3ct_2d_x( &(job->ct2d), dk3ma_d_add_ok(po[ib].x, (dxdtb / 3.0), ec), ec ), dk3ct_2d_y( &(job->ct2d), dk3ma_d_add_ok(po[ib].y, (dydtb / 3.0), ec), ec ), dk3ct_2d_x( &(job->ct2d), dk3ma_d_sub_ok(po[ic].x, (dxdtc / 3.0), ec), ec ), dk3ct_2d_y( &(job->ct2d), dk3ma_d_sub_ok(po[ic].y, (dydtc / 3.0), ec), ec ), dk3ct_2d_x( &(job->ct2d), po[ic].x, ec), dk3ct_2d_y( &(job->ct2d), po[ic].y, ec) ); } } } else { /* Too few points in X-spline */ } fputs(f2lsvg_c8_kw[42], job->of1); f2lsvgst_write_style_for_object(job, drw, psvg, obj); fputs(f2lsvg_c8_kw[36], job->of1); $? "- f2lsvg_process_fast_open_spline" } /** Process closed spline object. @param job Job structure. @param drw Drawing structure. @param psvg SVG style collection. @param obj Current object to process. @param primary Flag: Primary object (1=object, 0=arrowhead). @param ec Pointer to error code variable. */ static void f2lsvg_process_closed_spline( f2l_job_t *job, dk3_fig_drawing_t *drw, f2l_svg_t *psvg, dk3_fig_obj_t *obj, int primary, int *ec ) { dk3_fig_spline_point_t *sp; size_t np; size_t i; sp = (obj->dt).spl.po; np = (obj->dt).spl.np; fputs(f2lsvg_c8_kw[6], job->of1); f2lsvg_tag_name(job, 54); fputs(f2lsvg_c8_kw[55], job->of1); for(i = 0; i < np; i++) { f2lsvg_process_full_spline_segment( job, drw, obj, sp, np, i, ((0 == i) ? 1 : 0), 1, primary, ec ); } fputs(f2lsvg_c8_kw[59], job->of1); fputs(f2lsvg_c8_kw[42], job->of1); f2lsvgst_write_style_for_object(job, drw, psvg, obj); fputs(f2lsvg_c8_kw[36], job->of1); } /** Process fast closed spline object. @param job Job structure. @param drw Drawing structure. @param psvg SVG style collection. @param obj Current object to process. @param ec Pointer to error code variable. */ static void f2lsvg_process_fast_closed_spline( f2l_job_t *job, dk3_fig_drawing_t *drw, f2l_svg_t *psvg, dk3_fig_obj_t *obj, int *ec ) { dk3_fig_spline_point_t *po; double dxdtb; double dydtb; double dxdtc; double dydtc; size_t np; size_t ia; size_t ib; size_t ic; size_t id; $? "+ f2lsvg_process_fast_closed_spline %lu", obj->li po = (obj->dt).spl.po; np = (obj->dt).spl.np; fputs(f2lsvg_c8_kw[6], job->of1); f2lsvg_tag_name(job, 54); fputs(f2lsvg_c8_kw[55], job->of1); if (2 < np) { for (ib = 0; ib < np; ib++) { ic = ib + 1; id = ib + 2; if (ic >= np) { ic = ic - np; } if (id >= np) { id = id - np; } if (0 < ib) { ia = ib - 1; } else { ia = np - 1; } if (0 == ib) { /* MOVETO */ fprintf( job->of1, f2lsvg_c8_kw[56], dk3ct_2d_x(&(job->ct2d), po[ib].x, ec), dk3ct_2d_y(&(job->ct2d), po[ib].y, ec) ); } if ((fabs(po[ib].s) < 1.0e-6) && (fabs(po[ic].s) < 1.0e-6)) { /* LINETO */ fprintf( job->of1, f2lsvg_c8_kw[58], dk3ct_2d_x(&(job->ct2d), po[ib].x, ec), dk3ct_2d_y(&(job->ct2d), po[ib].y, ec) ); } else { dxdtb = dxdtc = dk3ma_d_sub_ok(po[ic].x, po[ib].x, ec); dydtb = dydtc = dk3ma_d_sub_ok(po[ic].y, po[ib].y, ec); if (fabs(1.0 + po[ib].s) < 1.0e-6) { dxdtb = f2lpara_derived_center(po[ia].x, po[ib].x, po[ic].x, ec); dydtb = f2lpara_derived_center(po[ia].y, po[ib].y, po[ic].y, ec); } else { if (fabs(1.0 + po[ic].s) < 1.0e-6) { dxdtb = f2lpara_derived_left(po[ib].x, po[ic].x, po[id].x, ec); dydtb = f2lpara_derived_left(po[ib].y, po[ic].y, po[id].y, ec); } } if (fabs(1.0 + po[ic].s) < 1.0e-6) { dxdtc = f2lpara_derived_center(po[ib].x, po[ic].x, po[id].x, ec); dydtc = f2lpara_derived_center(po[ib].y, po[ic].y, po[id].y, ec); } else { if (fabs(1.0 + po[ib].s) < 1.0e-6) { dxdtc = f2lpara_derived_right(po[ia].x, po[ib].x, po[ic].x, ec); dydtc = f2lpara_derived_right(po[ia].y, po[ib].y, po[ic].y, ec); } } /* CURVETO */ fprintf( job->of1, f2lsvg_c8_kw[57], dk3ct_2d_x( &(job->ct2d), dk3ma_d_add_ok(po[ib].x, (dxdtb / 3.0), ec), ec ), dk3ct_2d_y( &(job->ct2d), dk3ma_d_add_ok(po[ib].y, (dydtb / 3.0), ec), ec ), dk3ct_2d_x( &(job->ct2d), dk3ma_d_sub_ok(po[ic].x, (dxdtc / 3.0), ec), ec ), dk3ct_2d_y( &(job->ct2d), dk3ma_d_sub_ok(po[ic].y, (dydtc / 3.0), ec), ec ), dk3ct_2d_x( &(job->ct2d), po[ic].x, ec), dk3ct_2d_y( &(job->ct2d), po[ic].y, ec) ); } } } else { /* ERROR: Too few points */ } fputs(f2lsvg_c8_kw[59], job->of1); fputs(f2lsvg_c8_kw[42], job->of1); f2lsvgst_write_style_for_object(job, drw, psvg, obj); fputs(f2lsvg_c8_kw[36], job->of1); $? "- f2lsvg_process_fast_closed_spline" } /** Process spline object. @param job Job structure. @param drw Drawing structure. @param psvg SVG style collection. @param obj Current object to process. @param primary Flag: Primary object (1=object, 0=arrowhead). @param ec Pointer to error code variable. */ static void f2lsvg_process_spline( f2l_job_t *job, dk3_fig_drawing_t *drw, f2l_svg_t *psvg, dk3_fig_obj_t *obj, int primary, int *ec ) { switch(obj->st) { case 1: case 3: case 5: { /* closed spline */ f2lsvg_process_closed_spline(job, drw, psvg, obj, primary, ec); } break; default: { /* open spline */ f2lsvg_process_open_spline(job, drw, psvg, obj, primary, ec); } break; } } /** Process text object. @param job Job structure. @param drw Drawing structure. @param psvg SVG style collection. @param obj Current object to process. @param ec Pointer to error code variable. */ static void f2lsvg_process_text( f2l_job_t *job, dk3_fig_drawing_t *drw, f2l_svg_t *psvg, dk3_fig_obj_t *obj, int *ec ) { double rotation = 0.0; /* Rotation in degree. */ double irot = 0.0; /* Rotation as integer. */ double x; /* Text x position. */ double y; /* Text y position. */ int isRotated = 0; /* Flag: Text is rotated. */ int mec = 0; /* Mathematical error code. */ if(!(DK3_FIG_FONT_FLAG_HIDDEN & ((obj->dt).txt.ff))) { rotation = (obj->dt).txt.an; if(1.0e-6 < fabs(rotation)) { isRotated = 1; rotation = dk3ma_d_mul_ok(180.0, (rotation / M_PI), &mec); irot = dk3ma_d_rint(rotation); if(fabs(dk3ma_d_sub_ok(rotation, irot, &mec)) < 1.0e-3) { rotation = irot; } rotation = -1.0 * rotation; } fputs(f2lsvg_c8_kw[6], job->of1); f2lsvg_tag_name(job, 50); x = dk3ct_2d_x(&(job->ct2d), (obj->dt).txt.x, &mec); y = dk3ct_2d_y(&(job->ct2d), (obj->dt).txt.y, &mec); if(isRotated) { fprintf(job->of1, f2lsvg_c8_kw[53], x, y, rotation); } else { fprintf(job->of1, f2lsvg_c8_kw[52], x, y); } f2lsvgst_write_style_for_object(job, drw, psvg, obj); fputs(f2lsvg_c8_kw[51], job->of1); if((obj->dt).txt.st) { #if VERSION_BEFORE_2013_11_10 fputs((obj->dt).txt.st, job->of1); #else f2lsvg_fputs_translate((obj->dt).txt.st, job->of1); #endif } fputs(f2lsvg_c8_kw[6], job->of1); fputs(f2lsvg_c8_kw[8], job->of1); f2lsvg_tag_name(job, 50); fputs(f2lsvg_c8_kw[5], job->of1); if(mec) { *ec = mec; } if(DK3_FIG_FONT_FLAG_SPECIAL & ((obj->dt).txt.ff)) { /* WARNING: Special text was found! */ dk3app_log_1(job->app, DK3_LL_ERROR, job->msg, 44); } } } /** Process arc object. @param job Job structure. @param drw Drawing structure. @param psvg SVG style collection. @param obj Current object to process. @param ec Pointer to error code variable. */ static void f2lsvg_process_arc( f2l_job_t *job, dk3_fig_drawing_t *drw, f2l_svg_t *psvg, dk3_fig_obj_t *obj, int *ec ) { double sx; /* Start x. */ double sy; /* Start y. */ double cx; /* Center x. */ double cy; /* Center y. */ double r; /* Radius. */ double as; /* Arc start angle in radians. */ double ae; /* Arc end angle in radians. */ double lastx; /* Segment start x. */ double lasty; /* Segment start y. */ double lastkdxdt; /* X difference to first control. */ double lastkdydt; /* Y difference to first control. */ double x; /* Segment end x. */ double y; /* Segment end y. */ double kdxdt; /* X difference to last control. */ double kdydt; /* Y difference to last control. */ double dnumsegs; /* Number of segments. */ double alpha; /* Arc angle in radians. */ double alphaseg; /* Segment angle in radians. */ double kappa; /* Factor for derivative. */ double alphaend; /* Segment end angle in radians. */ size_t nsegs; /* Number of segments. */ size_t i; /* Index of current segment. */ fputs(f2lsvg_c8_kw[6], job->of1); f2lsvg_tag_name(job, 54); fputs(f2lsvg_c8_kw[55], job->of1); cx = (obj->dt).arc.xc; cy = (obj->dt).arc.yc; r = (obj->dt).arc.ra; if((obj->dt).arc.as < (obj->dt).arc.ae) { as = (obj->dt).arc.as; ae = (obj->dt).arc.ae; } else { as = (obj->dt).arc.ae; ae = (obj->dt).arc.as; } alpha = dk3ma_d_sub_ok(ae, as, ec); dnumsegs = ceil(dk3ma_d_mul_ok(4.0, (alpha / M_PI), ec)); nsegs = dk3ma_d_to_sz_ok(dnumsegs, ec); alphaseg = alpha / ((double)nsegs); kappa = dk3fig_tool_arc_kappa(alphaseg, ec); sx = lastx = dk3ma_d_add_ok(cx, (r * cos(as)), ec); sy = lasty = dk3ma_d_add_ok(cy, (r * sin(as)), ec); fprintf( job->of1, f2lsvg_c8_kw[56], dk3ct_2d_x(&(job->ct2d), lastx, ec), dk3ct_2d_y(&(job->ct2d), lasty, ec) ); lastkdxdt = dk3ma_d_mul_ok( kappa, (-1.0 * dk3ma_d_mul_ok(r, alphaseg, ec) * sin(as)), ec ); lastkdydt = dk3ma_d_mul_ok( kappa, (dk3ma_d_mul_ok(r, alphaseg, ec) * cos(as)), ec ); for(i = 0; i < nsegs; i++) { if(i < (nsegs - 1)) { alphaend = dk3ma_d_add_ok( as, dk3ma_d_mul_ok(dk3ma_d_add_ok(1.0, (double)i, ec), alphaseg, ec), ec ); } else { alphaend = ae; } x = dk3ma_d_add_ok(cx, (r * cos(alphaend)), ec); y = dk3ma_d_add_ok(cy, (r * sin(alphaend)), ec); kdxdt = dk3ma_d_mul_ok( kappa, (-1.0 * dk3ma_d_mul_ok(r, alphaseg, ec) * sin(alphaend)), ec ); kdydt = dk3ma_d_mul_ok( kappa, (dk3ma_d_mul_ok(r, alphaseg, ec) * cos(alphaend)), ec ); fprintf( job->of1, f2lsvg_c8_kw[57], dk3ct_2d_x(&(job->ct2d), dk3ma_d_add_ok(lastx, lastkdxdt, ec), ec), dk3ct_2d_y(&(job->ct2d), dk3ma_d_add_ok(lasty, lastkdydt, ec), ec), dk3ct_2d_x(&(job->ct2d), dk3ma_d_sub_ok(x, kdxdt, ec), ec), dk3ct_2d_y(&(job->ct2d), dk3ma_d_sub_ok(y, kdydt, ec), ec), dk3ct_2d_x(&(job->ct2d), x, ec), dk3ct_2d_y(&(job->ct2d), y, ec) ); fputs(f2lsvg_c8_kw[0], job->of1); lastx = x; lasty = y; lastkdxdt = kdxdt; lastkdydt = kdydt; } /* For closed arc draw the lines. */ if(1 != obj->st) { fprintf( job->of1, f2lsvg_c8_kw[58], dk3ct_2d_x(&(job->ct2d), cx, ec), dk3ct_2d_y(&(job->ct2d), cy, ec) ); fprintf( job->of1, f2lsvg_c8_kw[58], dk3ct_2d_x(&(job->ct2d), sx, ec), dk3ct_2d_y(&(job->ct2d), sy, ec) ); fputs(f2lsvg_c8_kw[59], job->of1); } fputs(f2lsvg_c8_kw[42], job->of1); f2lsvgst_write_style_for_object(job, drw, psvg, obj); fputs(f2lsvg_c8_kw[36], job->of1); } /** Process half-circle object. @param job Job structure. @param drw Drawing structure. @param psvg SVG style collection. @param obj Current object to process. @param ec Pointer to error code variable. */ static void f2lsvg_process_half_circle( f2l_job_t *job, dk3_fig_drawing_t *drw, f2l_svg_t *psvg, dk3_fig_obj_t *obj, int *ec ) { dk3_fig_poly_point_t po[7]; size_t i; /* Traverse po. */ int mec = 0; /* Mathematical error code. */ $? "+ f2lsvg_process_half_circle" po[0].x = 0.0; po[0].y = (obj->dt).hci.ra; po[1].x = -1.0 * FIG2LAT_CIRCLE_QUADRANT_BEZIER * (obj->dt).hci.ra; po[1].y = (obj->dt).hci.ra; po[2].x = -1.0 * (obj->dt).hci.ra; po[2].y = FIG2LAT_CIRCLE_QUADRANT_BEZIER * (obj->dt).hci.ra; po[3].x = -1.0 * (obj->dt).hci.ra; po[3].y = 0.0; po[4].x = -1.0 * (obj->dt).hci.ra; po[4].y = -1.0 * FIG2LAT_CIRCLE_QUADRANT_BEZIER * (obj->dt).hci.ra; po[5].x = -1.0 * FIG2LAT_CIRCLE_QUADRANT_BEZIER * (obj->dt).hci.ra; po[5].y = -1.0 * (obj->dt).hci.ra; po[6].x = 0.0; po[6].y = -1.0 * (obj->dt).hci.ra; if(1.0e-6 < fabs((obj->dt).hci.an)) { for(i = 0; i < 7; i++) { dk3fig_tool_rotate_point(&(po[i]), (obj->dt).hci.an, &mec); } } for(i = 0; i < 7; i++) { dk3fig_tool_shift_point(&(po[i]), (obj->dt).hci.cx, (obj->dt).hci.cy, &mec); } for(i = 0; i < 7; i++) { po[i].x = dk3ct_2d_x(&(job->ct2d), po[i].x, &mec); po[i].y = dk3ct_2d_y(&(job->ct2d), po[i].y, &mec); } fputs(f2lsvg_c8_kw[6], job->of1); f2lsvg_tag_name(job, 54); fputs(f2lsvg_c8_kw[55], job->of1); fprintf(job->of1, f2lsvg_c8_kw[56], po[0].x, po[0].y); fprintf( job->of1, f2lsvg_c8_kw[57], po[1].x, po[1].y, po[2].x, po[2].y, po[3].x, po[3].y ); fputs(f2lsvg_c8_kw[0], job->of1); fprintf( job->of1, f2lsvg_c8_kw[57], po[4].x, po[4].y, po[5].x, po[5].y, po[6].x, po[6].y ); if(obj->st) { fputs(f2lsvg_c8_kw[0], job->of1); fprintf(job->of1, f2lsvg_c8_kw[58], po[0].x, po[0].y); fputs(f2lsvg_c8_kw[59], job->of1); } fputs(f2lsvg_c8_kw[42], job->of1); f2lsvgst_write_style_for_object(job, drw, psvg, obj); fputs(f2lsvg_c8_kw[36], job->of1); if(mec) { *ec = mec; } $? "- f2lsvg_process_half_circle" } /** Process object and arrowheads. @param job Job structure. @param drw Drawing structure. @param psvg SVG style collection. @param obj Current object to process. @param primary Flag: primary (1=primary object, 0=arrowhead). @param ec Pointer to error code variable. */ static void f2lsvg_process_one( f2l_job_t *job, dk3_fig_drawing_t *drw, f2l_svg_t *psvg, dk3_fig_obj_t *obj, int primary, int *ec ) { int op; $? "+ f2lsvg_process_one type=%d primary=%d", obj->ot, primary op = dk3fig_tool_get_operation(drw, obj); $? ". op = %d", op switch(obj->ot) { case DK3_FIG_OBJ_ELLIPSE: { if(op) { f2lsvg_process_ellipse(job, drw, psvg, obj, ec); } } break; case DK3_FIG_OBJ_POLYLINE: { if(op) {f2lsvg_process_polyline(job, drw, psvg, obj, primary, ec); } } break; case DK3_FIG_OBJ_SPLINE: { if(op) {f2lsvg_process_spline(job, drw, psvg, obj, primary, ec); } } break; case DK3_FIG_OBJ_TEXT: { f2lsvg_process_text(job, drw, psvg, obj, ec); } break; case DK3_FIG_OBJ_ARC: { if(op) {f2lsvg_process_arc(job, drw, psvg, obj, ec); } } break; case DK3_FIG_OBJ_PSEUDO_HALF_CIRCLE: { $? ". half-circle %d", op if(op) {f2lsvg_process_half_circle(job, drw, psvg, obj, ec); } } break; case DK3_FIG_OBJ_PSEUDO_FAST_SPLINE: { if(op) { /* f2lsvg_process_spline(job, drw, psvg, obj, primary, ec); */ switch(obj->st) { case 1: case 3: case 5: { f2lsvg_process_fast_closed_spline(job, drw, psvg, obj, ec); } break; default: { f2lsvg_process_fast_open_spline(job, drw, psvg, obj, ec); } break; } } } break; } $? "- f2lsvg_process_one" } /** Check whether we must use a g instruction to group the object with its arrowheads. @param job Job structure. @param obj Current object to process. @return 1 to group, 0 for no group. */ static int f2lsvg_check_must_group(f2l_job_t *job, dk3_fig_obj_t *obj) { int back = 0; $? "+ f2lsvg_check_must_group" if(job->group) { $? ". grouping required" if(obj->af) { $? ". forward arrowhead" if((obj->af)->o1) { $? ". object found" back = 1; } if((obj->af)->o2) { $? ". object found" back = 1; } } if(obj->ab) { $? ". backward arrowhead" if((obj->ab)->o1) { $? ". object found" back = 1; } if((obj->ab)->o2) { $? ". object found" back = 1; } } } $? "- f2lsvg_check_must_group %d", back return back; } /** Process arrowhead object. @param job Job structure. @param drw Drawing structure. @param psvg SVG style collection. @param obj Current object to process. @param ec Pointer to error code variable. */ static void f2lsvg_process_ah_one( f2l_job_t *job, dk3_fig_drawing_t *drw, f2l_svg_t *psvg, dk3_fig_obj_t *obj, int *ec ) { switch (obj->ot) { case DK3_FIG_OBJ_SPLINE: { if ((!(job->xsah)) && (f2lud_is_interpolated_spline(obj))) { obj->ot = DK3_FIG_OBJ_PSEUDO_FAST_SPLINE; f2lsvg_process_one(job, drw, psvg, obj, 0, ec); obj->ot = DK3_FIG_OBJ_SPLINE; } else { f2lsvg_process_one(job, drw, psvg, obj, 0, ec); } } break; default: { f2lsvg_process_one(job, drw, psvg, obj, 0, ec); } break; } } /** Process object and arrowheads. @param job Job structure. @param drw Drawing structure. @param obj Current object to process. */ static void f2lsvg_process_object( f2l_job_t *job, dk3_fig_drawing_t *drw, dk3_fig_obj_t *obj ) { f2l_svg_t *psvg; /* SVG style collection. */ int mg; /* Flag: Must group */ int mec = 0; /* Mathematical error code. */ $? "+ f2lsvg_process_object" psvg = (f2l_svg_t *)(drw->dsd); mg = f2lsvg_check_must_group(job, obj); /* Process object itself. */ if(mg) { fputs(f2lsvg_c8_kw[6], job->of1); f2lsvg_tag_name(job, 35); fputs(f2lsvg_c8_kw[5], job->of1); } $? ". START OBJECT" f2lsvg_process_one(job, drw, psvg, obj, 1, &mec); /* Process arrowheads. */ if(obj->af) { $? ". forward arrowhead" if((obj->af)->o1) { $? ". forward o1" #if VERSION_BEFORE_20140329 f2lsvg_process_one(job,drw,psvg,(dk3_fig_obj_t *)((obj->af)->o1),0,&mec); #else f2lsvg_process_ah_one(job,drw,psvg,(dk3_fig_obj_t *)((obj->af)->o1),&mec); #endif } if((obj->af)->o2) { $? ". forward o2" #if VERSION_BEFORE_20140329 f2lsvg_process_one(job,drw,psvg,(dk3_fig_obj_t *)((obj->af)->o2),0,&mec); #else f2lsvg_process_ah_one(job,drw,psvg,(dk3_fig_obj_t *)((obj->af)->o2),&mec); #endif } $? ". forward arrowhead finished" } if(obj->ab) { $? ". backward arrowhead" if((obj->ab)->o1) { $? ". backward o1" #if VERSION_BEFORE_20140329 f2lsvg_process_one(job,drw,psvg,(dk3_fig_obj_t *)((obj->ab)->o1),0,&mec); #else f2lsvg_process_ah_one(job,drw,psvg,(dk3_fig_obj_t *)((obj->ab)->o1),&mec); #endif } if((obj->ab)->o2) { $? ". backward o2" #if VERSION_BEFORE_20140329 f2lsvg_process_one(job,drw,psvg,(dk3_fig_obj_t *)((obj->ab)->o2),0,&mec); #else f2lsvg_process_ah_one(job,drw,psvg,(dk3_fig_obj_t *)((obj->ab)->o2),&mec); #endif } $? ". backward arrowhead finished" } $? ". END OBJECT" if(mg) { fputs(f2lsvg_c8_kw[6], job->of1); fputs(f2lsvg_c8_kw[8], job->of1); f2lsvg_tag_name(job, 35); fputs(f2lsvg_c8_kw[5], job->of1); } if(mec) { /* ERROR: Mathematical error occured. */ dk3app_log_1(job->app, DK3_LL_ERROR, job->msg, 38); job->exval = FIG2LAT_EXIT_ERROR_MATH; $? ". exitcode" } $? "- f2lsvg_process_object" } void f2lsvg_output(f2l_job_t *job) { dk3_fig_drawing_t *drw; dk3_fig_obj_t *obj; unsigned long objno = 0UL; unsigned long oldsrcline = 0UL; $? "+ f2lsvg_output" oldsrcline = dk3app_get_source_line(job->app); dk3app_set_source_line(job->app, 0UL); drw = job->drw; objno = 0UL; if(f2lsvg_driver_initialize(job, drw)) { if(f2lsvg_open_output_files(job)) { if(f2lsvg_start_processing(job, drw)) { dk3sto_it_reset(drw->iobj); while(NULL != (obj = (dk3_fig_obj_t *)dk3sto_it_next(drw->iobj))) { dk3app_set_source_line(job->app, obj->li); if(!dk3fig_tool_is_bgrect(obj, objno)) { f2lsvg_process_object(job, drw, obj); } objno++; } } else { f2l_tool_set_exit_status(job, FIG2LAT_EXIT_ERROR_UNKNOWN); $? ". exitcode" } f2lsvg_end_processing(job, drw); } else { f2l_tool_set_exit_status(job, FIG2LAT_EXIT_ERROR_UNKNOWN); $? ". exitcode" } f2lsvg_close_output_files(job); } else { f2l_tool_set_exit_status(job, FIG2LAT_EXIT_ERROR_UNKNOWN); $? ". exitcode" } dk3app_set_source_line(job->app, oldsrcline); $? "- f2lsvg_output" f2lsvg_driver_end(job, drw); }