#define PROG_NAME "pz_draw" #define PROG_DESC "produce Postscript drawings of fragment outlines" #define PROG_VERS "1.0" /* Last edited on 2024-11-20 04:55:14 by stolfi */ #define PROG_HELP \ " " PROG_NAME " \\\n" \ " -output PSNAME \\\n" \ " [ -open ] \\\n" \ " [ -plotStep NUM [ -cubic ] ] \\\n" \ " [ -sampleDots ] \\\n" \ " [ -ticks | -extraDots [ -prec NUM ] ] \\\n" \ " [ -axes ] [ -grid NUM ] \\\n" \ pz_plot_gauge_OPTIONS_HELP " \\\n" \ " [ -scaleBarStep NUM | -scaleIconLambda NUM ] \\\n" \ " [ -label DX DY SIZE char *] \\\n" \ " [ -rectFile WNDNAME ] \\\n" \ pz_plot_paging_OPTIONS_HELP " \\\n" \ " [ -windowFile WNDNAME ] \\\n" \ " < CHAINFILE\n" #define PROG_INFO \ "NAME\n" \ " " PROG_NAME " - " PROG_DESC "\n" \ "\n" \ "SYNOPSIS\n" \ PROG_HELP "\n" \ "\n" \ "DESCRIPTION\n" \ " This program reads zero or more curves (\"pz_r3_chain_t\"'s) from" \ " standard input, generates a Postscript (\".ps\" or \".eps\") drawing of" \ " them.\n" \ "\n" \ " ???.\n" \ "\n" \ "OPTIONS\n" \ " ??? \n" \ " ???.\n" \ "\n" \ "DOCUMENTATION OPTIONS\n" \ argparser_help_info_HELP_INFO "\n" \ "\n" \ "SEE ALSO\n" \ " ??? foo(1).\n" \ "\n" \ "AUTHOR\n" \ " Created ??? by ???." /* */ #define _GNU_SOURCE #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include typedef struct options_t { /* Output file options: */ char *output; /* Output file name, minus ".ps" */ /* Plotting options: */ char *rectFile; /* Highlight rectangle filename, minus ".wnd" ("" if none). */ double plotStep; /* Resampling step for plot (0 = do not resample). */ bool_t ticks; /* TRUE to plot a tick mark every 0.05*(chain.ne) points. */ bool_t sampleDots; /* TRUE to plot a dot at every sample position. */ bool_t extraDots; /* TRUE to plot dots at positions given in {dotsFile}. */ char *dotsFile; /* Name of extraDots file (a pz_r3_chain_t), incl. extension */ unsigned dotsPrec; /* Formatting prec for 3rd column of {dotsFile}; 0=omit it. */ double grid; /* pz_plot_grid line spacing, or 0.0 if none. */ bool_t axes; /* TRUE to plot coordinate axes */ bool_t open; /* TRUE omits step from last sample to first sample. */ bool_t cubic; /* TRUE to use cubic interpolation for sampling */ char *label; /* Label text to print at window center, or "" if none. */ double labelSize; /* Label font size in points. */ double labelDX; /* Label X displacement relative to window center. */ double labelDY; /* Label Y displacement relative to window center. */ /* Options for output file format and scale: */ pz_plot_paging_options_t *paginOptions; char *windowFile; /* Window filename, minus ".wnd" ("" if none). */ /* Options that control the scale bar and/or icon at corner: */ pz_plot_gauge_options_t *gaugeOptions; /* Icon style options. */ double scaleIconLambda; /* Basic length for scale/icon */ } options_t; /* PROTOTYPES */ int main( int argc, char **argv ); char *pz_comments( options_t *o ); pz_window_t pz_draw_read_window( char *name ); void pz_draw_plot_tick_marks( PSStream *f, pz_r3_chain_t *c ); void pz_draw_plot_dots_marks( PSStream *f, pz_r3_chain_t *e, unsigned prec ); pz_r3_chain_t pz_draw_sample_chain( pz_r3_chain_t *p, double step, bool_t cubic ); options_t *pz_get_options( int argc, char **argv ); #define pt_per_mm (72.0/25.4) int main( int argc, char **argv ) { r3_t ctr; options_t *o = pz_get_options(argc, argv); pz_window_t w = o->paginOptions->window; if ((o->windowFile != NULL) && (o->windowFile[0] != '\000')) { w = pz_draw_read_window(o->windowFile); } /* Create Postscript figure stream: */ PSStream *f = pswr_new_stream ( /* prefix */ o->output, /* file */ NULL, /* eps */ o->paginOptions->epsFormat, /* docName */ "doc", /* paperSize */ "letter", /* used only if not EPS */ /* landscape */ FALSE, /* hPageSize */ o->paginOptions->actualHor * pt_per_mm, /* used only if EPS */ /* vPageSzie */ o->paginOptions->actualVer * pt_per_mm /* used only if EPS */ ); pswr_set_canvas_layout ( /* ps */ f, /* hPicSize */ o->paginOptions->actualHor * pt_per_mm, /* vPicSize */ o->paginOptions->actualVer * pt_per_mm, /* adjustPicSize */ FALSE, /* hPicMargin */ 4.0, /* vPicMargin */ 4.0, /* captionLines */ (o->paginOptions->epsFormat ? 0 : 1), /* hCount */ o->paginOptions->nCols, /* vCount */ o->paginOptions->nRows ); pswr_new_picture ( f, w.r[HOR].end[0], w.r[HOR].end[1], w.r[VER].end[0], w.r[VER].end[1]); if (o->axes) { pswr_set_pen(f, 0.0,0.0,0.0, 0.10, 0.0,0.0); pswr_coord_line(f, HOR, 0.0); pswr_coord_line(f, VER, 0.0); } if (o->grid > 0.0) { pz_plot_grid(f, o->grid, (r3_t){{0.5,0.5,0.5}}, 0.10); } while (1) { fget_skip_formatting_chars(stdin); if (feof(stdin)){ break; } pz_r3_chain_read_data_t a = pz_r3_chain_read(stdin, FALSE, pz_ctr_NONE); r3_vec_t original = a.c; r3_vec_t sampled = pz_draw_sample_chain(&original, o->plotStep, o->cubic); ctr = pz_r3_chain_area_barycenter(&original); if (! o->paginOptions->epsFormat) { pswr_set_pen(f, 0.0,0.0,0.0, 0.15, 0.0,0.0); pswr_add_caption(f, a.cmt, 0.0); } if (o->ticks){ pz_draw_plot_tick_marks(f, &original); } pswr_set_pen(f, 0.0,0.0,0.0, 0.15, 0.0,0.0); pswr_set_fill_color(f, -1.0,-1.0,-1.0); pz_plot_curve(f, &sampled, (! o->open), 1, 0); if (o->sampleDots){ pz_draw_plot_dots_marks(f, &sampled, 0); } } if (o->extraDots) { fprintf(stderr, "reading %s ...\n", o->dotsFile); FILE *rd = open_read(o->dotsFile, TRUE); pz_r3_chain_read_data_t er = pz_r3_chain_read(rd, FALSE, pz_ctr_NONE); r3_vec_t e = er.c; pz_draw_plot_dots_marks(f, &e, o->dotsPrec); } if (strlen(o->rectFile) != 0) { pz_window_t w = pz_draw_read_window(o->rectFile); interval_t *wx = &(w.r[HOR]), *wy = &(w.r[VER]); pswr_set_pen(f, 0.0,0.0,0.0, 0.10, 0.0,0.0); pswr_set_fill_color(f, -1.0,-1.0,-1.0); pswr_rectangle(f, wx->end[0], wx->end[1], wy->end[0], wy->end[1], FALSE, TRUE); } if (strlen(o->label) != 0) { pswr_set_pen(f, 0.0,0.0,0.0, 0.10, 0.0,0.0); pswr_set_label_font(f, "Courier", o->labelSize); pswr_label(f, o->label, ctr.c[0] + o->labelDX, ctr.c[1] + o->labelDY, 0.0, 0.5, 0.5 ); } if ((o->scaleIconLambda > 0.0) || ( o->gaugeOptions->barCount > 0)) { pswr_set_pen(f, 0.0,0.0,0.0, 0.1, 0.0,0.0); pz_plot_gauge(f, o->scaleIconLambda, o->gaugeOptions); } pswr_close_stream(f); return 0; } pz_r3_chain_t pz_draw_sample_chain( pz_r3_chain_t *p, double step, bool_t cubic ) { if (step <= 0.0) { return *p; } else { int m = p->nel; double_vec_t s = double_vec_new(m); double length = pz_r3_chain_linear_lengths(p, &s); int n = (int)ceil(length/step); r3_vec_t q = r3_vec_new(n); if (cubic) { r3_vec_t dp = r3_vec_new(m); r3_vec_t dq = r3_vec_new(n); pz_r3_chain_estimate_velocities(&s, length, p, &dp, pz_estimate_velocity_L); pz_r3_chain_hermite_uniform_sample(&s, length, p, &dp, 0.0, &q, &dq); } else { pz_r3_chain_linear_uniform_sample(&s, length, p, 0.0, &q); } return q; } } #define NTicks 20 void pz_draw_plot_tick_marks( PSStream *f, pz_r3_chain_t *c ) { int n = c->nel; pswr_set_pen(f, 0.0,0.5,0.0, 0.10, 0.0,0.0); int k; for (k = 0; k <= NTicks-1 ; k++) { int r = pz_round((double)k/(double)NTicks*100.0); int i = pz_round((double)(k*n)/(double)NTicks); char *lab = jsprintf("%02d", r); pswr_label(f, lab, c->el[i].c[0],c->el[i].c[1], 0.0, 0.0,0.0); free(lab); } for (k = 0; k <= NTicks-1 ; k++) { int i = pz_round((double)(k*n)/(double)NTicks); pswr_dot(f, c->el[i].c[0], c->el[i].c[1], 2.0, TRUE, FALSE); } } void pz_draw_plot_dots_marks( PSStream *f, pz_r3_chain_t *e, unsigned prec ) { int n = e->nel; int i; pswr_set_pen(f, 0.0,0.5,0.0, 0.10, 0.0,0.0); if (prec > 0.0) { for (i = 0; i <= n-1 ; i++) { char *lab = jsprintf("%*f", prec, e->el[i].c[2]); pswr_label(f, lab, e->el[i].c[0],e->el[i].c[1], 0.0, 0.0,0.0); free(lab); } } pswr_set_pen(f, 0.0,0.0,0.0, 0.10, 0.0,0.0); for (i = 0; i <= n-1 ; i++) { pswr_dot(f, e->el[i].c[0],e->el[i].c[1], 3.0, TRUE, FALSE); } } pz_window_t pz_draw_read_window( char *name ) { char *fileName = txtcat(name, ".wnd"); fprintf(stderr, "reading %s\n", fileName ); FILE *rd = open_read(fileName, TRUE); free(fileName); return pz_window_read(rd); } options_t *pz_get_options(int argc, char **argv) { argparser_t *pp = argparser_new(stderr, argc, argv); argparser_set_help(pp, PROG_NAME " version " PROG_VERS ", usage:\n" PROG_HELP); argparser_set_info(pp, PROG_INFO); argparser_process_help_info_options(pp); options_t *o = malloc(sizeof(options_t)); o->open = argparser_keyword_present(pp, "-open"); if (argparser_keyword_present(pp, "-rectFile")) { o->rectFile = argparser_get_next(pp); } else { o->rectFile = ""; } if (argparser_keyword_present(pp, "-plotStep")) { o->plotStep = argparser_get_next_double(pp, 0.0, DBL_MAX); o->cubic = argparser_keyword_present(pp, "-cubic"); } else { o->plotStep = 0.0; o->cubic = FALSE; } argparser_get_keyword(pp, "-output"); o->output = argparser_get_next(pp); o->ticks = argparser_keyword_present(pp, "-ticks"); o->sampleDots = argparser_keyword_present(pp, "-sampleDots"); o->extraDots = argparser_keyword_present(pp, "-extraDots"); if (o->extraDots) { o->dotsFile = argparser_get_next(pp); if (argparser_keyword_present(pp, "-prec")) { o->dotsPrec = argparser_get_next_int(pp, 0,16); } else { o->dotsPrec= 0; } } o->axes = argparser_keyword_present(pp, "-axes"); if (argparser_keyword_present(pp, "-grid")) { o->grid = argparser_get_next_double(pp, 0.0, DBL_MAX); } else { o->grid = 0.0; } if (argparser_keyword_present(pp, "-label")) { o->labelDX = argparser_get_next_double(pp, -DBL_MAX, +DBL_MAX); o->labelDY = argparser_get_next_double(pp, -DBL_MAX, +DBL_MAX); o->labelSize = argparser_get_next_double(pp, 0.0, 1000.0); o->label = argparser_get_next(pp); } else { o->labelDX = 0.0; o->labelDY = 0.0; o->labelSize = 0.0; o->label = ""; } o->paginOptions = pz_plot_parse_paging_options (pp, TRUE, 160.0, 160.0); if (argparser_keyword_present(pp, "-windowFile")) { o->windowFile = argparser_get_next(pp); } else { o->windowFile = ""; if (pz_window_is_empty(&(o->paginOptions->window))) { argparser_error ( pp, "must specify \"-objectSize\", \"-window\", or \"-windowFile\"" ); } } o->gaugeOptions = pz_plot_parse_gauge_options(pp); if ( argparser_keyword_present(pp, "-scaleBarStep") || argparser_keyword_present(pp, "-scaleIconLambda") ) { o->scaleIconLambda = argparser_get_next_double(pp, 0.0, DBL_MAX); } else { if ( ( o->gaugeOptions->style != NoGauge ) || ( o->gaugeOptions->barCount > 0 ) ) { argparser_error(pp, "scale icon/bar requires \"-scaleBarStep\" or \"-scaleIconLambda\""); } o->scaleIconLambda = 0.0; } argparser_finish(pp); return o; } /* Copyright © 2001 Universidade Estadual de Campinas (UNICAMP). Authors: Helena C. G. Leitão and Jorge Stolfi. This file can be freely distributed, used, and modified, provided that this copyright and authorship notice is preserved, and that any modified versions are clearly marked as such. This software has NO WARRANTY of correctness or applicability for any purpose. Neither the authors nor their employers chall be held responsible for any losses or damages that may result from its use. */