%% options copyright owner = Dirk Krause copyright year = 2012-2013 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 "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 }; $* Tool functions $* /** 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_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; 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; } } /** 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_size_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_size_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_size_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" min = dk3ma_d_to_size_ok((obj->dt).spl.ts, ec); if(obj->af) { $? ". have forward arrow" if((obj->dt).spl.te >= (obj->dt).spl.ts) { max = dk3ma_d_to_size_ok((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" max = dk3ma_d_to_size_ok((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 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 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_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) { fputs((obj->dt).txt.st, job->of1); } 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_size_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; } $? "- 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 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" f2lsvg_process_one(job,drw,psvg,(dk3_fig_obj_t *)((obj->af)->o1),0,&mec); } if((obj->af)->o2) { $? ". forward o2" f2lsvg_process_one(job,drw,psvg,(dk3_fig_obj_t *)((obj->af)->o2),0,&mec); } $? ". forward arrowhead finished" } if(obj->ab) { $? ". backward arrowhead" if((obj->ab)->o1) { $? ". backward o1" f2lsvg_process_one(job,drw,psvg,(dk3_fig_obj_t *)((obj->ab)->o1),0,&mec); } if((obj->ab)->o2) { $? ". backward o2" f2lsvg_process_one(job,drw,psvg,(dk3_fig_obj_t *)((obj->ab)->o2),0,&mec); } $? ". 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); }