MODULE PZDrawFiltering EXPORTS Main; (* Draw two versions of the same curve, and their correspondence. *) (* Last edited on 2001-11-15 16:11:23 by stolfi *) (* This program draws two sampled curves (or hodographs) and draws them one on top of each other, showing the matching implied by the associated labels. The program assumes that the samples for the two curves are stored in files "A.X" and "B.X", where "A" and "B" are arbitrary names, and "X" is a given extension (".flc" for curves, ".flv" for hodographs, etc.). The associated labels are read from files "A.lbl" and "B.lbl". *) IMPORT ParseParams, Text, Wr, Rd, FileRd, Process, OSError, Thread; IMPORT PSPlot, LR3; IMPORT PZLR3Chain, PZLRChain, PZSegment, PZMatch; IMPORT PZPlot, PZGeo; FROM Stdio IMPORT stderr; FROM PZTypes IMPORT LONG, NAT, BOOL; <* FATAL Wr.Failure, Thread.Alerted *> TYPE Options = RECORD curveA, curveB: TEXT; (* Input curve names (without extension). *) extension: TEXT; (* Extension for the curve samples (".flc" usually) *) output: TEXT; (* Output plot file (without ".ps"/".eps") *) label: TEXT; (* Label to show at the curve's center, or "". *) (* Plotting options *) scaleA, scaleB: LONG; (* Scaling factor for each curve. *) drawMatchEvery: NAT; (* Plot every this many samples of the match. *) drawSegments: NAT; (* If nonzero, plots this many segments. *) (* Options for output file format and scale: *) drawFmt: PZPlot.DrawFmtOptions; (* Options that request the `filter scale' icon at corner: *) scaleIconOptions: PZPlot.ScaleIconOptions; (* Icon style options. *) scaleIconLambda: LONG; (* Basic length for scale/icon *) END; TYPE CurveData = RECORD samples: PZLR3Chain.ReadData; labels: PZLRChain.ReadData END; PROCEDURE Main() = VAR o: Options := GetOptions(); f: PSPlot.File := NIL; BEGIN WITH cdA = ReadSamplesAndLabels(o.curveA, o.extension, o.scaleA), cdB = ReadSamplesAndLabels(o.curveB, o.extension, o.scaleB) DO PZPlot.BeginSingleDrawing(f, o.output, o.drawFmt); DrawCurves(f, cdA, cdB, o); PZPlot.EndSingleDrawing(f, o.drawFmt) END; END Main; PROCEDURE GetOptions(): Options = VAR o: Options; BEGIN WITH pp = NEW(ParseParams.T).init(stderr) DO TRY pp.getKeyword("-curves"); o.curveA := pp.getNext(); o.curveB := pp.getNext(); IF pp.keywordPresent("-extension") THEN o.extension:= pp.getNext(); ELSE o.extension := ".flc"; END; pp.getKeyword("-output"); o.output := pp.getNext(); o.drawFmt := PZPlot.ParseDrawFmtOptions( pp, single := TRUE, defaultWidth := 160.0d0, defaultHeight := 160.0d0 ); IF pp.keywordPresent("-label") THEN o.label := pp.getNext() ELSE o.label := "" END; IF pp.keywordPresent("-scale") THEN o.scaleA := pp.getNextLongReal(0.1d0, 10.0d0); o.scaleB := pp.getNextLongReal(0.1d0, 10.0d0) ELSE o.scaleA := 1.0d0; o.scaleB := 1.0d0 END; IF pp.keywordPresent("-drawMatchEvery") THEN o.drawMatchEvery := pp.getNextInt(1) ELSE o.drawMatchEvery := 1 END; IF pp.keywordPresent("-drawSegments") THEN o.drawSegments := pp.getNextInt(1) ELSE o.drawSegments := 0 END; o.scaleIconOptions := PZPlot.ParseScaleIconOptions(pp); IF pp.keywordPresent("-scaleBarStep") OR pp.keywordPresent("-scaleIconLambda") THEN o.scaleIconLambda := pp.getNextLongReal(0.0d0); ELSE IF o.scaleIconOptions.style # PZPlot.ScaleIconStyle.None OR o.scaleIconOptions.barCount > 0 THEN pp.error("scale icon/bar requires \"-scaleBarStep\" or \"-scaleIconLambda\"") END; o.scaleIconLambda := 0.0d0 END; pp.finish(); EXCEPT | ParseParams.Error => Wr.PutText(stderr, "Usage: PZDrawCands \\\n"); Wr.PutText(stderr, " -curves NAMEA NAMEB [ -extension EXT ] \\\n"); Wr.PutText(stderr, " -output NAME \\\n"); Wr.PutText(stderr, " [ -scale SCALEA SCALEB ] \\\n"); Wr.PutText(stderr, " [ -drawMatchEvery NSAMPLES ] \\\n"); Wr.PutText(stderr, PZPlot.ScaleIconOptionsHelp & " \\\n"); Wr.PutText(stderr, " [ -label STRING ] \\\n"); Wr.PutText(stderr, " [ -scaleBarStep NUM | -scaleIconLambda NUM ] \\\n"); Wr.PutText(stderr, PZPlot.DrawFmtOptionsHelp & " \n"); Process.Exit(1); END; END; RETURN o END GetOptions; PROCEDURE DrawCurves( VAR f: PSPlot.File; READONLY cdA: CurveData; READONLY cdB: CurveData; READONLY o: Options; )= BEGIN PZPlot.Frame(f); DoDrawCurves(f, o, cdA.samples, cdA.labels, PSPlot.Blue, FALSE, cdB.samples, cdB.labels, PSPlot.Red, TRUE ); IF o.scaleIconLambda > 0.0d0 OR o.scaleIconOptions.barCount > 0 THEN PZPlot.ScaleIcon(f, lambda := o.scaleIconLambda, o := o.scaleIconOptions) END; END DrawCurves; PROCEDURE DoDrawCurves( f: PSPlot.File; READONLY o: Options; READONLY chA: PZLR3Chain.ReadData; READONLY lbA: PZLRChain.ReadData; READONLY colorA: PSPlot.Color; dotsA: BOOL; (* Plot dots on curve A *) READONLY chB: PZLR3Chain.ReadData; READONLY lbB: PZLRChain.ReadData; READONLY colorB: PSPlot.Color; dotsB: BOOL; (* Plot dots on curve B *) ) = (* Draws the curves proper, assuming that curve "A" has the smallest step size. *) BEGIN <* ASSERT NUMBER(chA.c^) = NUMBER(lbA.c^) *> <* ASSERT NUMBER(chB.c^) = NUMBER(lbB.c^) *> WITH ca = chA.c^, ma = NUMBER(ca), cb = chB.c^, sa = PZSegment.T{cvx := 0, tot := ma, ini := 0, ns := ma+1, rev := FALSE}, oa = PZLR3Chain.AreaBarycenter(ca), ob = PZLR3Chain.AreaBarycenter(cb), ctr = LR3.Scale(0.5d0, LR3.Add(oa, ob)), trn = PZGeo.Translation(LR3.Neg(ctr)), (* "cc" is "cb" resampled at the same times as "ca": *) cc = NEW(REF PZLR3Chain.T, ma)^ DO <* ASSERT lbB.stride = lbA.stride *> PZLR3Chain.LinearTimeSample(lbB.c^, lbB.stride, cb, lbA.c^, cc); WITH caMapped = PZLR3Chain.Map(ca, trn)^, cbMapped = PZLR3Chain.Map(cb, trn)^, ccMapped = PZLR3Chain.Map(cc, trn)^ DO (* Draw the matching lines: *) f.setLineSolid(); f.setFillColor(PSPlot.Invisible); f.setLineWidth(0.1); f.setLineColor(PSPlot.Color{0.500, 0.500, 0.500}); WITH match = PZMatch.MostPerfect(sa.ns, sa.ns)^, phase = ma DIV 2 DO PZPlot.Match(f, match, caMapped, ccMapped, sa, sa, drawEvery := o.drawMatchEvery, phaseA := phase, phaseB := phase ) END; (* Draw markers for some pairs of corresp. segments: *) IF o.drawSegments > 0 THEN FOR k := 0 TO o.drawSegments-1 DO WITH caIni = (ma * k) DIV o.drawSegments, caLim = (ma * (k+1)) DIV o.drawSegments, za = PZSegment.T{ cvx := 0, tot := ma, ini := caIni, ns := (caLim - caIni) DIV 2, rev := FALSE }, zb = PZLRChain.MapSegment(za, lbA.c^, lbB.c^, lbA.stride) DO f.setLineColor(colorA); PZPlot.SegmentBrackets(f, za, caMapped, width := 20.0, length := 8.0); f.setLineColor(colorB); PZPlot.SegmentBrackets(f, zb, cbMapped, width := 20.0, length := 8.0); END END END; (* Draw the contour label: *) IF NOT Text.Empty(o.label) THEN f.setTextColor(PSPlot.Black); PZPlot.SegmentLabel(f, sa, caMapped, minRelDist := 1.0d0, label := o.label); END; (* Draw the two curves, with dots at the original samples: *) f.setLineWidth(0.1); f.setFillColor(PSPlot.Invisible); f.setLineColor(colorA); PZPlot.Curve(f, caMapped, closed := TRUE, drawEvery := 1); IF dotsA THEN PZPlot.Dots(f, caMapped, size := 2.0, drawEvery := 1); END; f.setLineColor(colorB); PZPlot.Curve(f, ccMapped, closed := TRUE, drawEvery := 1); IF dotsB THEN PZPlot.Dots(f, cbMapped, size := 2.0, drawEvery := 1); END; END END END DoDrawCurves; PROCEDURE ReadSamplesAndLabels( curve: TEXT; extension: TEXT; scale: LONG; ): CurveData = BEGIN WITH samples = PZLR3Chain.Read( OpenRead(curve & extension), headerOnly := FALSE, centralize := FALSE ), labels = PZLRChain.Read(OpenRead(curve & ".lbl"), headerOnly := FALSE) DO IF scale # 1.0d0 THEN WITH c = samples.c^ DO FOR i := 0 TO LAST(c) DO c[i] := LR3.Scale(scale, c[i]) END END END; RETURN CurveData{ samples := samples, labels := labels } END END ReadSamplesAndLabels; PROCEDURE OpenRead(name: TEXT): Rd.T = <* FATAL OSError.E *> BEGIN Wr.PutText(stderr, "reading " & name & "\n"); RETURN FileRd.Open(name) END OpenRead; BEGIN Main() END PZDrawFiltering. (* 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. *)