#define PROG_NAME "pz_draw_cands" #define PROG_DESC "draws a list of candidates, flagging the true ones" #define PROG_VERS "1.0" /* Copyright © 2001 by the State University of Campinas (UNICAMP). */ /* See the copyright, authorship, and warranty notice at end of file. */ /* Last edited on 2015-01-20 16:45:20 by stolfilocal */ #define PROG_HELP \ " " PROG_NAME " \\\n" " -inFile \\\n" " -black \\\n" " -grey \\\n" " [ -pixelSize ] \\\n" " [ -outUnit ] \\\n" " -outFile \\\n" " [ -inside | -outside ]\n" #define PROG_INFO \ "NAME\n" \ " " PROG_NAME " - " PROG_DESC "\n" \ "\n" \ "SYNOPSIS\n" \ PROG_HELP "\n" \ "\n" \ "DESCRIPTION\n" \ " Output file names are \"XXX-NNNNN.eps\" if \"-epsFormat\" is" \ " given, or \"XXX.ps\" otherwise; where XXX is the \"-output\"" \ " parameter, and \"NNNNN\" is the candidate's index in the file.\n" \ "\n" \ "AUTHORS\n" \ " Created in 2001 by Helena C. G. Leitão and Jorge Stolfi at IC-UNICAMP.\n" \ " Converted from Modula-3 to C in 2004-2006 by Jorge Stolfi." #define _GNU_SOURCE #include #include #include #include #include #include #include #include #include #include #include #include #include #include typedec struct Options_t { char *input; /* Input candidate file name. */ unsigned firstCand; /* Index of first candidate to plot. */ unsigned lastCand; /* Index of last candidate to plot. */ char *chainDir; /* Directory where chains can be found. */ char *chainPrefix; /* Chain file name prefix. */ unsigned band; /* Filtering scale ID for file names. */ double step; /* Nominal input sampling step (pixels). */ char *extension; /* Extension for geometric chains (".flc" usually) */ char *output; /* Output plot file (without ".ps"/".eps") */ /* The reference candidate set and comparison parameters: */ char *refInput; /* Reference candidate set name ("" if none). */ bool_t omitTrue; /* TRUE to skip candidates that are in ref set. */ bool_t omitFalse; /* TRUE to skip candidates not in ref. set. */ double minRefLength; /* Min length (pixels) for ref cands (at lambda->0). */ double blurFactor; /* Corner broadening factor. */ double minCompOverlap; /* Minimum overlap (pixels). */ double maxCompShift; /* Maximum displacement on each curve (pixels). */ /* Plotting options */ r2_t shift[2]; /* Displacements to apply to each curve. */ double tilt[2]; /* CCW rotation (degrees) to apply to each curve. */ bool_t segsOnly; /* TRUE does not draw curve outside segment. */ bool_t drawAllSamples; /* TRUE plot all samples, FALSE only every 0.1mm. */ bool_t sampleDots; /* Plot a dot at each sample position. */ bool_t noPointers; /* TRUE omits the arrowheads at the segment ends. */ bool_t noFrame; /* TRUE omits the frame around each candidate. */ bool_t noColors; /* TRUE uses only black, FALSE uses red/blue for segs. */ bool_t noThicker; /* TRUE draws segments like rest of curve, FALSE thicker. */ double labelSize; /* Curve label font size in pt (0 = no labels). */ double mismatchSize; /* Font size in pt for mismatch value (0 = omit). */ double grid; /* Coordinate grid spacing (0 = no grid). */ unsigned drawMatchEvery; /* Draw sample pairs every this many (0 = none). */ /* Options for output file format and scale: */ pz_plot_paging_options_t *paginOptions; /* 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; 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->lastCand >= o->firstCand){ { pz_candidate_read_data_t inpData = pz_draw_cands_read_set(o->input); pz_candidate_vec_t inpCand = inpData.c; pz_candidate_read_data_t refData = pz_draw_cands_read_ref_set(o->refInput; minLength := o->minRefLength, blurFactor := o->blurFactor; lambda := inpData.lambda, step := o->step ); flag = pz_draw_cands_compare_sets( inpData, refData; minCompOverlap := o->minCompOverlap; maxCompShift := o->maxCompShift; step := o->step )^; bool_vec_t chainUsed = ChainsReallyUsed(inpCand, o)^; pz_r3_chain_real_all_data_t chAllData = pz_r3_chain_read_all( o->chainPrefix, o->band, o->extension, sel := chainUsed; dir := o->chainDir, header_only := FALSE, recenter := pz_ctr_NONE ); pz_draw_candidates(inpCand, flag, chAllData.chData^, o); } } pz_candidate_read_data_t pz_draw_cands_read_set(char *name) char *fileName = jsprintf("%s.can", name); FILE *rd = open_read(fileName, TRUE); free(fileName); return pz_candidate_read(rd); } pz_candidate_read_data_t pz_draw_cands_read_ref_set ( char *name, double minLength, double blurFactor, double lambda, double step ) /* Reads a candidate list, and removes entries shorter than "minLength" (minus corner blurring) on either segment. */ { pz_candidate_read_data_t cData; /* Hack to avoid overflow when "step" is zero. */ if (step == 0) { minLength = 0.0; step = 1.0 ;}; int nCands; if (name != NULL) char *fileName = jsprintf("%s.can", name); FILE *rd = open_read(fileName, TRUE); free(fileName); cData = pz_candidate_read(open_read(fileName, TRUE)); affirm(cData.lambda == lambda); fprintf(stderr, "read %d reference candidates\n", cData.c.ne); double minCorrLength = fmax(0.0, minLength - 2.0*blurFactor*cData.lambda); int minSteps = (int)floor(minCorrLength/step); pz_candidate_remove_short(&(cData.c), &(cData.cmt), minSteps); fprintf(stderr, "using %d reference candidates\n", cData.c.ne); } else { nCands = 0; cData.cmt = "No reference candidates"; cData.c = pz_candidate_vec_new(0); cData.lambda = lambda; } return cData; } bool_vec_t *ChainsReallyUsed( pz_candidate.List *cand, Options *o ) { { /* with */ ??? nCands = MIN(o->lastCand, (cand.ne - 1)) - o->firstCand + 1; /* do */ return pz_candidate_chains_used(SUBARRAY(cand, o->firstCand, nCands)); } } /* ChainsReallyUsed */ void pz_draw_candidates( pz_candidate.List *cand, bool_vec_t *flag, ARRAY *OF pz_r3_chain_read_data flc, Options *o ) VAR f: PSPlot.File = NULL; nInFile: unsigned = 0; { affirm((flag.ne) == (cand.ne) ); { /* with */ ??? firstCand = o->firstCand; ??? lastCand = MIN(o->lastCand, (cand.ne - 1)); /* do */ fprintf(stderr, "Drawing candidates from " & Fmt.Int(firstCand) & " to " & Fmt.Int(lastCand) & "\n" ); for ( iCand = firstCand TO lastCand ){ fprintf(stderr, "Considering candidate %s\n", Fmt.Int(iCand) ); if (( ((flag[iCand]) ) ANDAND ( NOT o->omitTrue) ) || ( ((NOT flag[iCand]) ) ANDAND ( NOT o->omitFalse) )){ { /* with */ ??? id = Fmt.Pad(Fmt.Int(iCand), 5, '0'); /* do */ pz_plot.BeginNewDrawing(f, o->output, id, o->drawFmt, nInFile); }; DrawCandidate(f, cand[iCand], flag[iCand], flc, o); }; }; }; pz_plot.NoMoreDrawings(f, o->drawFmt, nInFile); fprintf(stderr, "Drawings finished.\n") } /* pz_draw_candidates */ void DrawCandidate( PSPlot.File f, pz_candidate_t *cand, bool_t flag, ARRAY *OF pz_r3_chain_read_data flc, Options *o ) VAR { if (( o->grid > 0.0 )){ pz_plot.Grid(f, o->grid) ;}; if (( NOT o->noFrame )){ pz_plot.Frame(f) ;}; for (j = 0; j <= 1 ; j++){ { /* with */ ??? seg = cand.seg[j]; ??? chainNum = seg.cvx; ??? chain = flc[chainNum].c^; m = pz_pose.PlaceSegment( seg, chain; tilt := o->tilt[j], shift := o->shift[j]; flip := FALSE /* Hope that "seg.rev = (j = 1). */ ); /* do */ mappedChain[j] = pz_r3_chain_map(chain, m); }; }; pz_plot.Candidate( f, cand, mappedChain[0]^, mappedChain[1]^, whole = NOT o->segsOnly, closed = TRUE, colors = NOT o->noColors, thicker = NOT o->noThicker, dots = o->sampleDots, pointers = NOT o->noPointers, labelSize = o->labelSize, drawEvery = pz_plot.ComputeDrawEvery(f, 0.2, o->step, all = o->drawAllSamples), drawMatchEvery = o->drawMatchEvery ); if (( flag )){ if (( o->noColors )){ f.setLineColor(PSPlot.Black) }else{ f.setLineColor(PSPlot.Color{0.0, 0.7, 0.0}); }; pz_plot.Star(f, radius = max(1.0, o->labelSize/10.0)); }; if (( o->mismatchSize > 0.0 )){ { /* with */ ??? xr = f.getRange(PSPlot.Axis.X); ??? x = xr.min + 0.05*(xr.max - xr.min); ??? yr = f.getRange(PSPlot.Axis.Y); ??? y = yr.min + 0.05*(yr.max - yr.min); ??? mstr = Fmt.LongReal(cand.mismatch, prec := 2, style := Fmt.Style.Fix); /* do */ f.label(mstr, x, y, size = o->mismatchSize); }; }; if (( o->scaleIconLambda > 0.0 ) || ( o->scaleIconOptions.barCount > 0 )){ pz_plot.ScaleIcon(f, lambda = o->scaleIconLambda, o = o->scaleIconOptions); }; } /* DrawCandidate */ bool_vec_t *pz_draw_cands_compare_sets( pz_candidate_read_data_t *inpData, pz_candidate_read_data_t *refData, double minCompOverlap, double maxCompShift, double step ) /* Compares the input candidates "inpData" with the reference candidates "refData", and returns a vector "ok" where "ok[i] == TRUE" iff "inpData.c[i]" is fairly similar to some reference candidate "refData.c[j]". */ { if (( (refData.c^.ne) > 0 )){ affirm(inpData.lambda == refData.lambda ); }; /* Hack to avoid overflow when "step" is zero-> */ if (( step == 0.0 )){ step = minCompOverlap; if (( step == 0.0 )){ step = 1.0 ;}; }; { /* with */ ??? inpCand = inpData.c^; ??? refCand = refData.c^; ??? inpOK = NEW(REF bool_vec_t, (inpCand.ne)); /* do */ if (( (refCand.ne) == 0 )){ for ( iCand = 0 TO (inpCand.ne - 1) ){ inpOK[iCand] = FALSE ;} }else{ { /* with */ ??? refOK = NEW(REF bool_vec_t, (refCand.ne)); ??? minSteps = FLOOR(minCompOverlap / step + 0.0001); ??? maxAdjust = CEILING(maxCompShift / step - 0.0001); /* do */ fprintf(stderr, "Candidate comparison parameters:\n"); fprintf(stderr, " overlap minSteps == %s\n", Fmt.Int(minSteps) ); fprintf(stderr, " alignment maxAdjust == %s\n", Fmt.Int(maxAdjust) ); pz_candidate_find_similar_cands( aCand = inpCand, bCand = refCand, minSteps = minSteps, maxAdjust = maxAdjust, aOK = inpOK^, bOK = refOK^ ); pz_candidate_print_similarity_statistics( stderr, inpOK^, "input", refOK^, "reference" ); }; }; return inpOK; }; } /* pz_draw_cands_compare_sets */ Options pz_get_options(int argc, char **argv ) VAR o: Options; { 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); { /* with */ /* do */ TRY argparser_get_keyword(pp, "-input"); o->input = argparser_get_next(pp); if (( argparser_keyword_present(pp, "-chainDir") )){ o->chainDir = argparser_get_next(pp) }else{ o->chainDir = "."; }; argparser_get_keyword(pp, "-chainPrefix"); o->chainPrefix = argparser_get_next(pp); argparser_get_keyword(pp, "-band"); o->band = argparser_get_next_int(pp); if (( argparser_keyword_present(pp, "-extension") )){ o->extension= argparser_get_next(pp); }else{ o->extension = ".flc"; }; argparser_get_keyword(pp, "-step"); o->step = argparser_get_next_double(pp, 0.0, 1024.0); argparser_get_keyword(pp, "-output"); o->output = argparser_get_next(pp); if (( argparser_keyword_present(pp, "-maxCands") )){ o->firstCand = 0; o->lastCand = argparser_get_next_int(pp, 1) - 1 }else if (( argparser_keyword_present(pp, "-candsRange") )){ o->firstCand = argparser_get_next_int(pp, 0); o->lastCand = argparser_get_next_int(pp, o->firstCand) }else{ o->firstCand = 0; o->lastCand = 239; }; /* Reference set options: */ if (( argparser_keyword_present(pp, "-refInput") )){ o->refInput = argparser_get_next(pp); if (( argparser_keyword_present(pp, "-minRefLength") )){ o->minRefLength = argparser_get_next_double(pp, 0.0) }else{ o->minRefLength = 0.0; }; o->omitTrue = argparser_keyword_present(pp, "-omitTrue"); o->omitFalse = argparser_keyword_present(pp, "-omitFalse"); argparser_get_keyword(pp, "-blurFactor"); o->blurFactor = argparser_get_next_double(pp, 0.01, 100.0); argparser_get_keyword(pp, "-minCompOverlap"); o->minCompOverlap = argparser_get_next_double(pp, 0.0); argparser_get_keyword(pp, "-maxCompShift"); o->maxCompShift = argparser_get_next_double(pp, 0.0); }else{ o->refInput = ""; o->omitTrue = FALSE; o->omitFalse = FALSE; o->minRefLength = 0.0; o->blurFactor = 0.0; o->minCompOverlap = 0.0; o->maxCompShift = 0.0; }; o->drawAllSamples = argparser_keyword_present(pp, "-drawAllSamples"); if (( argparser_keyword_present(pp, "-drawMatch") )){ o->drawMatchEvery = 1 }else if (( argparser_keyword_present(pp, "-drawMatchEvery") )){ o->drawMatchEvery= argparser_get_next_int(pp, 1); }else{ o->drawMatchEvery = 0; }; if (( argparser_keyword_present(pp, "-displace") )){ { /* with */ ??? d = argparser_get_next_double(pp); /* do */ o->shift[0] = LR2.T{0.0, -d/2.0}; o->shift[1] = LR2.T{0.0, +d/2.0}; } }else if (( argparser_keyword_present(pp, "-shift") )){ for (j = 0; j <= 1 ; j++){ for (k = 0; k <= 1 ; k++){ o->shift[j][k] = argparser_get_next_double(pp); }; } }else{ for (j = 0; j <= 1 ; j++){ o->shift[j] = LR2.T{0.0, 0.0}; }; }; if (( argparser_keyword_present(pp, "-tilt") )){ o->tilt[0] = argparser_get_next_double(pp); o->tilt[1] = argparser_get_next_double(pp) }else{ o->tilt[0] = 0.0; o->tilt[1] = 0.0; }; o->segsOnly = argparser_keyword_present(pp, "-segsOnly"); o->sampleDots = argparser_keyword_present(pp, "-sampleDots"); o->noPointers = argparser_keyword_present(pp, "-noPointers"); o->noFrame = argparser_keyword_present(pp, "-noFrame"); o->noColors = argparser_keyword_present(pp, "-noColors"); o->noThicker = argparser_keyword_present(pp, "-noThicker"); if (( argparser_keyword_present(pp, "-labelSize") )){ o->labelSize = pp.getNextReal(0.0, 100.0) }else{ o->labelSize = 12.0; }; if (( argparser_keyword_present(pp, "-mismatchSize") )){ o->mismatchSize = pp.getNextReal(0.0, 100.0) }else{ o->mismatchSize = 12.0; }; if (( argparser_keyword_present(pp, "-grid") )){ o->grid = argparser_get_next_double(pp, 1.0e-10, 1.0e+10) }else{ o->grid = 0.0; }; o->drawFmt = pz_plot.ParseDrawFmtOptions( pp, single = FALSE, defaultWidth = 40.0, defaultHeight = 40.0 ); o->scaleIconOptions = pz_plot.ParseScaleIconOptions(pp); if (( argparser_keyword_present(pp, "-scaleBarStep") ) || ( argparser_keyword_present(pp, "-scaleIconLambda") )){ o->scaleIconLambda = argparser_get_next_double(pp, 0.0); }else{ if (( o->scaleIconOptions.style != pz_plot.ScaleIconStyle.None ) || ( o->scaleIconOptions.barCount > 0 )){ argparser_error(pp, "scale icon/bar requires \"-scaleBarStep\" or \"-scaleIconLambda\""); }; o->scaleIconLambda = 0.0; }; argparser_finish(pp); EXCEPT | ParseParams.Error ==> fprintf(stderr, "Usage: pz_draw_cands \\\n"); fprintf(stderr, " -input NAME \\\n"); fprintf(stderr, " [ -chainDir DIR ] -chainPrefix NAME \\\n"); fprintf(stderr, " -band NUMBER [ -extension EXT ] -step NUM \\\n"); fprintf(stderr, " -output NAME \\\n"); fprintf(stderr, " [ -maxCands NUMBER | -candsRange FIRSTNUM LASTNUM ] \\\n"); fprintf(stderr, " [ -drawAllSamples ] \\\n"); fprintf(stderr, " [ -refInput NAME \\\n"); fprintf(stderr, " [ -minRefLength PIXELS ] \\\n"); fprintf(stderr, " -blurFactor NUM \\\n"); fprintf(stderr, " -minCompOverlap PIXELS -maxCompShift PIXELS \\\n"); fprintf(stderr, " -blurFactor PIXELS \\\n"); fprintf(stderr, " ] \\\n"); fprintf(stderr, " [ -drawMatch | -drawMatchEvery NUMBER ] \\\n"); fprintf(stderr, " [ -displace NUMBER | -shift DXA DYA DXB DYB ] \\\n"); fprintf(stderr, " [ -tilt NUMBER NUMBER ] \\\n"); fprintf(stderr, " [ -segsOnly ] [ -sampleDots ] [ -noColors ] \\\n"); fprintf(stderr, " [ -noPointers ] [ -noFrame ] [ -noThicker ] \\\n"); fprintf(stderr, " [ -labelSize POINTS ] [ -mismatchSize POINTS ] \\\n"); fprintf(stderr, " [ -grid SPACING ] \\\n"); fprintf(stderr, pz_plot.ScaleIconOptionsHelp & " \\\n"); fprintf(stderr, " [ -scaleBarStep NUM | -scaleIconLambda NUM ] \\\n"); fprintf(stderr, pz_plot.DrawFmtOptionsHelp & " \n"); Process.Exit(1); }; }; return o } /* GetOptions */ { /* 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. */