1
{ ******************************************************************
2
Plotting routines for Delphi
3
****************************************************************** }
11
utypes, umath, uround, uinterv, ustrings;
13
function InitGraphics(Canvas : TCanvas; Width, Height : Integer) : Boolean;
15
{ ------------------------------------------------------------------
17
------------------------------------------------------------------
18
The parameters Width and Height refer to the object on which the
23
To draw on a TImage object:
24
InitGraph(Image1.Canvas, Image1.Width, Image1.Height)
27
InitGraph(Printer.Canvas, Printer.PageWidth, Printer.PageHeight)
28
------------------------------------------------------------------ }
30
procedure SetWindow(Canvas : TCanvas;
31
X1, X2, Y1, Y2 : Integer;
32
GraphBorder : Boolean);
33
{ ------------------------------------------------------------------
34
Sets the graphic window
36
X1, X2, Y1, Y2 : Window coordinates in % of maximum
37
GraphBorder : Flag for drawing the window border
38
------------------------------------------------------------------ }
40
procedure AutoScale(X : PVector;
43
var XMin, XMax, XStep : Float);
44
{ ------------------------------------------------------------------
45
Finds an appropriate scale for plotting the data in X[Lb..Ub]
46
------------------------------------------------------------------ }
48
procedure SetOxScale(Scale : TScale;
49
OxMin, OxMax, OxStep : Float);
50
{ ------------------------------------------------------------------
51
Sets the scale on the Ox axis
52
------------------------------------------------------------------ }
54
procedure SetOyScale(Scale : TScale;
55
OyMin, OyMax, OyStep : Float);
56
{ ------------------------------------------------------------------
57
Sets the scale on the Oy axis
58
------------------------------------------------------------------ }
60
procedure SetGraphTitle(Title : String);
61
{ ------------------------------------------------------------------
62
Sets the title for the graph
63
------------------------------------------------------------------ }
65
procedure SetOxTitle(Title : String);
66
{ ------------------------------------------------------------------
67
Sets the title for the Ox axis
68
------------------------------------------------------------------ }
70
procedure SetOyTitle(Title : String);
71
{ ------------------------------------------------------------------
72
Sets the title for the Oy axis
73
------------------------------------------------------------------ }
75
procedure PlotOxAxis(Canvas : TCanvas);
76
{ ------------------------------------------------------------------
77
Plots the horizontal axis
78
------------------------------------------------------------------ }
80
procedure PlotOyAxis(Canvas : TCanvas);
81
{ ------------------------------------------------------------------
82
Plots the vertical axis
83
------------------------------------------------------------------ }
85
procedure PlotGrid(Canvas : TCanvas; Grid : TGrid);
86
{ ------------------------------------------------------------------
87
Plots a grid on the graph
88
------------------------------------------------------------------ }
90
procedure WriteGraphTitle(Canvas : TCanvas);
91
{ ------------------------------------------------------------------
92
Writes the title of the graph
93
------------------------------------------------------------------ }
95
procedure SetMaxCurv(NCurv : Byte);
96
{ ------------------------------------------------------------------
97
Sets the maximum number of curves and re-initializes their
99
------------------------------------------------------------------ }
101
procedure SetPointParam(CurvIndex, Symbol, Size : Integer;
103
{ ------------------------------------------------------------------
104
Sets the point parameters for curve # CurvIndex
105
------------------------------------------------------------------ }
107
procedure SetLineParam(CurvIndex : Integer;
111
{ ------------------------------------------------------------------
112
Sets the line parameters for curve # CurvIndex
113
------------------------------------------------------------------ }
115
procedure SetCurvLegend(CurvIndex : Integer; Legend : String);
116
{ ------------------------------------------------------------------
117
Sets the legend for curve # CurvIndex
118
------------------------------------------------------------------ }
120
procedure SetCurvStep(CurvIndex, Step : Integer);
121
{ ------------------------------------------------------------------
122
Sets the step for curve # CurvIndex
123
------------------------------------------------------------------ }
125
procedure PlotPoint(Canvas : TCanvas;
127
CurvIndex : Integer);
128
{ ------------------------------------------------------------------
129
Plots a point on the screen
130
------------------------------------------------------------------
131
Input parameters : X, Y = point coordinates
132
CurvIndex = index of curve parameters
133
(Symbol, Size, Color)
134
------------------------------------------------------------------ }
136
procedure PlotCurve(Canvas : TCanvas;
139
CurvIndex : Integer);
140
{ ------------------------------------------------------------------
142
------------------------------------------------------------------
143
Input parameters : X, Y = point coordinates
144
Lb, Ub = indices of first and last points
145
CurvIndex = index of curve parameters
146
------------------------------------------------------------------ }
148
procedure PlotCurveWithErrorBars(Canvas : TCanvas;
151
CurvIndex : Integer);
152
{ ------------------------------------------------------------------
153
Plots a curve with error bars
154
------------------------------------------------------------------
155
Input parameters : X, Y = point coordinates
157
Ns = number of SD to be plotted
158
Lb, Ub = indices of first and last points
159
CurvIndex = index of curve parameters
160
------------------------------------------------------------------ }
162
procedure PlotFunc(Canvas : TCanvas;
166
CurvIndex : Integer);
167
{ ------------------------------------------------------------------
169
------------------------------------------------------------------
171
Func = function to be plotted
172
Xmin, Xmax = abscissae of 1st and last point to plot
173
Npt = number of points
174
CurvIndex = index of curve parameters (Width, Style, Color)
175
------------------------------------------------------------------
176
The function must be programmed as :
177
function Func(X : Float) : Float;
178
------------------------------------------------------------------ }
180
procedure WriteLegend(Canvas : TCanvas;
183
ShowLines : Boolean);
184
{ ------------------------------------------------------------------
185
Writes the legends for the plotted curves
186
------------------------------------------------------------------
187
NCurv : number of curves (1 to MaxCurv)
188
ShowPoints : for displaying points
189
ShowLines : for displaying lines
190
------------------------------------------------------------------ }
192
procedure ConRec(Canvas : TCanvas;
193
Nx, Ny, Nc : Integer;
196
{ ------------------------------------------------------------------
198
Adapted from Paul Bourke, Byte, June 1987
199
http://astronomy.swin.edu.au/~pbourke/projection/conrec/
200
------------------------------------------------------------------
202
Nx, Ny = number of steps on Ox and Oy
203
Nc = number of contour levels
204
X[0..Nx], Y[0..Ny] = point coordinates in pixels
205
Z[0..(Nc - 1)] = contour levels in increasing order
206
F[0..Nx, 0..Ny] = function values, such that F[I,J] is the
207
function value at (X[I], Y[I])
208
------------------------------------------------------------------ }
210
function Xpixel(X : Float) : Integer;
211
{ ------------------------------------------------------------------
212
Converts user abscissa X to screen coordinate
213
------------------------------------------------------------------ }
215
function Ypixel(Y : Float) : Integer;
216
{ ------------------------------------------------------------------
217
Converts user ordinate Y to screen coordinate
218
------------------------------------------------------------------ }
220
function Xuser(X : Integer) : Float;
221
{ ------------------------------------------------------------------
222
Converts screen coordinate X to user abscissa
223
------------------------------------------------------------------ }
225
function Yuser(Y : Integer) : Float;
226
{ ------------------------------------------------------------------
227
Converts screen coordinate Y to user ordinate
228
------------------------------------------------------------------ }
230
procedure LeaveGraphics;
231
{ ------------------------------------------------------------------
233
------------------------------------------------------------------ }
239
MaxSymbol = 9; { Max. number of symbols for plotting curves }
240
MaxCurvColor = 9; { Max. number of colors for curves }
241
Eps = 1.0E-10; { Lower limit for an axis label }
242
MaxColor = $02FFFFFF; { Max. color value for Delphi }
245
CurvColor : array[1..MaxCurvColor] of TColor =
257
TAxis = record { Coordinate axis }
264
TPointParam = record { Point parameters }
265
Symbol : Integer; { Symbol: 0: point (.) }
266
Size : Integer; { 1: solid circle 2: open circle }
267
Color : TColor; { 3: solid square 4: open square }
268
end; { 5: solid triangle 6: open triangle }
269
{ 7: plus (+) 8: multiply (x) }
272
TLineParam = record { Line parameters }
278
TCurvParam = record { Curve parameters }
279
PointParam : TPointParam;
280
LineParam : TLineParam;
281
Legend : Str30; { Legend of curve }
282
Step : Integer; { Plot 1 point every Step points }
285
TCurvParamVector = array[1..255] of TCurvParam;
286
PCurvParamVector = ^TCurvParamVector;
289
Xwin1, Xwin2, Ywin1, Ywin2 : Integer;
290
XminPixel, XmaxPixel : Integer;
291
YminPixel, YmaxPixel : Integer;
292
FactX, FactY : Float;
293
XAxis, YAxis : TAxis;
294
GraphTitle, XTitle, YTitle : String;
296
CurvParam : PCurvParamVector;
297
GraphWidth, GraphHeight : Integer;
298
SymbolSizeUnit : Integer;
300
PenStyle : TPenStyle;
301
PenColor, BrushColor : TColor;
302
BrushStyle : TBrushStyle;
304
procedure DimCurvParamVector(var CurvParam : PCurvParamVector; Ub : Byte);
309
GetMem(CurvParam, Ub * SizeOf(TCurvParam));
310
if CurvParam = nil then Exit;
314
{ Initialize curve parameters }
316
with CurvParam^[I] do
318
PointParam.Symbol := (I - 1) mod MaxSymbol + 1;
319
PointParam.Size := 2;
320
PointParam.Color := CurvColor[(I - 1) mod MaxCurvColor + 1];
321
Legend := 'Curve ' + LTrim(IntStr(I));
322
LineParam.Width := 1;
323
LineParam.Style := psSolid;
324
LineParam.Color := PointParam.Color;
329
procedure DelCurvParamVector(var CurvParam : PCurvParamVector; Ub : Byte);
331
if CurvParam <> nil then
333
FreeMem(CurvParam, Ub * SizeOf(TCurvParam));
339
function InitGraphics(Canvas : TCanvas; Width, Height : Integer) : Boolean;
342
GraphHeight := Height;
343
SymbolSizeUnit := GraphWidth div 250;
355
MaxCurv := MaxSymbol;
356
DimCurvParamVector(CurvParam, MaxCurv);
358
InitGraphics := True;
361
procedure SetWindow(Canvas : TCanvas;
362
X1, X2, Y1, Y2 : Integer;
363
GraphBorder : Boolean);
367
if (X1 >= 0) and (X2 <= 100) and (X1 < X2) then
371
R := 0.01 * GraphWidth;
372
XminPixel := Round(X1 * R);
373
XmaxPixel := Round(X2 * R);
376
if (Y1 >= 0) and (Y2 <= 100) and (Y1 < Y2) then
380
R := 0.01 * GraphHeight;
381
YminPixel := Round(Y1 * R);
382
YmaxPixel := Round(Y2 * R);
385
XAxis.Scale := LinScale;
390
YAxis.Scale := LinScale;
395
FactX := (XmaxPixel - XminPixel) / (XAxis.Max - XAxis.Min);
396
FactY := (YmaxPixel - YminPixel) / (YAxis.Max - YAxis.Min);
399
Canvas.Rectangle(XminPixel, YminPixel, Succ(XmaxPixel), Succ(YmaxPixel));
402
procedure AutoScale(X : PVector; Lb, Ub : Integer; Scale : TScale;
403
var XMin, XMax, XStep : Float);
408
{ Minimum and maximum of X }
415
else if X^[I] > X2 then
420
if Scale = LinScale then
422
Interval(X1, X2, 2, 6, XMin, XMax, XStep);
426
{ Logarithmic scale }
432
if X1 <= 0.0 then Exit;
434
XMin := Int(Log10(X1)); if X1 < 1.0 then XMin := XMin - 1.0;
435
XMax := Int(Log10(X2)); if X2 > 1.0 then XMax := XMax + 1.0;
440
procedure SetOxScale(Scale : TScale; OxMin, OxMax, OxStep : Float);
442
XAxis.Scale := Scale;
446
if OxMin < OxMax then
451
if OxStep > 0.0 then XAxis.Step := OxStep;
455
if (OxMin > 0.0) and (OxMin < OxMax) then
457
XAxis.Min := Floor(Log10(OxMin));
458
XAxis.Max := Ceil(Log10(OxMax));
463
FactX := (XmaxPixel - XminPixel) / (XAxis.Max - XAxis.Min);
466
procedure SetOyScale(Scale : TScale; OyMin, OyMax, OyStep : Float);
468
YAxis.Scale := Scale;
472
if OyMin < OyMax then
477
if OyStep > 0.0 then YAxis.Step := OyStep;
481
if (OyMin > 0.0) and (OyMin < OyMax) then
483
YAxis.Min := Floor(Log10(OyMin));
484
YAxis.Max := Ceil(Log10(OyMax));
489
FactY := (YmaxPixel - YminPixel) / (YAxis.Max - YAxis.Min);
492
function Xpixel(X : Float) : Integer;
496
P := FactX * (X - XAxis.Min);
497
if Abs(P) > 30000 then
500
Xpixel := Round(P) + XminPixel;
503
function Ypixel(Y : Float) : Integer;
507
P := FactY * (YAxis.Max - Y);
508
if Abs(P) > 30000 then
511
Ypixel := Round(P) + YminPixel;
514
function Xuser(X : Integer) : Float;
516
Xuser := XAxis.Min + (X - XminPixel) / FactX;
519
function Yuser(Y : Integer) : Float;
521
Yuser := YAxis.Max - (Y - YminPixel) / FactY;
524
procedure SetGraphTitle(Title : String);
529
procedure SetOxTitle(Title : String);
534
procedure SetOyTitle(Title : String);
539
procedure PlotLine(Canvas : TCanvas; X1, Y1, X2, Y2 : Integer);
541
Canvas.MoveTo(X1, Y1);
542
Canvas.LineTo(X2, Y2);
545
procedure PlotOxAxis(Canvas : TCanvas);
548
Wp, Xp, Yp1, Yp2 : Integer;
550
TickLength : Integer;
551
MinorTickLength : Integer;
554
TickLength := Canvas.TextHeight('M') div 2;
555
MinorTickLength := Round(0.67 * TickLength);
557
PlotLine(Canvas, XminPixel, YmaxPixel, XmaxPixel, YmaxPixel);
559
N := Round((XAxis.Max - XAxis.Min) / XAxis.Step); { Nb of intervals }
560
X := XAxis.Min; { Tick mark position }
562
Yp1 := YmaxPixel + TickLength; { End of tick mark }
563
Yp2 := YmaxPixel + MinorTickLength; { End of minor tick mark (log scale) }
565
for I := 0 to N do { Label axis }
567
if (XAxis.Scale = LinScale) and (Abs(X) < Eps) then X := 0.0;
571
PlotLine(Canvas, Xp, YmaxPixel, Xp, Yp1);
573
if XAxis.Scale = LinScale then Z := X else Z := Exp10(X);
575
XLabel := Trim(FloatStr(Z));
577
Canvas.TextOut(Xp - Canvas.TextWidth(XLabel) div 2, Yp1, XLabel);
579
{ Plot minor divisions on logarithmic scale }
581
if (XAxis.Scale = LogScale) and (I < N) then
586
PlotLine(Canvas, Wp, YmaxPixel, Wp, Yp2);
595
Canvas.TextOut(XminPixel + (XmaxPixel - XminPixel -
596
Canvas.TextWidth(XTitle)) div 2,
597
YmaxPixel + 4 * TickLength, XTitle);
600
procedure PlotOyAxis(Canvas : TCanvas);
603
Wp, Xp1, Xp2, Yp : Integer;
605
TickLength : Integer;
606
MinorTickLength : Integer;
610
TickLength := Canvas.TextWidth('M') div 2;
611
MinorTickLength := Round(0.67 * TickLength);
612
Yoffset := Canvas.TextHeight('M') div 2;
614
PlotLine(Canvas, XminPixel, YminPixel, XminPixel, YmaxPixel);
616
N := Round((YAxis.Max - YAxis.Min) / YAxis.Step);
619
Xp1 := XminPixel - TickLength;
620
Xp2 := XminPixel - MinorTickLength;
624
if (YAxis.Scale = LinScale) and (Abs(Y) < Eps) then Y := 0.0;
628
PlotLine(Canvas, XminPixel, Yp, Xp1, Yp);
630
if YAxis.Scale = LinScale then Z := Y else Z := Exp10(Y);
632
YLabel := Trim(FloatStr(Z));
634
Canvas.TextOut(Xp1 - Canvas.TextWidth(YLabel), Yp - Yoffset, YLabel);
636
if (YAxis.Scale = LogScale) and (I < N) then
641
PlotLine(Canvas, XminPixel, Wp, Xp2, Wp);
648
Canvas.TextOut(XminPixel, YminPixel - 3 * Yoffset, YTitle);
651
procedure PlotGrid(Canvas : TCanvas; Grid : TGrid);
654
I, N, Xp, Yp : Integer;
657
PenStyle : TpenStyle;
660
PenStyle := Canvas.Pen.Style;
661
Canvas.Pen.Style := psDot;
663
if Grid in [HorizGrid, BothGrid] then { Horizontal lines }
665
N := Round((YAxis.Max - YAxis.Min) / YAxis.Step); { Nb of intervals }
666
for I := 1 to Pred(N) do
668
Y := YAxis.Min + I * YAxis.Step; { Origin of line }
670
PlotLine(Canvas, XminPixel, Yp, XmaxPixel, Yp);
674
if Grid in [VertiGrid, BothGrid] then { Vertical lines }
676
N := Round((XAxis.Max - XAxis.Min) / XAxis.Step);
677
for I := 1 to Pred(N) do
679
X := XAxis.Min + I * XAxis.Step;
681
PlotLine(Canvas, Xp, YminPixel, Xp, YmaxPixel);
685
Canvas.Pen.Style := PenStyle;
688
procedure WriteGraphTitle(Canvas : TCanvas);
690
if GraphTitle <> '' then
692
TextOut((XminPixel + XmaxPixel - TextWidth(GraphTitle)) div 2,
693
YminPixel - 2 * TextHeight(GraphTitle), GraphTitle);
696
procedure SetMaxCurv(NCurv : Byte);
698
if NCurv < 1 then Exit;
699
DelCurvParamVector(CurvParam, MaxCurv);
701
DimCurvParamVector(CurvParam, MaxCurv);
704
procedure SetPointParam(CurvIndex, Symbol, Size : Integer;
707
if (CurvIndex < 1) or (CurvIndex > MaxCurv) then Exit;
709
if (Symbol >= 0) and (Symbol <= MaxSymbol) then
710
CurvParam^[CurvIndex].PointParam.Symbol := Symbol;
713
CurvParam^[CurvIndex].PointParam.Size := Size;
715
if (Color >= 0) and (Color <= MaxColor) then
716
CurvParam^[CurvIndex].PointParam.Color := Color;
719
procedure SetLineParam(CurvIndex : Integer;
725
if (CurvIndex < 1) or (CurvIndex > MaxCurv) then Exit;
727
CurvParam^[CurvIndex].LineParam.Style := Style;
730
CurvParam^[CurvIndex].LineParam.Width := Width;
732
if (Color >= 0) and (Color <= MaxColor) then
733
CurvParam^[CurvIndex].LineParam.Color := Color;
736
procedure SetCurvLegend(CurvIndex : Integer; Legend : String);
738
if (CurvIndex >= 1) and (CurvIndex <= MaxCurv) then
739
CurvParam^[CurvIndex].Legend := Legend;
742
procedure SetCurvStep(CurvIndex, Step : Integer);
744
if (CurvIndex >= 1) and (CurvIndex <= MaxCurv) and (Step > 0) then
745
CurvParam^[CurvIndex].Step := Step;
748
function XOutOfBounds(X : Integer) : Boolean;
749
{ Checks if an absissa is outside the graphic bounds }
751
XOutOfBounds := (X < XminPixel) or (X > XmaxPixel);
754
function YOutOfBounds(Y : Integer) : Boolean;
755
{ Checks if an ordinate is outside the graphic bounds }
757
YOutOfBounds := (Y < YminPixel) or (Y > YmaxPixel);
760
function CheckPoint(X, Y : Float;
761
var Xp, Yp : Integer) : Boolean;
762
{ Computes the pixel coordinates of a point and
763
checks if it is enclosed within the graph limits }
767
CheckPoint := not(XOutOfBounds(Xp) or YOutOfBounds(Yp));
770
procedure PlotSymbol(Canvas : TCanvas;
772
CurvIndex : Integer);
774
Xp1, Xp2, Yp1, Yp2, Size : Integer;
776
Size := CurvParam^[CurvIndex].PointParam.Size * SymbolSizeUnit;
780
Xp2 := Xp + Size + 1;
781
Yp2 := Yp + Size + 1;
784
case CurvParam^[CurvIndex].PointParam.Symbol of
785
0 : Pixels[Xp, Yp] := Brush.Color;
786
1, 2 : Ellipse(Xp1, Yp1, Xp2, Yp2); { Circle }
787
3, 4 : Rectangle(Xp1, Yp1, Xp2, Yp2); { Square }
788
5, 6 : Polygon([Point(Xp1, Yp2 - 1),
790
Point(Xp, Yp1 - 1)]); { Triangle }
792
PlotLine(Canvas, Xp, Yp1, Xp, Yp2);
793
PlotLine(Canvas, Xp1, Yp, Xp2, Yp);
796
PlotLine(Canvas, Xp1, Yp1, Xp2, Yp2);
797
PlotLine(Canvas, Xp1, Yp2 - 1, Xp2, Yp1 - 1);
800
PlotLine(Canvas, Xp, Yp1, Xp, Yp2);
801
PlotLine(Canvas, Xp1, Yp, Xp2, Yp);
802
PlotLine(Canvas, Xp1, Yp1, Xp2, Yp2);
803
PlotLine(Canvas, Xp1, Yp2 - 1, Xp2, Yp1 - 1);
808
procedure SetGraphSettings(Canvas : TCanvas; CurvIndex : Integer);
809
{ Saves the current graphic properties of the Canvas
810
and sets them to the values of curve # CurvIndex }
812
PenColor := Canvas.Pen.Color;
813
PenStyle := Canvas.Pen.Style;
814
PenWidth := Canvas.Pen.Width;
815
BrushColor := Canvas.Brush.Color;
816
BrushStyle := Canvas.Brush.Style;
818
Canvas.Pen.Color := CurvParam^[CurvIndex].LineParam.Color;
819
Canvas.Pen.Style := CurvParam^[CurvIndex].LineParam.Style;
820
Canvas.Pen.Width := CurvParam^[CurvIndex].LineParam.Width;
821
Canvas.Brush.Color := CurvParam^[CurvIndex].PointParam.Color;
823
if CurvParam^[CurvIndex].PointParam.Symbol in [0, 1, 3, 5] then
824
Canvas.Brush.Style := bsSolid
826
Canvas.Brush.Style := bsClear;
829
procedure RestoreGraphSettings(Canvas : TCanvas);
831
Canvas.Pen.Color := PenColor;
832
Canvas.Pen.Style := PenStyle;
833
Canvas.Pen.Width := PenWidth;
834
Canvas.Brush.Color := BrushColor;
835
Canvas.Brush.Style := BrushStyle;
838
procedure PlotPoint(Canvas : TCanvas;
840
CurvIndex : Integer);
844
if XAxis.Scale = LogScale then X := Log10(X);
845
if YAxis.Scale = LogScale then Y := Log10(Y);
847
if not CheckPoint(X, Y, Xp, Yp) then Exit;
849
SetGraphSettings(Canvas, CurvIndex);
850
PlotSymbol(Canvas, Xp, Yp, CurvIndex);
851
RestoreGraphSettings(Canvas);
854
procedure PlotErrorBar(Canvas : TCanvas;
857
Xp, Yp, Size : Integer);
858
{ Plots an error bar with the current canvas settings }
862
PenStyle : TPenStyle;
864
Size := Size * SymbolSizeUnit;
865
PenStyle := Canvas.Pen.Style;
866
Canvas.Pen.Style := psSolid;
870
if YAxis.Scale = LogScale then Y1 := Log10(Y1);
873
if Yp1 <= YmaxPixel then
875
PlotLine(Canvas, Xp - Size, Yp1, Xp + Size + 1, Yp1);
876
PlotLine(Canvas, Xp, Yp, Xp, Yp1);
879
PlotLine(Canvas, Xp, Yp, Xp, YmaxPixel);
882
if YAxis.Scale = LogScale then Y1 := Log10(Y1);
885
if Yp1 >= YminPixel then
887
PlotLine(Canvas, Xp - Size, Yp1, Xp + Size + 1, Yp1);
888
PlotLine(Canvas, Xp, Yp, Xp, Yp1);
891
PlotLine(Canvas, Xp, Yp, Xp, YminPixel);
893
Canvas.Pen.Style := PenStyle;
896
procedure GenPlotCurve(Canvas : TCanvas;
901
ErrorBars : Boolean);
902
{ General curve plotting routine }
904
X1, Y1, X2, Y2 : Float;
905
Xp1, Yp1, Xp2, Yp2 : Integer;
907
Flag1, Flag2 : Boolean;
909
SetGraphSettings(Canvas, CurvIndex);
913
X1 := X^[Lb]; if XAxis.Scale = LogScale then X1 := Log10(X1);
914
Y1 := Y^[Lb]; if YAxis.Scale = LogScale then Y1 := Log10(Y1);
916
Flag1 := CheckPoint(X1, Y1, Xp1, Yp1);
920
PlotSymbol(Canvas, Xp1, Yp1, CurvIndex);
921
if ErrorBars and (S^[Lb] > 0.0) then
922
PlotErrorBar(Canvas, Y^[Lb], S^[Lb], Ns, Xp1, Yp1, CurvIndex);
925
{ Plot other points and connect them by lines if necessary }
927
I := Lb + CurvParam^[CurvIndex].Step;
931
X2 := X^[I]; if XAxis.Scale = LogScale then X2 := Log10(X2);
932
Y2 := Y^[I]; if YAxis.Scale = LogScale then Y2 := Log10(Y2);
934
Flag2 := CheckPoint(X2, Y2, Xp2, Yp2);
938
PlotSymbol(Canvas, Xp2, Yp2, CurvIndex);
939
if ErrorBars and (S^[I] > 0.0) then
940
PlotErrorBar(Canvas, Y^[I], S^[I], Ns, Xp2, Yp2, CurvIndex);
941
if (CurvParam^[CurvIndex].LineParam.Style <> psClear) and Flag1 then
942
PlotLine(Canvas, Xp1, Yp1, Xp2, Yp2);
948
Inc(I, CurvParam^[CurvIndex].Step);
951
RestoreGraphSettings(Canvas);
954
procedure PlotCurve(Canvas : TCanvas;
957
CurvIndex : Integer);
959
GenPlotCurve(Canvas, X, Y, nil, 0, Lb, Ub, CurvIndex, False);
962
procedure PlotCurveWithErrorBars(Canvas : TCanvas;
966
CurvIndex : Integer);
968
GenPlotCurve(Canvas, X, Y, S, Ns, Lb, Ub, CurvIndex, True);
971
procedure PlotFunc(Canvas : TCanvas;
975
CurvIndex : Integer);
977
X1, Y1, X2, Y2, H : Float;
978
Xp1, Yp1, Xp2, Yp2 : Integer;
979
Flag1, Flag2 : Boolean;
982
if (Npt < 2) or (CurvParam^[CurvIndex].LineParam.Style = psClear) then Exit;
990
H := (Xmax - Xmin) / Npt;
992
SetGraphSettings(Canvas, CurvIndex);
994
{ Check first point }
996
if XAxis.Scale = LinScale then
999
Y1 := Func(Exp10(X1));
1001
if YAxis.Scale = LogScale then Y1 := Log10(Y1);
1002
Flag1 := CheckPoint(X1, Y1, Xp1, Yp1);
1004
{ Check other points and plot lines if possible }
1005
for I := 1 to Npt do
1008
if XAxis.Scale = LinScale then
1011
Y2 := Func(Exp10(X2));
1013
if YAxis.Scale = LogScale then Y2 := Log10(Y2);
1015
Flag2 := CheckPoint(X2, Y2, Xp2, Yp2);
1017
if Flag1 and Flag2 then
1018
PlotLine(Canvas, Xp1, Yp1, Xp2, Yp2);
1026
RestoreGraphSettings(Canvas);
1029
procedure WriteLegend(Canvas : TCanvas;
1032
ShowLines : Boolean);
1035
CharHeight, I, L, Lmax : Integer;
1036
N, Nmax, Xp, Xl, Y : Integer;
1038
N := 0; { Nb of legends to be plotted }
1039
Lmax := 0; { Length of the longest legend }
1041
for I := 1 to NCurv do
1042
if CurvParam^[I].Legend <> '' then
1045
L := Canvas.TextWidth(CurvParam^[I].Legend);
1046
if L > Lmax then Lmax := L;
1049
if (N = 0) or (Lmax = 0) then Exit;
1051
{ Character height }
1052
CharHeight := Canvas.TextHeight('M');
1054
{ Max. number of legends which may be plotted }
1055
Nmax := Round((YmaxPixel - YminPixel) / CharHeight) - 1;
1056
if N > Nmax then N := Nmax;
1058
{ Draw rectangle around the legends }
1059
Canvas.Rectangle(XmaxPixel + Round(0.02 * GraphWidth), YminPixel,
1060
XmaxPixel + Round(0.12 * GraphWidth) + Lmax,
1061
YminPixel + (N + 1) * CharHeight);
1063
L := Round(0.02 * GraphWidth); { Half-length of line }
1064
Xp := XmaxPixel + 3 * L; { Position of symbol }
1065
Xl := XmaxPixel + 5 * L; { Position of legend }
1067
if NCurv <= Nmax then N := NCurv else N := Nmax;
1072
SetGraphSettings(Canvas, I);
1074
{ Plot point and line }
1075
Y := YminPixel + I * CharHeight;
1077
PlotSymbol(Canvas, Xp, Y, I);
1079
PlotLine(Canvas, Xp - L, Y, Xp + L, Y);
1082
Brush.Style := bsClear;
1083
Canvas.TextOut(Xl, Y - CharHeight div 2, CurvParam^[I].Legend);
1086
RestoreGraphSettings(Canvas);
1089
procedure ConRec(Canvas : TCanvas;
1090
Nx, Ny, Nc : Integer;
1095
{ Mapping from vertex numbers to X offsets }
1096
Im : array[0..3] of Integer = (0, 1, 1, 0);
1098
{ Mapping from vertex numbers to Y offsets }
1099
Jm : array[0..3] of Integer = (0, 0, 1, 1);
1101
{ Case switch table }
1102
CasTab : array[0..2, 0..2, 0..2] of Integer =
1103
(((0,0,8), (0,2,5), (7,6,9)),
1104
((0,3,4), (1,3,1), (4,3,0)),
1105
((9,6,7), (5,2,0), (8,0,0)));
1108
I, J, K, M, M1, M2, M3 : Integer;
1109
X1, X2, Y1, Y2 : Float;
1111
Xp, Yp : PIntVector;
1115
H : array[0..4] of Float; { Relative heights of the box above contour }
1116
Ish : array[0..4] of Integer; { Sign of H() }
1117
Xh : array[0..4] of Integer; { X coordinates of box }
1118
Yh : array[0..4] of Integer; { Y coordinates of box }
1121
Case0, NoneInTri, NoneInBox;
1124
{ Check the input parameters for validity }
1129
if (Nx <= 0) or (Ny <= 0) or (Nc <= 0) then PrmErr := True;
1131
for K := 1 to Nc - 1 do
1132
if Z^[K] <= Z^[K - 1] then PrmErr := True;
1136
SetErrCode(MatErrDim);
1140
{ Convert user coordinates to pixels }
1142
DimIntVector(Xp, Nx);
1143
DimIntVector(Yp, Ny);
1146
Xp^[I] := Xpixel(X^[I]);
1149
Yp^[J] := Ypixel(Y^[J]);
1151
{ Scan the array, top down, left to right }
1153
for J := Ny - 1 downto 0 do
1155
for I := 0 to Nx - 1 do
1157
{ Find the lowest vertex }
1158
if F^[I]^[J] < F^[I]^[J + 1] then
1161
Fmin := F^[I]^[J + 1];
1163
if F^[I + 1]^[J] < Fmin then
1164
Fmin := F^[I + 1]^[J];
1166
if F^[I + 1]^[J + 1] < Fmin then
1167
Fmin := F^[I + 1]^[J + 1];
1169
{ Find the highest vertex }
1170
if F^[I]^[J] > F^[I]^[J + 1] then
1173
Fmax := F^[I]^[J + 1];
1175
if F^[I + 1]^[J] > Fmax then
1176
Fmax := F^[I + 1]^[J];
1178
if F^[I + 1]^[J + 1] > Fmax then
1179
Fmax := F^[I + 1]^[J + 1];
1181
if (Fmax < Z^[0]) or (Fmin > Z^[Nc - 1]) then
1184
{ Draw each contour within this box }
1185
for K := 0 to Nc - 1 do
1187
if (Z^[K] < Fmin) or (Z^[K] > Fmax) then
1190
for M := 4 downto 0 do
1194
H[M] := F^[I + Im[M - 1]]^[J + Jm[M - 1]] - Z^[K];
1195
Xh[M] := Xp^[I + Im[M - 1]];
1196
Yh[M] := Yp^[J + Jm[M - 1]];
1201
H[0] := (H[1] + H[2] + H[3] + H[4]) / 4;
1202
Xh[0] := (Xp^[I] + Xp^[I + 1]) div 2;
1203
Yh[0] := (Yp^[J] + Yp^[J + 1]) div 2;
1206
if H[M] > 0 then Ish[M] := 2;
1207
if H[M] < 0 then Ish[M] := 0;
1208
if H[M] = 0 then Ish[M] := 1;
1211
{ Scan each triangle in the box }
1218
M1 := M; M2 := 0; M3 := M + 1;
1219
if M3 = 5 then M3 := 1;
1221
case CasTab[Ish[M1], Ish[M2], Ish[M3]] of
1225
{ Line between vertices M1 and M2 }
1233
{ Line between vertices M2 and M3 }
1241
{ Line between vertices M3 and M1 }
1249
{ Line between vertex M1 and side M2-M3 }
1253
X2 := (H[M3] * Xh[M2] - H[M2] * Xh[M3]) / (H[M3] - H[M2]);
1254
Y2 := (H[M3] * Yh[M2] - H[M2] * Yh[M3]) / (H[M3] - H[M2]);
1257
{ Line between vertex M2 and side M3-M1 }
1261
X2 := (H[M1] * Xh[M3] - H[M3] * Xh[M1]) / (H[M1] - H[M3]);
1262
Y2 := (H[M1] * Yh[M3] - H[M3] * Yh[M1]) / (H[M1] - H[M3]);
1265
{ Line between vertex M3 and side M1-M2 }
1269
X2 := (H[M2] * Xh[M1] - H[M1] * Xh[M2]) / (H[M2] - H[M1]);
1270
Y2 := (H[M2] * Yh[M1] - H[M1] * Yh[M2]) / (H[M2] - H[M1]);
1273
{ Line between sides M1-M2 and M2-M3 }
1275
X1 := (H[M2] * Xh[M1] - H[M1] * Xh[M2]) / (H[M2] - H[M1]);
1276
Y1 := (H[M2] * Yh[M1] - H[M1] * Yh[M2]) / (H[M2] - H[M1]);
1277
X2 := (H[M3] * Xh[M2] - H[M2] * Xh[M3]) / (H[M3] - H[M2]);
1278
Y2 := (H[M3] * Yh[M2] - H[M2] * Yh[M3]) / (H[M3] - H[M2]);
1281
{ Line between sides M2-M3 and M3-M1 }
1283
X1 := (H[M3] * Xh[M2] - H[M2] * Xh[M3]) / (H[M3] - H[M2]);
1284
Y1 := (H[M3] * Yh[M2] - H[M2] * Yh[M3]) / (H[M3] - H[M2]);
1285
X2 := (H[M1] * Xh[M3] - H[M3] * Xh[M1]) / (H[M1] - H[M3]);
1286
Y2 := (H[M1] * Yh[M3] - H[M3] * Yh[M1]) / (H[M1] - H[M3]);
1289
{ Line between sides M3-M1 and M1-M2 }
1291
X1 := (H[M1] * Xh[M3] - H[M3] * Xh[M1]) / (H[M1] - H[M3]);
1292
Y1 := (H[M1] * Yh[M3] - H[M3] * Yh[M1]) / (H[M1] - H[M3]);
1293
X2 := (H[M2] * Xh[M1] - H[M1] * Xh[M2]) / (H[M2] - H[M1]);
1294
Y2 := (H[M2] * Yh[M1] - H[M1] * Yh[M2]) / (H[M2] - H[M1]);
1298
Canvas.Pen.Color := CurvParam^[K mod MaxCurv + 1].LineParam.Color;
1299
PlotLine(Canvas, Trunc(X1), Trunc(Y1), Trunc(X2), Trunc(Y2));
1309
procedure LeaveGraphics;
1311
DelCurvParamVector(CurvParam, MaxCurv);