MathgeomGLS
4497 строк · 119.3 Кб
1unit uCanvas;
2
3interface
4
5uses
6Winapi.OpenGL,
7System.Types,
8System.Classes,
9System.SysUtils,
10System.Math,
11Vcl.Dialogs,
12Vcl.Graphics,
13
14GLS.OpenGLTokens,
15GLS.Context,
16GLS.VectorTypes,
17GLS.Canvas,
18GLS.VectorGeometry,
19GLS.Color,
20
21GLS.State,
22GLS.RenderContextInfo,
23GLS.WindowsFont,
24
25uGlobal,
26uParser,
27fPrint,
28fFuncts;
29
30type
31TTextLocObject = class(TObject)
32constructor Create(x, y: integer; c: TColor; T: string);
33destructor Destroy; override;
34private
35public
36TextString: string;
37TextColor: integer;
38xLoc: integer;
39yLoc: integer;
40end;
41
42TfxCanvas = class(TGLCanvas)
43private
44
45CharW, CharH: integer; { GLWinBitFont width and height }
46dxGrad, dyGrad: extended;
47dx10Grad, dy10Grad: extended;
48IntegXMax, IntegXMin: extended;
49IntegYMax, IntegYMin: extended;
50xDigits, yDigits: integer;
51PlotList: TList; { used to hold function TGraphPointObjects }
52yfx1List: TList; { used to hold y = f'(x) TGraphPointObjects }
53yfx2List: TList; { used to hold y = f"(x) TGraphPointObjects }
54IntegList: TList; { used to hold Integral TGraphPointObjects }
55SectorList: TList; { used to hold polar Integral sectors }
56FxParser: TFxParser;
57function FormatValue(const n: integer; const v, dv: extended): string;
58function CoordX(x: extended): integer;
59function CoordY(y: extended): integer;
60function CoordLogX(x: extended): integer;
61function CoordLogY(y: extended): integer;
62function EvaluateFunction(const x: extended): extended;
63function ValueX(const x: integer): extended;
64function ValueLogX(const x: integer): extended;
65procedure AddXAxisText(x: extended;
66xCoord, yCoord, halfWd: integer; atTop: Boolean);
67procedure AddYAxisText(y: extended;
68xCoord, yCoord, halfWd: integer; atRight: Boolean);
69procedure DrawXGridLinear;
70procedure DrawYGridLinear;
71procedure DrawXGridLog;
72procedure DrawYGridLog;
73procedure DrawPolarGrid;
74procedure DrawXAxisLinear;
75procedure DrawYAxisLinear;
76procedure DrawXAxisLog;
77procedure DrawYAxisLog;
78procedure PlotFunction(Selected: Boolean);
79procedure PlotAsCartesian(Selected: Boolean);
80procedure PlotAsPolar(Selected: Boolean);
81procedure PopulateCartesian(var L: TList);
82procedure PopulateCartesianLogX(var L: TList);
83procedure PopulateCartesianLogY(var L: TList);
84procedure PopulateCartesianLogXY(var L: TList);
85procedure PopulatePolar(var L: TList);
86procedure PopulateDerivCartesian(var Ls, L: TList);
87procedure PopulateDerivPolar(var Ls, L: TList);
88procedure NoNumberCartesian(var L: Tlist; const P, C: TGraphPoint; const i: integer);
89procedure NoNumberDerivCartesian(var L: Tlist; const P, C: TGraphPoint; const i: integer);
90procedure NoNumberPolar(var L: Tlist; var P, C: TGraphPoint; const i: integer);
91procedure InfinityCartesian(var L: Tlist; var P, C: TGraphPoint; const i: integer);
92procedure InfinityPolar(var L: Tlist; var P, C: TGraphPoint; const i: integer);
93function LineIsValid(var P, C: TGraphPoint): Boolean;
94procedure AnalyseCartesian(var L: TList);
95procedure AnalyseDerivCartesian(var L: TList);
96procedure AnalysePolar(var L: TList);
97procedure DrawCartesian(var L: TList);
98procedure DrawPolar(var L: TList);
99procedure Draw_yfx1(var L: Tlist);
100procedure Draw_yfx2(Var L: TList);
101procedure IntegrateCartesian;
102procedure IntegratePolar;
103procedure IntegrateYCartesian;
104procedure IntegrateBetweenFunctions;
105procedure IntegrateVolumeX;
106procedure IntegrateVolumeY;
107procedure FindfxValues(const y: extended);
108procedure DrawfxPoints;
109procedure Findfx1Values(const dy: extended);
110procedure Drawfx1Points;
111procedure Findfx2Values(const d2y: extended);
112procedure Drawfx2Points;
113procedure DrawCartesianCoordinates;
114procedure DrawPolarCoordinates;
115procedure ClearTextList;
116procedure ClearPointList(var L: TList);
117function SumSegments(var aNeg, aPos: extended): extended;
118function SumYSegments(var aNeg, aPos: extended): extended;
119protected
120procedure QuadVertices(x, y, xRadius, yRadius: Single;
121q1, q2, q3, q4: Boolean);
122public
123TextList: TList;
124constructor Create(bufferSizeX, bufferSizeY: Integer); overload;
125destructor Destroy; override;
126{ Draws a filled ellipse with (x1,y1)-(x2, y2) bounding rectangle }
127procedure FillEllipseBB(const x1, y1, x2, y2: Integer); overload;
128procedure FillEllipseBB(const x1, y1, x2, y2: Single); overload;
129procedure FillQuadrants(const x, y: Integer;
130const xRadius, yRadius: Single;
131q1, q2, q3, q4: Boolean);
132procedure FillQuadrantsBB(const x1, y1, x2, y2: Integer;
133q1, q2, q3, q4: Boolean);
134procedure StartRadialFill(const x, y: Integer);
135procedure FillSector(x, y: Integer);
136procedure StopRadialFill;
137procedure SetupFont(var rci: TGLRenderContextInfo;
138var wbf: TGLWindowsBitmapFont);
139procedure SetGLWinBitFont(var rci: TGLRenderContextInfo;
140var wbf: TGLWindowsBitmapFont;
141Nm: string; Sz: integer; St: TFontStyles);
142procedure AddFunctionLabelsText;
143procedure xAxisGradsCalc(var wbf: TGLWindowsBitmapFont);
144procedure yAxisGradsCalc(var wbf: TGLWindowsBitmapFont);
145procedure DrawAxes;
146procedure DrawTextList(var rci: TGLRenderContextInfo; L: TList;
147var wbf: TGLWindowsBitmapFont);
148procedure DrawFunctions;
149procedure DrawNumericData;
150procedure DrawTextBlocks(var rci: TGLRenderContextInfo;
151var wbf: TGLWindowsBitmapFont);
152end;
153
154//======================================================================
155implementation
156//======================================================================
157
158uses
159fPlot1D,
160fNumeric,
161fTextBlocks,
162fIntegrateX,
163fIntegrateY,
164fBetween,
165fVolumeX,
166fVolumeY,
167fBitmap,
168fxValue,
169fx1Value,
170fx2Value;
171
172constructor TTextLocObject.Create(x, y: integer; c: TColor; T: string);
173begin
174inherited Create;
175xLoc := x;
176yLoc := y;
177TextColor := c;
178TextString := T;
179end;
180
181destructor TTextLocObject.Destroy;
182begin
183inherited Destroy;
184end;
185
186constructor TfxCanvas.Create(bufferSizeX, bufferSizeY: Integer);
187begin inherited;
188TextList := TList.Create;
189PlotList := TList.Create;
190FxParser := TFxParser.Create(0);
191end;
192
193destructor TfxCanvas.Destroy;
194begin
195ClearTextList;
196ClearPointList(Plotlist);
197
198with FxParser do
199begin
200Calculus.Free;
201Calculus := nil;
202Free;
203end;
204inherited;
205end;
206
207function TfxCanvas.FormatValue(const n: integer; const v, dv: Extended): string;
208var
209s: string;
210d: integer;
211
212begin
213d := 1;
214if n > 3 then // decide which format to use
215begin
216Result := FloatToStrF(v, ffExponent, d, 1);
217s := FloatToStrF(v + dv, ffExponent, d, 1);
218
219while Result = s do
220begin
221Inc(d);
222Result := FloatToStrF(v, ffExponent, d, 1);
223s := FloatToStrF(v + dv, ffExponent, d, 1);
224end;
225Dec(d);
226
227Result := FloatToStrF(v, ffExponent, d, 1);
228end
229else Result := FloatToStrF(v, ffGeneral, 6, n);
230end;
231
232// linear X coordinate
233function TfxCanvas.CoordX(x: extended): integer;
234begin
235Result := round(CanvasSizeX*(x - GraphData.xMin)/(GraphData.xMax - GraphData.xMin));
236end;
237
238// linear Y coordinate
239function TfxCanvas.CoordY(y: extended): integer;
240begin
241Result := CanvasSizeY -
242round(CanvasSizeY*(y - GraphData.yMin)/(GraphData.yMax - GraphData.yMin));
243end;
244
245// log X coordinate
246function TfxCanvas.CoordLogX(x: Extended): integer;
247begin
248Result := round(CanvasSizeX*(Log10(x)-
249Log10(GraphData.xMin))/(Log10(GraphData.xMax)-Log10(GraphData.xMin)));
250end;
251
252// log Y coordinate
253function TfxCanvas.CoordLogY(y: Extended): integer;
254begin
255Result := CanvasSizeY -
256round(CanvasSizeY*(Log10(y)-Log10(GraphData.yMin))/(Log10(GraphData.yMax)-Log10(GraphData.yMin)));
257end;
258
259function TfxCanvas.EvaluateFunction(const x: extended): extended;
260begin
261with FxParser do
262if Assigned(Calculus) then
263try
264VarX.Value := x;
265Result := Calculus.Eval;
266except
267Result := NaN;
268end
269else Result := 0;
270end;
271
272function TfxCanvas.ValueX(const x: integer): extended;
273begin
274with GraphData do Result := xMin + x*(xMax - xMin)/CanvasSizeX;
275end;
276
277function TfxCanvas.ValueLogX(const x: integer): extended;
278var
279LogMin, a: extended;
280
281begin
282with GraphData do
283begin
284LogMin := Log10(xMin);
285a := LogMin + x*(Log10(xMax) - LogMin)/CanvasSizeX;
286end;
287Result := Power(10, a);
288end;
289
290procedure TfxCanvas.AddXAxisText(x: extended;
291xCoord, yCoord, halfWd: integer; atTop: Boolean);
292var
293s: string;
294
295begin
296s := FormatValue(xDigits, x, dxGrad );
297
298with GraphData do
299begin
300if Grid.GridStyle = gsCartesian then // Cartesian grid drawn
301begin
302if atTop
303then TextList.Add(TTextLocObject.Create(
304xCoord + 2*CharW div 3 + halfWd,
3058 + AxisWidth, xAxisColor, s))
306else TextList.Add(TTextLocObject.Create(
307xCoord + 2*CharW div 3 + halfWd,
308yCoord - 8 - CharH - AxisWidth ,xAxisColor, s));
309end
310else
311begin
312if atTop
313then TextList.Add(TTextLocObject.Create(
314xCoord - CharW div 3,
31515 + halfWd, xAxisColor, s))
316else TextList.Add(TTextLocObject.Create(
317xCoord - CharW div 3,
318yCoord - 15 - CharH - halfWd, xAxisColor, s));
319end;
320end;
321end;
322
323procedure TfxCanvas.AddYAxisText(y: extended;
324xCoord, yCoord, halfWd: integer; atRight: Boolean);
325var
326s: string;
327
328
329begin
330s := FormatValue(yDigits, y, dyGrad);
331
332with GraphData do
333begin
334if Grid.GridStyle = gsCartesian then { Cartesian grid drawn }
335begin
336if atRight
337then TextList.Add(TTextLocObject.Create(
338CanvasSizeX - Length(s)*CharW - AxisWidth - 5,
339yCoord - 3*CharH div 2 - halfWd, yAxisColor, s)) { at right }
340else TextList.Add(TTextLocObject.Create(xCoord + 2*CharW + halfWd,
341yCoord - 3*CharH div 2 - halfWd, yAxisColor, s));
342end
343else
344begin
345if atRight
346then TextList.Add(TTextLocObject.Create(
347CanvasSizeX - Length(s)*CharW - AxisWidth - 15,
348yCoord - 7*CharH div 8, yAxisColor, s)) { at right }
349else TextList.Add(TTextLocObject.Create(xCoord + halfWd + 25,
350yCoord - 7*CharH div 8, yAxisColor, s));
351end;
352end;
353end;
354
355procedure TfxCanvas.AddFunctionLabelsText;
356var
357i: integer;
358x, y: integer;
359LabelStr: string;
360
361begin
362with FunctionsForm.CheckListBox do
363begin
364for i := 0 to Items.Count -1 do if Checked[i] then
365begin
366with GraphData do
367begin
368PlotData := TPlotDataObject(Items.Objects[i]).Data;
369if Plotdata.ShowLabel and
370(PlotData.xLabel > xMin) and (PlotData.xLabel < xMax) and
371(PlotData.yLabel > yMin) and (PlotData.yLabel < yMax) then
372begin
373if PlotData.TextStr = '' then LabelStr := ''
374else if PlotData.PlotAsFx
375then LabelStr := 'y = '+PlotData.TextStr
376else LabelStr := 'r = '+PlotData.TextStr;
377
378if Grid.xAxisStyle = asLog
379then x := CoordLogX(PlotData.xLabel)
380else x := CoordX(PlotData.xLabel);
381
382if Grid.yAxisStyle = asLog
383then y := CoordLogY(PlotData.yLabel)
384else y := CoordY(PlotData.yLabel);
385
386TextList.Add(TTextLocObject.Create(x, y,
387PlotData.PlotColor, LabelStr));
388end;
389end;
390end;
391GraphData.PlotData := TPlotDataObject(Items.Objects[ItemIndex]).Data;
392end;
393end;
394
395procedure TfxCanvas.DrawXGridLinear;
396var
397xO, xCoord, c: integer;
398atRight: Boolean;
399x: extended;
400yMinCoord, yMaxCoord: integer;
401
402begin
403with GraphData do
404begin
405yMinCoord := CoordY(yMin);
406yMaxCoord := CoordY(yMax);
407
408xO := CoordX(0); { x origin, i.e. y axis }
409atRight := (xO >= CanvasSizeX - 6*CharW - AxisWidth div 2);
410
411x := trunc(xMin/dx10Grad)*dx10Grad;
412c := round((xMin - x)/dxGrad);
413x := x + c*dxGrad;
414
415if c < 0 then Inc(c, 10);
416
417while x < xMax do
418begin
419if c mod 10 = 0 then
420begin
421PenColor := xAxisColor;
422PenWidth := MajorWidth;
423end
424else
425begin
426PenColor := GridColor;
427PenWidth := MinorWidth;
428end;
429
430xCoord := CoordX(x);
431
432if (abs(xCoord - xO) > 2) or atRight then
433begin
434MoveTo(xCoord, yMinCoord);
435LineTo(xCoord, yMaxCoord);
436end;
437
438x := x + dxGrad;
439Inc(c);
440end;
441end;
442end;
443
444procedure TfxCanvas.DrawYGridLinear;
445var
446yO, yCoord, c: integer;
447atTop: Boolean;
448y: extended;
449xMinCoord, xMaxCoord: integer;
450
451begin
452with GraphData do
453begin
454xMinCoord := CoordX(xMin);
455xMaxCoord := CoordX(xMax);
456
457yO := CoordY(0); { y origin, i.e. x axis }
458atTop := (yO <= 2*CharH + AxisWidth);
459
460y := trunc(yMin/dy10Grad)*dy10Grad;
461c := round((yMin - y)/dyGrad);
462y := y + c*dyGrad;
463
464if c < 0 then Inc(c, 10);
465
466while y < yMax do
467begin
468if c mod 10 = 0 then
469begin
470PenColor := yAxisColor;
471PenWidth := MajorWidth;
472end
473else
474begin
475PenColor := GridColor;
476PenWidth := MinorWidth;
477end;
478
479yCoord := CoordY(y);
480
481if (abs(yCoord - yO) > 2) or atTop then
482begin
483MoveTo(xMinCoord, yCoord);
484LineTo(xMaxCoord, yCoord);
485end;
486
487y := y + dyGrad;
488Inc(c);
489end;
490end;
491end;
492
493procedure TfxCanvas.DrawXGridLog;
494var
495xCoord, ixCoord, yMinCoord, yMaxCoord, i: integer;
496x, dx: extended;
497
498begin
499with GraphData do
500begin
501yMinCoord := CoordY(yMin);
502yMaxCoord := CoordY(yMax);
503dx := 10*dx10Grad;
504xCoord := CoordLogX(dx);
505while xCoord > 0 do
506begin
507PenColor := xAxisColor;
508PenWidth := MajorWidth;
509MoveTo(xCoord, yMinCoord);
510LineTo(xCoord, yMaxCoord);
511x := dx;
512PenColor := GridColor;
513PenWidth := MinorWidth;
514for i := 2 to 9 do
515begin
516x := x + dx;
517if x < xMax then
518begin
519ixCoord := CoordLogX(x);
520MoveTo(ixCoord, yMinCoord);
521LineTo(ixCoord, yMaxCoord);
522end;
523end;
524dx := dx/10;
525xCoord := CoordLogX(dx);
526end;
527x := dx;
528for i := 2 to 9 do
529begin
530x := x + dx;
531if x > xMin then
532begin
533ixCoord := CoordLogX(x);
534MoveTo(ixCoord, yMinCoord);
535LineTo(ixCoord, yMaxCoord);
536end;
537end;
538end;
539end;
540
541procedure TfxCanvas.DrawYGridLog;
542var
543yCoord, iyCoord, xMinCoord, xMaxCoord, i: integer;
544y, dy: extended;
545
546begin
547with GraphData do
548begin
549xMinCoord := CoordX(xMin);
550xMaxCoord := CoordX(xMax);
551dy := 10*dy10Grad;
552yCoord := CoordLogY(dy);
553while yCoord < CanvasSizeY do
554begin
555PenColor := yAxisColor;
556PenWidth := MajorWidth;
557MoveTo(xMinCoord, yCoord);
558LineTo(xMaxCoord, yCoord);
559y := dy;
560PenColor := GridColor;
561PenWidth := MinorWidth;
562for i := 2 to 9 do
563begin
564y := y + dy;
565if y < yMax then
566begin
567iyCoord := CoordLogy(y);
568MoveTo(xMinCoord, iyCoord);
569LineTo(xMaxCoord, iyCoord);
570end;
571end;
572dy := dy/10;
573yCoord := CoordLogY(dy);
574end;
575y := dy;
576for i := 2 to 9 do
577begin
578y := y + dy;
579if y > yMin then
580begin
581iyCoord := CoordLogy(y);
582MoveTo(xMinCoord, iyCoord);
583LineTo(xMaxCoord, iyCoord);
584end;
585end;
586end;
587end;
588
589procedure TfxCanvas.DrawPolarGrid;
590var
591rMax, r, dr: extended;
592dx, dy: extended;
593
594const
595MaxR = $2000;
596dMax = $700;
597
598begin
599with GraphData do
600begin
601PenColor := GridColor;
602PenWidth := MinorWidth;
603rMax := 0;
604dx := xMax - xMin;
605dy := yMax - yMin;
606
607r := Hypot(xMin, yMin);
608if r > rMax then rMax := r;
609
610r := Hypot(xMin, yMax);
611if r > rMax then rMax := r;
612
613r := Hypot(xMax, yMax);
614if r > rMax then rMax := r;
615
616r := Hypot(xMax, yMin);
617if r > rMax then rMax := r;
618end;
619
620r := trunc(rMax/dx10Grad)*dx10Grad;
621dr := dxGrad;
622
623{ major X axis graduation lengths }
624while rMax/dr > GraphData.xMajorGrad do dr := dr*10;
625
626if (CoordX(abs(r)) < MaxR) and { r & canvas width/height ratio }
627(CoordY(abs(r)) < MaxR) and { are not too big }
628(dx/dy < dMax) and (dy/dx < dMax) then
629begin
630while r < rMax - 2*dr do r := r + dr;
631while r > 0 do
632begin
633EllipseBB(CoordX(-r),CoordY(-r),
634CoordX(r)+1,CoordY(r)-1);
635r := r - dr;
636end;
637end
638end;
639
640procedure TfxCanvas.DrawXAxisLinear;
641var
642halfWd: integer;
643xCoord, yCoord: integer; { holds screen coordinate location }
644xO: integer;
645x: extended;
646c: integer; { for graduation marks }
647dCoord: integer;
648atTop: Boolean;
649
650begin
651with GraphData do
652begin
653halfWd := AxisWidth div 2;
654yCoord := CoordY(0); { coordinate for x axis }
655xO := CoordX(0); { x origin, i.e. y axis }
656{ if GridStyle = gsPolar the xAxis may be off canvas
657otherwise it will be displayed at the top or bottom of canvas }
658if (Grid.GridStyle in [gsAxes, gsCartesian]) or
659((yCoord > 0) and (yCoord < CanvasSizeY + halfWd)) then
660begin { xAxis is within canvas height range }
661PenColor := xAxisColor;
662PenWidth := AxisWidth;
663atTop := yCoord < 2*CharH + AxisWidth;
664
665if atTop then yCoord := halfWd { top of canvas }
666else if yCoord > CanvasSizeY { bottom of canvas }
667then yCoord := CanvasSizeY - halfWd;
668
669MoveTo(0, yCoord);
670LineTo(CanvasSizeX, yCoord);
671
672PenWidth := halfWd;
673
674x := trunc(xMin/dx10Grad)*dx10Grad; { graduations for x axis }
675c := round((xMin - x)/dxGrad);
676x := x + c*dxGrad;
677
678if c < 0 then Inc(c, 10);
679dCoord := CoordX(x + dxGrad) - CoordX(x);
680
681while x < xMax do
682begin { calculate coordinate for each graduation }
683xCoord := CoordX(x);
684
685if atTop then MoveTo(xCoord, AxisWidth) else MoveTo(xCoord, yCoord);
686
687if c mod 5 = 0 then { larger mark for 5th graduation }
688begin
689if abs(xCoord - xO) > 2 then { is not y axis }
690begin
691if c mod 10 = 0 then
692begin
693if atTop then LineTo(xCoord, 16 + halfWd)
694else LineTo(xCoord, yCoord - 16 - halfWd);
695AddXAxisText(x, xCoord, yCoord, halfWd, atTop);
696end
697else
698begin
699if atTop then LineTo(xCoord, 11 + halfWd)
700else LineTo(xCoord, yCoord - 11 - halfWd);
701if (trunc(x) = x) and (dCoord >= 5*xMinorGrad)
702then AddXAxisText(x, xCoord, yCoord, halfWd, atTop);
703end;
704end; { is not y axis }
705end
706else
707begin
708if atTop then LineTo(xCoord, 7 + AxisWidth)
709else LineTo(xCoord, yCoord - 6 - halfWd);
710{ small graduation mark }
711if (trunc(x) = x) and (dCoord >= xMajorGrad)
712then AddXAxisText(x, xCoord, yCoord, halfWd, atTop);
713end;
714x := x + dxGrad;
715Inc(c);
716end; { while x < xMax do... }
717end
718end;
719end;
720
721procedure TfxCanvas.DrawYAxisLinear;
722var
723halfWd: integer;
724xCoord, yCoord: integer; { holds screen coordinate location }
725yO: integer;
726y: extended;
727c: integer; { for graduation marks }
728dCoord: integer;
729atRight: Boolean;
730
731begin
732with GraphData do
733begin
734halfWd := AxisWidth div 2;
735xCoord := CoordX(0); { coordinate for y axis }
736yO := CoordY(0); { y origin, i.e. x axis }
737{ if GridStyle = gsPolar the yAxis may be off canvas
738otherwise it will be displayed at the left or right of canvas }
739if (Grid.GridStyle in [gsAxes, gsCartesian]) or
740((xCoord > 0) and (xCoord < CanvasSizeX + halfWd)) then
741begin { yAxis is within canvas width range }
742PenColor := yAxisColor;
743PenWidth := AxisWidth;
744atRight := xCoord > CanvasSizeX - 6*CharW - halfWd;
745
746if atRight then xCoord := CanvasSizeX - halfWd { canvas right }
747else if xCoord < 0 then xCoord := halfWd; { canvas left }
748
749MoveTo(xCoord, 0);
750LineTo(xCoord, CanvasSizeY);
751
752PenWidth := halfWd;
753
754y := trunc(yMin/dy10Grad)*dy10Grad; { graduations for y axis }
755c := round((yMin - y)/dyGrad);
756y := y + c*dyGrad;
757
758if c < 0 then Inc(c, 10);
759dCoord := CoordY(y) - CoordY(y + dyGrad);
760
761while y < yMax do
762begin { calculate coordinate for each graduation }
763yCoord := CoordY(y);
764
765if atRight then MoveTo(CanvasSizeX - AxisWidth, yCoord)
766else MoveTo(xCoord, yCoord);
767
768if c mod 5 = 0 then { larger mark for 5th graduation }
769begin
770if abs(yCoord - yO) > 2 then { is not x axis }
771begin
772if c mod 10 = 0 then
773begin
774if atRight
775then LineTo(CanvasSizeX - 15 - halfWd, yCoord)
776else LineTo(xCoord + 15 + halfWd, yCoord);
777AddYAxisText(y, xCoord, yCoord, halfWd, atRight);
778end
779else
780begin
781if atRight
782then LineTo(CanvasSizeX - 10 - halfWd, yCoord)
783else LineTo(xCoord + 10 + halfWd, yCoord);
784if (trunc(y) = y) and (dCoord > 5*yMinorGrad)
785then AddYAxisText(y, xCoord, yCoord, halfWd, atRight);
786end;
787end; { is not x axis }
788end
789else
790begin
791if atRight
792then LineTo(CanvasSizeX - 7 - AxisWidth, yCoord)
793else LineTo(xCoord + 5 + halfWd, yCoord);
794{ small graduation mark }
795if (trunc(y) = y) and (dCoord >= yMajorGrad)
796then AddYAxisText(y, xCoord, yCoord, halfWd, atRight);
797end;
798y := y + dyGrad;
799Inc(c);
800end; { while y < yMax do... }
801end;
802end;
803end;
804
805procedure TfxCanvas.DrawXAxisLog;
806var
807xCoord, ixCoord, yCoord, halfWd, i: integer;
808x, dx: extended;
809s: string;
810atTop: Boolean;
811
812begin
813with GraphData do
814begin
815halfWd := AxisWidth div 2;
816
817if Grid.yAxisStyle = asLog then yCoord := CanvasSizeY
818else yCoord := CoordY(0); { coordinate for x axis if y axis not Log }
819
820{ if GridStyle = gsPolar and yAxis is not Log the xAxis may be off canvas
821otherwise it will be displayed at the top or bottom of the canvas }
822if (Grid.GridStyle in [gsAxes, gsCartesian]) or
823((yCoord > 0) and (yCoord < CanvasSizeY + halfWd)) then
824begin { xAxis is within canvas height range }
825PenColor := xAxisColor;
826PenWidth := AxisWidth;
827atTop := yCoord < 2*CharH + AxisWidth;
828
829if atTop then yCoord := halfWd { top of canvas }
830else if yCoord > CanvasSizeY { bottom of canvas }
831then yCoord := CanvasSizeY - halfWd;
832
833MoveTo(0, yCoord);
834LineTo(CanvasSizeX, yCoord);
835
836PenWidth := halfWd;
837dx := 10*dx10Grad;
838
839xCoord := CoordLogX(dx);
840while xCoord > 0 do
841begin
842MoveTo(xCoord, yCoord);
843if atTop then LineTo(xCoord, 15 + halfWd)
844else LineTo(xCoord, yCoord - 15 -HalfWd);
845x := dx;
846s := FormatValue(xDigits, x, dxGrad);
847if CoordLogX(x + 10*dx)-xCoord > Length(' '+s)*CharW then
848AddXAxisText(x, xCoord - CharW div 2, yCoord, halfWd, atTop);
849for i := 2 to 9 do
850begin
851x := x + dx;
852if x < xMax then
853begin
854ixCoord := CoordLogX(x);
855MoveTo(ixCoord, yCoord);
856if i = 5 then
857begin
858if atTop then LineTo(ixCoord, 11 + halfWd)
859else LineTo(ixCoord, yCoord - 11 -HalfWd);
860end
861else
862begin
863if atTop then LineTo(ixCoord, 7 + HalfWd)
864else LineTo(ixCoord, yCoord - 6 -HalfWd); { small graduation mark }
865end;
866s := FormatValue(xDigits, x, dxGrad);
867if CoordLogX(x + dx)-ixCoord > Length(' '+s)*CharW then
868AddXAxisText(x, ixCoord - CharW div 2, yCoord, halfWd, atTop);
869end;
870end;
871dx := dx/10;
872xCoord := CoordLogX(dx);
873end;
874
875x := dx;
876for i := 2 to 9 do
877begin
878x := x + dx;
879if x > xMin then
880begin
881ixCoord := CoordLogX(x);
882MoveTo(ixCoord, yCoord);
883if i = 5 then
884begin
885if atTop then LineTo(ixCoord, 11 + halfWd)
886else LineTo(ixCoord, yCoord - 11 -HalfWd);
887end
888else
889begin
890if atTop then LineTo(ixCoord, 7 + HalfWd)
891else LineTo(ixCoord, yCoord - 6 -HalfWd); { small graduation mark }
892end;
893s := FormatValue(xDigits, x, dxGrad);
894if CoordLogX(x + dx)-ixCoord > Length(' '+s)*CharW then
895AddXAxisText(x, ixCoord - CharW div 2, yCoord, halfWd, atTop);
896end;
897end;
898end;
899end;
900end;
901
902procedure TfxCanvas.DrawYAxisLog;
903var
904xCoord, yCoord, iyCoord, halfWd, i: integer;
905y, dy: extended;
906atRight: Boolean;
907
908begin
909with GraphData do
910begin
911halfWd := AxisWidth div 2;
912
913if Grid.xAxisStyle = asLog then xCoord := 0
914else xCoord := CoordX(0); { coordinate for y axis }
915
916{ if GridStyle = gsPolar and xAxis is not Log the yAxis may be off canvas
917otherwise it will be displayed at the left or right of the canvas }
918if (Grid.GridStyle in [gsAxes, gsCartesian]) or
919((xCoord > 0) and (xCoord < CanvasSizeX + halfWd)) then
920begin { yAxis is within canvas width range }
921PenColor := yAxisColor;
922PenWidth := AxisWidth;
923atRight := xCoord > CanvasSizeX - 6*CharW - halfWd;
924
925if atRight then xCoord := CanvasSizeX - halfWd { canvas right }
926else if xCoord < 0 then xCoord := halfWd; { canvas left }
927
928MoveTo(xCoord, 0);
929LineTo(xCoord, CanvasSizeY);
930
931PenWidth := halfWd;
932dy := 10*dy10Grad;
933yCoord := CoordLogY(dy);
934
935while yCoord < CanvasSizeY do
936begin
937MoveTo(xCoord, yCoord);
938if atRight then LineTo(CanvasSizeX - 15 - halfWd, yCoord)
939else LineTo(xCoord + 15 + halfWd, yCoord);
940y := dy;
941if 3*CharH div 2 < yCoord - CoordLogY(y + 10*dy) then
942AddYAxisText(y, xCoord - CharW div 2,
943yCoord + CharH div 3, halfWd, atRight);
944
945for i := 2 to 9 do
946begin
947y := y + dy;
948if y < yMax then
949begin
950iyCoord := CoordLogY(y);
951MoveTo(xCoord, iyCoord);
952if i = 5 then
953begin
954if atRight then LineTo(CanvasSizeX - 11 - halfWd, iyCoord)
955else LineTo(xCoord + 11 + halfWd, iyCoord);
956end
957else
958begin
959if atRight then LineTo(CanvasSizeX - 7 - halfWd, iyCoord)
960else LineTo(xCoord + 6 + halfWd, iyCoord); { small graduation mark }
961end;
962if 3*CharH div 2 < iyCoord - CoordLogY(y + dy) then
963AddYAxisText(y, xCoord - CharW div 2,
964iyCoord + CharH div 3, halfWd, atRight);
965end;
966end;
967
968dy := dy/10;
969yCoord := CoordLogY(dy);
970end;
971
972y := dy;
973for i := 2 to 9 do
974begin
975y := y + dy;
976if y > yMin then
977begin
978iyCoord := CoordLogY(y);
979MoveTo(xCoord, iyCoord);
980if i = 5 then
981begin
982if atRight then LineTo(CanvasSizeX - 11 - halfWd, iyCoord)
983else LineTo(xCoord + 11 + halfWd, iyCoord);
984end
985else
986begin
987if atRight then LineTo(CanvasSizeX - 7 - halfWd, iyCoord)
988else LineTo(xCoord + 6 + halfWd, iyCoord); { small graduation mark }
989end;
990if 3*CharH div 2 < iyCoord - CoordLogY(y + dy) then
991AddYAxisText(y, xCoord - CharW div 2,
992iyCoord + CharH div 3, halfWd, atRight);
993end;
994end;
995end;
996end;
997end;
998
999procedure TfxCanvas.PlotFunction(Selected: Boolean);
1000var
1001LabelStr: string;
1002
1003function GetStringWidth(const s: string): integer;
1004var
1005i : integer;
1006
1007begin { GetStringWidth }
1008Result := 0;
1009for i := 1 to Length(s)
1010do Result := Result + MainForm.GLWinBitFont.GetCharWidth(Char(s[i])) +1;
1011end; { GetStringWidth }
1012
1013begin
1014with GraphData, PlotData, FxParser do
1015begin
1016if PlotAsFx then LabelStr := 'y = ' + TextStr
1017else LabelStr := 'r = ' + TextStr;
1018
1019PenColor := PlotColor;
1020if ShowLabel and (ErrorByte = 0) and
1021(PlotData.xLabel > xMin) and (PlotData.xLabel < xMax) and
1022(PlotData.yLabel > yMin) and (PlotData.yLabel < yMax) then
1023begin { display the label rectangle }
1024if Selected and (BitmapForm = nil) and (PrintForm = nil) then
1025begin { display a rectangle around the label }
1026PenWidth := 1;
1027
1028with LabelRect do
1029begin
1030Right := GetStringWidth(LabelStr+' ');
1031Bottom := round(4*MainForm.GLWinBitFont.CharHeight/3);
1032
1033if Grid.xAxisStyle = asLog
1034then Left := CoordLogX(xLabel) -
10352*MainForm.GLWinBitFont.GetCharWidth(' ')
1036else Left := CoordX(xLabel) -
10372*MainForm.GLWinBitFont.GetCharWidth(' ');
1038
1039if Grid.yAxisStyle = asLog
1040then Top := CoordLogY(yLabel) -
1041round(MainForm.GLWinBitFont.CharHeight/8)
1042else Top := CoordY(yLabel) -
1043round(MainForm.GLWinBitFont.CharHeight/8);
1044
1045Right := Left + Right;
1046Bottom := Top + Bottom;
1047RoundRect(Left, Top, Right, Bottom, 9, 9);
1048end;
1049end; { if Selected... then... }
1050end; { if ShowLabel then... }
1051
1052PenWidth := PlotWidth;
1053
1054if (ErrorByte = 0) and Assigned(Calculus) then
1055begin
1056if PlotAsFx
1057then PlotAsCartesian(Selected)
1058else PlotAsPolar(Selected);
1059end;
1060end;
1061end;
1062
1063procedure TfxCanvas.PlotAsCartesian(Selected: Boolean);
1064begin
1065{ evaluate y for each x & calculate plot point }
1066if GraphData.Grid.xAxisStyle = asLog then
1067begin
1068if GraphData.Grid.yAxisStyle = asLog
1069then PopulateCartesianLogXY(PlotList)
1070else PopulateCartesianLogX(PlotList);
1071end
1072else
1073if GraphData.Grid.yAxisStyle = asLog
1074then PopulateCartesianLogY(PlotList)
1075else PopulateCartesian(PlotList);
1076
1077AnalyseCartesian(PlotList); { determine which lines are to be drawn }
1078
1079if Selected then with FunctionsForm do
1080begin
1081if Integrate2x.Checked then IntegrateCartesian else
1082if Integrate2y.Checked then IntegrateYCartesian else
1083if Between1.Checked then IntegrateBetweenFunctions else
1084if VolumeX1.Checked then IntegrateVolumeX;
1085if VolumeY1.Checked then IntegrateVolumeY;
1086if fxValueForm.Visible and fxValueForm.DisplayOK
1087then FindfxValues(fxValueForm.fxValueToFind);
1088if fx1ValueForm.Visible and fx1ValueForm.DisplayOK
1089then Findfx1Values(fx1ValueForm.fx1ValueToFind);
1090if fx2ValueForm.Visible and fx2ValueForm.DisplayOK
1091then Findfx2Values(fx2ValueForm.fx2ValueToFind);
1092end;
1093{ next line hides the function used for the integrate volume }
1094if not (Selected and
1095(VolumeXForm.HideFunctionCheckBox.Checked or
1096VolumeYForm.HideFunctionCheckBox.Checked)) then
1097DrawCartesian(PlotList); { draw the graph }
1098
1099if Selected then with FunctionsForm do
1100begin
1101if yfx1.Checked then { dy/dx }
1102begin
1103yfx1List := TList.Create;
1104try
1105PopulateDerivCartesian(PlotList, yfx1List);
1106AnalyseDerivCartesian(yfx1List);
1107Draw_yfx1(yfx1List);
1108if yfx2.Checked then {d2y/dx2 }
1109begin
1110yfx2List := TList.Create;
1111try
1112PopulateDerivCartesian(yfx1List, yfx2List);
1113AnalyseDerivCartesian(yfx2List);
1114Draw_yfx2(yfx2List);
1115finally
1116ClearPointList(yfx2List);
1117end;
1118end;
1119finally
1120ClearPointList(yfx1List);
1121end;
1122end;
1123
1124if EvaluateButton.Tag = 1 then
1125begin
1126yEvaluate := EvaluateFunction(xEvaluate);
1127ShowCartesianEvaluate;
1128DrawCartesianCoordinates;
1129end;
1130end;
1131if FunctionsForm.fxValue.Checked then DrawfxPoints;
1132if FunctionsForm.fx1Value.Checked then Drawfx1Points;
1133if FunctionsForm.fx2Value.Checked then Drawfx2Points;
1134end;
1135
1136procedure TfxCanvas.PlotAsPolar(Selected: Boolean);
1137begin
1138PopulatePolar(PlotList); { evaluate r for each phi & calculate plot point }
1139AnalysePolar(PlotList); { determine which lines are to be drawn }
1140
1141if FunctionsForm.Integrate2x.Checked and Selected then IntegratePolar;
1142
1143DrawPolar(PlotList); { draw the graph }
1144
1145if Selected then with FunctionsForm do
1146begin
1147if yfx1.Checked then
1148begin
1149yfx1List := TList.Create;
1150try
1151PopulateDerivPolar(PlotList, yfx1List);
1152AnalysePolar(yfx1List);
1153Draw_yfx1(yfx1List);
1154if yfx2.Checked then
1155begin
1156yfx2List := TList.Create;
1157try
1158PopulateDerivPolar(yfx1List, yfx2List);
1159AnalysePolar(yfx2List);
1160Draw_yfx2(yfx2List);
1161finally
1162ClearPointList(yfx2List);
1163end;
1164end;
1165finally
1166ClearPointList(yfx1List);
1167end;
1168end;
1169
1170if EvaluateButton.Tag = 1 then
1171begin
1172yEvaluate := EvaluateFunction(xEvaluate);
1173ShowPolarEvaluate;
1174DrawPolarCoordinates;
1175end;
1176end;
1177end;
1178
1179procedure TfxCanvas.PopulateCartesian(var L: TList);
1180var
1181i, n: integer;
1182vx, vy: extended;
1183
1184begin
1185n := round(GraphData.PlotData.xInc); { xInc may have decimals }
1186if n < 1 then n := 1; { each pixel }
1187
1188i := 0;
1189
1190while i <= CanvasSizeX do
1191begin
1192vx := ValueX(i);
1193try
1194vy := EvaluateFunction(vx);
1195except
1196vy := NaN;
1197end;
1198
1199L.Add(TGraphPointObject.Create(vx, vy));
1200with TGraphPointObject(L[L.Count -1]) do
1201begin
1202PlotPoint.X := CoordX(vx);
1203PlotPoint.Y := CoordY(vy);
1204DrawLine := false; { set all false initially }
1205end;
1206Inc(i, n);
1207end; { while i <= CanvasSizeX do... }
1208end;
1209
1210procedure TfxCanvas.PopulateCartesianLogX(var L: TList);
1211var
1212i, n: integer;
1213vx, vy: extended;
1214
1215begin
1216i := 0;
1217n := round(GraphData.PlotData.xInc);
1218if n < 1 then n := 1; { plot all points for each pixel }
1219
1220while i <= CanvasSizeX + n do
1221begin
1222vx := ValueLogX(i);
1223try
1224vy := EvaluateFunction(vx);
1225except
1226vy := NaN;
1227end;
1228
1229L.Add(TGraphPointObject.Create(vx, vy));
1230
1231with TGraphPointObject(L[L.Count -1]) do
1232begin
1233PlotPoint.X := CoordLogX(vx);
1234PlotPoint.Y := CoordY(vy);
1235DrawLine := false; { set all false initially }
1236end;
1237Inc(i, n);
1238end;
1239end;
1240
1241procedure TfxCanvas.PopulateCartesianLogY(var L: TList);
1242var
1243i, n: integer;
1244vx, vy: extended;
1245
1246begin
1247i := 0;
1248n := round(GraphData.PlotData.xInc);
1249if n < 1 then n := 1; { plot all points for each pixel }
1250
1251while i <= CanvasSizeX + n do
1252begin
1253vx := ValueX(i);
1254try
1255vy := EvaluateFunction(vx);
1256except
1257vy := NaN;
1258end;
1259
1260L.Add(TGraphPointObject.Create(vx, vy));
1261
1262with TGraphPointObject(L[L.Count -1]) do
1263begin
1264PlotPoint.X := CoordX(vx);
1265with GraphData do
1266begin
1267if vy < yMin then PlotPoint.Y := CoordLogY(yMin) + 2 else
1268if vy > yMax then PlotPoint.Y := CoordLogY(yMax) - 2
1269else PlotPoint.Y := CoordLogY(vy);
1270end;
1271DrawLine := false; { set all false initially }
1272end;
1273Inc(i, n);
1274end;
1275end;
1276
1277procedure TfxCanvas.PopulateCartesianLogXY(var L: TList);
1278var
1279i, n: integer;
1280vx, vy: extended;
1281
1282begin
1283i := 0;
1284n := round(GraphData.PlotData.xInc);
1285if n < 1 then n := 1; { plot all points for each pixel }
1286
1287while i <= CanvasSizeX + n do
1288begin
1289vx := ValueLogX(i);
1290try
1291vy := EvaluateFunction(vx);
1292except
1293vy := NaN;
1294end;
1295
1296L.Add(TGraphPointObject.Create(vx, vy));
1297
1298with TGraphPointObject(L[L.Count -1]) do
1299begin
1300PlotPoint.X := CoordLogX(vx);
1301with GraphData do
1302begin
1303if vy < yMin then PlotPoint.Y := CoordLogY(yMin) + 2 else
1304if vy > yMax then PlotPoint.Y := CoordLogY(yMax) - 2
1305else PlotPoint.Y := CoordLogY(vy);
1306end;
1307DrawLine := false; { set all false initially }
1308end;
1309Inc(i, n);
1310end;
1311end;
1312
1313procedure TfxCanvas.PopulatePolar(var L: TList);
1314var
1315vPhi, vr: extended;
1316
1317begin
1318with GraphData, PlotData do
1319begin
1320vPhi := SegMin;
1321
1322while vPhi <= SegMax + PhiInc do
1323begin
1324try
1325vr := EvaluateFunction(vPhi);
1326except
1327vr := NaN;
1328end;
1329
1330L.Add(TGraphPointObject.Create(vPhi, vr));
1331
1332with TGraphPointObject(L[L.Count -1]) do
1333begin
1334PlotPoint.X := CoordX(vr*Cos(vPhi));
1335PlotPoint.Y := CoordY(vr*Sin(vPhi));
1336DrawLine := false; { set all false initially }
1337end;
1338vPhi := vPhi + PhiInc; { next step }
1339end;
1340end;
1341end;
1342
1343procedure TfxCanvas.PopulateDerivCartesian(var Ls: TList; var L: TList);
1344var
1345i: integer;
1346p1, p2, p: TGraphPoint;
1347m: extended;
1348
1349begin
1350for i := 1 to Ls.Count -2 do
1351begin
1352with TGraphPointObject(Ls[i -1]) do
1353begin
1354p1.x := x_phi;
1355p1.y := y_r;
1356end;
1357
1358with TGraphPointObject(Ls[i]) do
1359begin
1360p.x := x_phi;
1361p.y := y_r;
1362end;
1363
1364with TGraphPointObject(Ls[i +1]) do
1365begin
1366p2.x := x_phi;
1367p2.y := y_r;
1368end;
1369
1370m := (p2.y - p1.y)/(p2.x - p1.x);
1371L.Add(TGraphPointObject.Create(p.x, m));
1372
1373with TGraphPointObject(L[L.Count -1]) do
1374begin
1375with GraphData, Grid do
1376begin
1377if xAxisStyle = asLog
1378then PlotPoint.X := CoordLogX(x_phi)
1379else PlotPoint.X := CoordX(x_phi);
1380
1381if yAxisStyle = asLog then
1382begin
1383if y_r < yMin then PlotPoint.Y := CoordLogY(yMin) + 2 else
1384if y_r > yMax then PlotPoint.Y := CoordLogY(yMax) - 2
1385else PlotPoint.Y := CoordLogY(y_r);
1386end
1387else PlotPoint.Y := CoordY(y_r);
1388end;
1389DrawLine := false;
1390end;
1391end;
1392end;
1393
1394procedure TfxCanvas.PopulateDerivPolar(var Ls: TList; var L: TList);
1395var
1396i: integer;
1397p1, p2, p: TGraphPoint;
1398m: extended;
1399
1400begin
1401for i := 1 to Ls.Count -2 do
1402begin
1403with TGraphPointObject(Ls[i -1]) do
1404begin
1405p1.x := x_phi;
1406p1.y := y_r;
1407end;
1408
1409with TGraphPointObject(Ls[i]) do
1410begin
1411p.x := x_phi;
1412p.y := y_r;
1413end;
1414
1415with TGraphPointObject(Ls[i +1]) do
1416begin
1417p2.x := x_phi;
1418p2.y := y_r;
1419end;
1420
1421m := (p2.y - p1.y)/(p2.x - p1.x);
1422L.Add(TGraphPointObject.Create(p.x, m));
1423
1424with TGraphPointObject(L[L.Count -1]) do
1425begin
1426PlotPoint.X := CoordX(y_r*Cos(x_phi));
1427PlotPoint.Y := CoordY(y_r*Sin(x_phi));
1428DrawLine := false;
1429end;
1430end;
1431end;
1432
1433procedure TfxCanvas.NoNumberCartesian(var L: TList; const P, C: TGraphPoint;
1434const i: integer);
1435{ ChecknoNumber checks prior and current graph values for validity.
1436If not valid then prior point is adjusted to a more accurate X, Y values }
1437const
1438dpMin = 1e-9;
1439
1440function StartPoint(const n: integer): extended;
1441var
1442vx, vy, dx, dp: extended;
1443
1444begin
1445Result := NaN;
1446with TGraphPointObject(L[n]) do
1447begin
1448if GraphData.Grid.xAxisStyle = asLog
1449then vx := ValueLogX(PlotPoint.X -1)
1450else vx := ValueX(PlotPoint.X -1);
1451dx := (vx - x_phi);
1452dp := 1; { one pixel }
1453while dp > dpMin do
1454begin
1455vy := EvaluateFunction(vx);
1456if isNaN(vy) then vx := vx - dx
1457else
1458begin
1459Result := vx;
1460vx := vx + dx;
1461end;
1462dx := dx/2;
1463dp := dp/2;
1464end;
1465end;
1466end;
1467
1468function StopPoint(const n: integer): extended;
1469var
1470vx, vy, dx, dp: extended;
1471
1472begin
1473Result := NaN;
1474with TGraphPointObject(L[n]) do
1475begin
1476if GraphData.Grid.xAxisStyle = asLog
1477then vx := ValueLogX(PlotPoint.X -1)
1478else vx := ValueX(PlotPoint.X -1);
1479dx := (x_phi - vx);
1480dp := 1; { one pixel }
1481while dp > dpMin do
1482begin
1483vy := EvaluateFunction(vx);
1484if isNaN(vy) then vx := vx - dx
1485else
1486begin
1487Result := vx;
1488vx := vx + dx;
1489end;
1490dx := dx/2;
1491dp := dp/2;
1492end;
1493end;
1494end;
1495
1496var
1497sy: extended;
1498b: Boolean;
1499
1500begin
1501if isNaN(P.y) and not isNaN(C.y) then
1502begin
1503sy := EvaluateFunction(StartPoint(i));
1504with TGraphPointObject(L[i - 1]) do PlotPoint.Y := CoordY(sy);
1505Exit;
1506end;
1507{ in some cases this is needed to trigger the next option }
1508b := (i + 2 < L.Count) and isNaN(TGraphPointObject(L[i + 2]).y_r);
1509if not isNaN(P.y) and isNaN(C.y) and b then
1510begin
1511sy := EvaluateFunction(StopPoint(i + 1));
1512with TGraphPointObject(L[i + 1]).PlotPoint do Y := CoordY(sy);
1513end;
1514end;
1515
1516procedure TfxCanvas.NoNumberDerivCartesian(var L: TList; const P, C: TGraphPoint;
1517const i: integer);
1518{ ChecknoNumber checks prior and current graph values for validity.
1519If not valid then prior point is adjusted to a more accurate X, Y values }
1520var
1521delta: integer;
1522
1523begin
1524try
1525if isNaN(P.y) and not isNaN(C.y) then
1526begin
1527with TGraphPointObject(L[i +1])
1528do delta := C.PlotPoint.Y - PlotPoint.Y;
1529with TGraphPointObject(L[i -1]).PlotPoint do
1530begin
1531X := C.PlotPoint.X;
1532Y := C.PlotPoint.Y + delta;
1533end;
1534Exit;
1535end;
1536
1537if not isNaN(P.y) and isNaN(C.y) then
1538begin
1539with TGraphPointObject(L[i -2])
1540do delta := P.PlotPoint.Y - PlotPoint.Y;
1541with TGraphPointObject(L[i -1]).PlotPoint do
1542begin
1543X := C.PlotPoint.X;
1544Y := P.PlotPoint.Y + delta;
1545end;
1546end;
1547except
1548end;
1549end;
1550
1551procedure TfxCanvas.NoNumberPolar(var L: TList; var P, C: TGraphPoint;
1552const i: Integer);
1553begin
1554if isNaN(P.y) and not isNaN(C.y) then
1555begin
1556with TGraphPointObject(L[i - 1]).PlotPoint do
1557begin
1558X := C.PlotPoint.X;
1559Y := C.PlotPoint.Y;
1560end;
1561end;
1562if not isNaN(P.y) and isNaN(C.y) then
1563begin
1564with TGraphPointObject(L[i]).PlotPoint do
1565begin
1566X := P.PlotPoint.X;
1567Y := P.PlotPoint.Y;
1568end;
1569end;
1570end;
1571
1572procedure TfxCanvas.InfinityCartesian(var L: Tlist; var P, C: TGraphPoint;
1573const i: integer);
1574{ CheckInfinity checks prior and current graph values for infinity.
1575If one is and the other is not then the y value of the prior plot point
1576needs to be adjusted either to the top or bottom of the viewer. }
1577begin
1578if isInfinite(P.y) and not isInfinite(C.y)
1579then with TGraphPointObject(L[i -1]).PlotPoint do
1580begin
1581case Sign(P.y) of
1582-1:Y := CanvasSizeY; { -INF: bottom }
15830:Y := C.PlotPoint.Y; { may never happen }
15841:Y := 0; { +INF: top }
1585end;
1586end;
1587
1588if not isInfinite(P.y) and isInfinite(C.y)
1589then with TGraphPointObject(L[i -1]).PlotPoint do
1590begin
1591case Sign(C.y) of
1592-1:Y := CanvasSizeY; { -INF: bottom }
15930:Y := C.PlotPoint.Y; { may never happen }
15941:Y := 0; { +INF: top }
1595end;
1596end;
1597end;
1598
1599procedure TfxCanvas.InfinityPolar(var L: Tlist; var P, C: TGraphPoint;
1600const i: integer);
1601begin
1602{ CheckInfinity checks prior and current graph values for infinity.
1603If one is and the other is not then the y value of the prior
1604plot point needs to be adjusted. }
1605if isInfinite(P.y) and not isInfinite(C.y) then
1606begin
1607with TGraphPointObject(L[i -1]).PlotPoint do
1608begin
1609X := C.PlotPoint.X;
1610Y := C.PlotPoint.Y;
1611end;
1612end;
1613
1614if not isInfinite(P.y) and isInfinite(C.y) then
1615begin
1616with TGraphPointObject(L[i]).PlotPoint do
1617begin
1618X := P.PlotPoint.X;
1619Y := P.PlotPoint.Y;
1620end;
1621end;
1622end;
1623
1624function TfxCanvas.LineIsValid(var P, C: TGraphPoint): Boolean;
1625begin
1626{ if the line is not valid it will not be drawn }
1627if not GraphData.PlotData.IsContinuous then
1628begin
1629if isNaN(C.y) or IsInfinite(C.y) then
1630begin
1631Result := false;
1632Exit;
1633end;
1634
1635if (C.PlotPoint.Y <= 0) and (P.PlotPoint.Y >= CanvasSizeY) or
1636(P.PlotPoint.Y <= 0) and (C.PlotPoint.Y >= CanvasSizeY) then
1637begin
1638Result := false;
1639Exit;
1640end;
1641end;
1642Result := true;
1643end;
1644
1645procedure TfxCanvas.AnalyseCartesian(var L: TList);
1646var
1647i: integer;
1648Prior, Current: TGraphPoint;
1649
1650begin
1651i := 0;
1652
1653with TGraphPointObject(L[i]) do
1654begin
1655Prior.PlotPoint := PlotPoint;
1656Prior.x := x_phi;
1657Prior.y := y_r;
1658end;
1659
1660Inc(i); { start from L[1]; first point is a MoveTo not a LineTo
1661i.e. DrawLine is false }
1662while i < L.Count do
1663begin { integer plot points; down is greater }
1664with TGraphPointObject(L[i]) do
1665begin
1666Current.PlotPoint := PlotPoint;
1667Current.x := x_phi;
1668Current.y := y_r;
1669
1670if GraphData.PlotData.IsSegment then
1671begin { plot only segment }
1672with GraphData.PlotData do
1673if (x_phi >= SegMin) and (x_phi <= SegMax) then
1674begin
1675NoNumberCartesian(L, Prior, Current, i);
1676InfinityCartesian(L, Prior, Current, i);
1677DrawLine := LineIsValid(Prior, Current);
1678end;
1679end
1680else
1681begin { complete plot }
1682NoNumberCartesian(L, Prior, Current, i);
1683InfinityCartesian(L, Prior, Current, i);
1684DrawLine := LineIsValid(Prior, Current);
1685end;
1686end; { with TGraphPointObject(L[i]) do... }
1687
1688Prior := Current; { update Prior }
1689Inc(i); { next step }
1690end; { while i < L.Count do... }
1691end;
1692
1693procedure TfxCanvas.AnalyseDerivCartesian(var L: TList);
1694var
1695i: integer;
1696Prior, Current: TGraphPoint;
1697
1698begin
1699i := 0;
1700
1701with TGraphPointObject(L[i]) do
1702begin
1703Prior.PlotPoint := PlotPoint;
1704Prior.x := x_phi;
1705Prior.y := y_r;
1706end;
1707
1708Inc(i); { start from L[1]; first point is a MoveTo not a LineTo
1709i.e. DrawLine is false }
1710while i < L.Count do
1711begin { integer plot points; down is greater }
1712with TGraphPointObject(L[i]) do
1713begin
1714Current.PlotPoint := PlotPoint;
1715Current.x := x_phi;
1716Current.y := y_r;
1717if GraphData.PlotData.IsSegment then
1718begin { plot only segment }
1719with GraphData.PlotData do
1720if (x_phi >= SegMin) and (x_phi <= SegMax) then
1721begin
1722NoNumberDerivCartesian(L, Prior, Current, i);
1723InfinityCartesian(L, Prior, Current, i);
1724DrawLine := LineIsValid(Prior, Current);
1725end;
1726end
1727else
1728begin { complete plot }
1729NoNumberDerivCartesian(L, Prior, Current, i);
1730InfinityCartesian(L, Prior, Current, i);
1731DrawLine := LineIsValid(Prior, Current);
1732end;
1733end; { with TGraphPointObject(L[i]) do... }
1734
1735Prior := Current; { update Prior }
1736Inc(i); { next step }
1737end; { while i < L.Count do... }
1738end;
1739
1740procedure TfxCanvas.AnalysePolar(var L: TList);
1741var
1742idx: integer;
1743Prior, Current: TGraphPoint;
1744
1745begin
1746idx := 0;
1747
1748with TGraphPointObject(L[idx]) do
1749begin
1750Prior.PlotPoint := PlotPoint;
1751Prior.x := x_phi;
1752Prior.y := y_r;
1753end;
1754
1755Inc(idx);
1756
1757while idx < L.Count do
1758begin
1759with TGraphPointObject(L[idx]) do
1760begin
1761Current.PlotPoint := PlotPoint;
1762Current.x := x_phi;
1763Current.y := y_r;
1764
1765NoNumberPolar(L, Prior, Current, idx);
1766InfinityPolar(L, Prior, Current, idx);
1767DrawLine := LineIsValid(Prior, Current);
1768end;
1769Prior := Current; { update Prior }
1770Inc(idx); { next step }
1771end; { while i < L.Count do... }
1772end;
1773
1774procedure TfxCanvas.DrawCartesian(var L: TList);
1775var
1776i: integer;
1777x0: integer;
1778
1779begin
1780with GraphData, PlotData do
1781begin
1782PenWidth := PlotWidth;
1783PenColor := PlotColor;
1784x0 := MaxInt;
1785end;
1786
1787for i := 0 to L.Count -1 do
1788with TGraphPointObject(L[i]) do
1789begin
1790if x0 <> PlotPoint.X then
1791if DrawLine then LineTo(PlotPoint.X, PlotPoint.Y)
1792else MoveTo(PlotPoint.X, PlotPoint.Y);
1793x0 := PlotPoint.X;
1794end;
1795end;
1796
1797procedure TfxCanvas.DrawPolar(var L: TList);
1798var
1799i: integer;
1800
1801begin
1802with GraphData, PlotData do
1803begin
1804PenWidth := PlotWidth;
1805PenColor := PlotColor;
1806end;
1807
1808for i := 0 to L.Count -1 do
1809with TGraphPointObject(L[i]) do
1810if DrawLine then LineTo(PlotPoint.X, PlotPoint.Y)
1811else MoveTo(PlotPoint.X, PlotPoint.Y);
1812end;
1813
1814procedure TfxCanvas.Draw_yfx1(var L: TList);
1815var
1816i: integer;
1817x0: integer;
1818
1819begin
1820PenWidth := GraphData.dydxWidth;
1821PenColor := GraphData.dydxColor;
1822x0 := MaxInt;
1823
1824for i := 0 to L.Count -1 do
1825with TGraphPointObject(L[i]) do
1826begin
1827if x0 <> PlotPoint.X then
1828if DrawLine then LineTo(PlotPoint.X, PlotPoint.Y)
1829else MoveTo(PlotPoint.X, PlotPoint.Y);
1830x0 := PlotPoint.X;
1831end;
1832end;
1833
1834procedure TfxCanvas.Draw_yfx2(var L: TList);
1835var
1836i: integer;
1837x0: integer;
1838
1839begin
1840PenWidth := GraphData.d2ydx2Width;
1841PenColor := GraphData.d2ydx2Color;
1842x0 := MaxInt;
1843
1844for i := 0 to L.Count -1 do
1845with TGraphPointObject(L[i]) do
1846begin
1847if x0 <> PlotPoint.X then
1848if DrawLine then LineTo(PlotPoint.X, PlotPoint.Y)
1849else MoveTo(PlotPoint.X, PlotPoint.Y);
1850x0 := PlotPoint.X;
1851end;
1852end;
1853
1854procedure TfxCanvas.IntegrateCartesian;
1855
1856procedure SetupIntegral;
1857var
1858i: integer;
1859
1860begin { SetupIntegral }
1861if Assigned(IntegList) then
1862for i := 0 to IntegList.Count -1 do
1863with TGraphPointObject(IntegList[i]) do
1864begin
1865PlotPoint.X := CoordX(x_phi);
1866PlotPoint.Y := CoordY(y_r);
1867if i = 0 then DrawLine := false;
1868end;
1869end; { SetupIntegral }
1870
1871procedure ShadeArea;
1872var
1873i: integer;
1874yCoord: integer;
1875
1876procedure DrawShading;
1877var
1878yValue: extended;
1879x, y: integer;
1880
1881begin
1882with TGraphPointObject(IntegList[i]) do
1883begin
1884x := PlotPoint.X;
1885yValue := EvaluateFunction(x_phi);
1886
1887PenWidth := 1;
1888PenAlpha := GraphData.AreaAlpha;
1889y := CoordY(yValue);
1890
1891if yValue < 0
1892then PenColor := GraphData.NegAreaColor
1893else PenColor := GraphData.PosAreaColor;
1894
1895Line(x, yCoord, x, y);
1896PenAlpha := 1;
1897end;
1898end;
1899
1900begin { ShadeArea }
1901yCoord := CoordY(0);
1902for i := 0 to IntegList.Count -1 do
1903with TGraphPointObject(IntegList[i]) do
1904if DrawLine then DrawShading;
1905end; { ShadeArea }
1906
1907procedure DrawIntegral;
1908var
1909i: integer;
1910
1911begin { DrawIntegral }
1912PenColor := GraphData.ydxColor;
1913PenWidth := GraphData.ydxWidth;
1914for i := 0 to IntegList.Count -1 do
1915with TGraphPointObject(IntegList[i]) do
1916if DrawLine
1917then LineTo(PlotPoint.X, PlotPoint.Y)
1918else MoveTo(PlotPoint.X, PlotPoint.Y);
1919end; { DrawIntegral }
1920
1921{ TfxCanvas.IntegrateCartesian }
1922var
1923SumSegs: extended;
1924NegSegs: extended;
1925PosSegs: extended;
1926
1927begin
1928IntegList := TList.Create;
1929try
1930NegSegs := 0;
1931PosSegs := 0;
1932SumSegs := SumSegments(NegSegs, PosSegs); { Cartesian }
1933
1934with IntegrateXForm do
1935begin
1936if IntegCheckBox.Checked then { Plot Integral selected }
1937begin
1938MinIntegXLabel.Caption := 'Minimum: x = '+
1939FloatToStrF(IntegXMin, ffGeneral, 12, 8);
1940MinIntegYLabel.Caption := 'Minimum: y = '+
1941FloatToStrF(IntegYMin, ffGeneral, 12, 8);
1942
1943MaxIntegXLabel.Caption := 'Maximum: x = '+
1944FloatToStrF(IntegXMax, ffGeneral, 12, 8);
1945MaxIntegYLabel.Caption := 'Maximum: y = '+
1946FloatToStrF(IntegYMax, ffGeneral, 12, 8);
1947end;
1948AreaLabel.Caption := 'Integral P[a, b] = '+
1949FloatToStrF(SumSegs, ffGeneral, 12, 8);
1950
1951NegAreaLabel.Caption := '"Negative" Area = '+
1952FloatToStrF(-NegSegs, ffGeneral, 12, 8);
1953
1954PosAreaLabel.Caption := '"Positive" Area = '+
1955FloatToStrF(PosSegs, ffGeneral, 12, 8);
1956
1957TotalAreaLabel.Caption := 'Total Area = '+
1958FloatToStrF(PosSegs - NegSegs, ffGeneral, 12, 8);
1959
1960SumAreaLabel.Caption := 'Sum Area = '+
1961FloatToStrF(SumSegs, ffGeneral, 12, 8);
1962end;
1963
1964if IntegList.Count > 0 then
1965begin
1966SetupIntegral;
1967if IntegrateXForm.PlotIntegrated and piArea = piArea then ShadeArea;
1968if IntegrateXForm.PlotIntegrated and piShow = piShow then DrawIntegral;
1969end;
1970finally
1971ClearPointList(IntegList);
1972IntegList := nil;
1973end;
1974end; { TfxCanvas.IntegrateCartesian }
1975
1976procedure TfxCanvas.IntegratePolar;
1977function SumSectors(var aNeg, aPos: extended): extended;
1978var
1979a: extended; { area }
1980h: extended; { step }
1981phi, phi1, phi2: extended;
1982i: integer;
1983r, r1, r2: extended;
1984m: extended;
1985xCoord: integer;
1986yCoord: integer;
1987LastXCoord: integer;
1988LastYCoord: integer;
1989
1990begin { SumSectors }
1991if KeepRange then
1992begin
1993IntegMin := KeptMin;
1994IntegMax := KeptMax;
1995end
1996else with GraphData, PlotData do
1997begin
1998if IsSegment then
1999begin
2000IntegMin := SegMin;
2001IntegMax := SegMax;
2002end
2003else if PlotAsFx then
2004begin
2005IntegMin := xMin;
2006IntegMax := xMax;
2007end;
2008end;
2009
2010if IntegMax = IntegMin then
2011begin
2012Result := 0;
2013Exit;
2014end;
2015
2016if IntegMax < IntegMin then
2017begin
2018a := IntegMax;
2019IntegMax := IntegMin;
2020IntegMin := a;
2021with IntegrateXForm do
2022begin
2023EditIntegMin.Text := FloatToStrF(IntegMin, ffGeneral, 13, 4);
2024EditIntegMax.Text := FloatToStrF(IntegMax, ffGeneral, 13, 4);
2025end;
2026end;
2027LastXCoord := MaxInt;
2028LastYCoord := MaxInt;
2029
2030h := (IntegMax - IntegMin)/GraphData.IntegCount; { calculate step }
2031a := 0; { initial area = 0 }
2032
2033{ calculate numerical value to be used to display area }
2034phi1 := IntegMin;
2035phi2 := phi1 + h; { h = d� }
2036
2037for i := 1 to GraphData.IntegCount do
2038begin { calculate area using a = 0.5*r(mean)^2*d� }
2039phi := (phi1 + phi2)/2; { mean phi }
2040
2041r1 := EvaluateFunction(phi1); { r1 = f(�1) }
2042r2 := EvaluateFunction(phi2); { r2 = f(�2) }
2043r := (r1 + r2)/2; { mean r }
2044
2045if not isNaN(r) then
2046begin
2047m := h*sqr(r)/2; { area of sector }
2048a := a + m; { add to total area }
2049
2050xCoord := CoordX(r*Cos(Phi));
2051yCoord := CoordY(r*Sin(phi));
2052
2053if (LastXCoord <> xCoord) or (LastYCoord <> yCoord)
2054then SectorList.Add(TGraphPointObject.Create(phi, r));
2055
2056LastXCoord := xCoord;
2057LastYCoord := yCoord;
2058
2059if r < 0 then aNeg := aNeg + m else aPos := aPos + m;
2060end;
2061
2062phi1 := phi2; { step }
2063phi2 := phi2 + h;
2064end;
2065Result := aPos - aNeg;
2066end; { SumSectors }
2067
2068procedure SetupIntegral;
2069var
2070i: integer;
2071
2072begin { SetupIntegral }
2073if Assigned(IntegList) then
2074for i := 0 to IntegList.Count -1 do
2075with TGraphPointObject(IntegList[i]) do
2076begin
2077PlotPoint.X := CoordX(y_r*Cos(x_phi));
2078PlotPoint.Y := CoordY(y_r*Sin(x_phi));
2079if i = 0 then DrawLine := false;
2080end;
2081end; { SetupIntegral }
2082
2083procedure ShadeArea;
2084var
2085i: integer;
2086p1, p2: TPoint;
2087yCoord: integer;
2088xCoord: integer;
2089r: extended;
2090
2091procedure DrawShading;
2092begin
2093with TGraphPointObject(SectorList[i]) do
2094begin
2095p1.x := xCoord;
2096r := EvaluateFunction(x_phi);
2097p2.x := CoordX(r*Cos(x_phi));
2098
2099p1.y := yCoord;
2100p2.y := CoordY(r*Sin(x_Phi));
2101if y_r < 0
2102then PenColor := GraphData.NegAreaColor
2103else PenColor := GraphData.PosAreaColor;
2104FillSector(p2.x, p2.Y);
2105end;
2106end; { DrawShading }
2107
2108begin { ShadeArea }
2109yCoord := CoordY(0); { coordinate for x axis }
2110xCoord := CoordX(0); { coordinate for y axis }
2111
2112PenWidth := 1;
2113PenAlpha := GraphData.AreaAlpha;
2114StartRadialFill(xCoord, yCoord);
2115
2116for i := 0 to Sectorlist.Count -1 do
2117with TGraphPointObject(SectorList[i]) do DrawShading;
2118PenAlpha := 1;
2119PenWidth := GraphData.PlotData.PlotWidth;
2120StopRadialFill;
2121end; { ShadeArea }
2122
2123procedure DrawIntegral;
2124var
2125i: integer;
2126
2127begin { DrawIntegral }
2128if Assigned(IntegList) then
2129PenColor := GraphData.ydxColor;
2130PenWidth := GraphData.ydxWidth;
2131for i := 0 to IntegList.Count -1 do
2132with TGraphPointObject(IntegList[i]) do
2133if DrawLine
2134then LineTo(PlotPoint.X, PlotPoint.Y)
2135else MoveTo(PlotPoint.X, PlotPoint.Y);
2136end; { DrawIntegral }
2137
2138{ TfxCanvas.IntegratePolar }
2139var
2140SumSect: extended; { calculate sector area using a = 0.5*r(mean)^2*d� }
2141NegSect: extended;
2142PosSect: extended;
2143
2144NegSegs: extended;
2145PosSegs: extended;
2146
2147begin
2148SectorList := TList.Create;
2149NegSect := 0;
2150PosSect := 0;
2151SumSect := SumSectors(NegSect, PosSect); { polar sectors }
2152
2153if IntegrateXForm.PlotIntegrated and piShow = piShow then
2154begin
2155IntegList := TList.Create;
2156NegSegs := 0;
2157PosSegs := 0;
2158SumSegments(NegSegs, PosSegs); { integral values }
2159end;
2160
2161try
2162with IntegrateXForm do
2163begin
2164if IntegCheckBox.Checked then { Plot Integral selected }
2165begin
2166MinIntegXLabel.Caption := 'Minimum: � = '+
2167FloatToStrF(IntegXMin, ffGeneral, 12, 8);
2168MinIntegYLabel.Caption := 'Minimum: r = '+
2169FloatToStrF(IntegYMin, ffGeneral, 12, 8);
2170
2171MaxIntegXLabel.Caption := 'Maximum: � = '+
2172FloatToStrF(IntegXMax, ffGeneral, 12, 8);
2173MaxIntegYLabel.Caption := 'Maximum: r = '+
2174FloatToStrF(IntegYMax, ffGeneral, 12, 8);
2175end;
2176
2177AreaLabel.Caption := 'Integral P[a, b] = '+
2178FloatToStrF(SumSect, ffGeneral, 12, 8);
2179
2180NegAreaLabel.Caption := '"Negative" Area = '+
2181FloatToStrF(NegSect, ffGeneral, 12, 8);
2182
2183PosAreaLabel.Caption := '"Positive" Area = '+
2184FloatToStrF(PosSect, ffGeneral, 12, 8);
2185
2186TotalAreaLabel.Caption := 'Total Area = '+
2187FloatToStrF(PosSect + NegSect, ffGeneral, 12, 8);
2188
2189SumAreaLabel.Caption := 'Sum Area = '+
2190FloatToStrF(SumSect, ffGeneral, 12, 8);
2191end;
2192
2193if SectorList.Count > 0 then
2194begin
2195SetupIntegral;
2196if IntegrateXForm.PlotIntegrated and piArea = piArea then ShadeArea;
2197if IntegrateXForm.PlotIntegrated and piShow = piShow then DrawIntegral;
2198end;
2199
2200finally
2201ClearPointList(SectorList);
2202SectorList := nil;
2203
2204ClearPointList(IntegList);
2205IntegList := nil;
2206end;
2207end; { TfxCanvas.IntegratePolar }
2208
2209procedure TfxCanvas.IntegrateYCartesian;
2210
2211procedure SetupIntegral;
2212var
2213i: integer;
2214
2215begin { SetupIntegral }
2216if Assigned(IntegList) then
2217for i := 0 to IntegList.Count -1 do
2218with TGraphPointObject(IntegList[i]) do
2219begin
2220PlotPoint.X := CoordX(x_phi);
2221PlotPoint.Y := CoordY(y_r);
2222if i = 0 then DrawLine := false;
2223end;
2224end; { SetupIntegral }
2225
2226procedure ShadeArea;
2227var
2228i: integer;
2229xCoord: integer;
2230
2231procedure DrawShading;
2232var
2233yValue: extended;
2234x, y: integer;
2235
2236begin
2237with TGraphPointObject(IntegList[i]) do
2238begin
2239x := PlotPoint.X;
2240yValue := EvaluateFunction(x_phi);
2241
2242PenWidth := 1;
2243PenAlpha := GraphData.AreaAlpha;
2244y := CoordY(yValue);
2245
2246if x_Phi < 0
2247then PenColor := GraphData.NegAreaColor
2248else PenColor := GraphData.PosAreaColor;
2249
2250Line(x, y, xCoord, y);
2251PenAlpha := 1;
2252end;
2253end;
2254
2255begin { ShadeArea }
2256xCoord := CoordX(0);
2257for i := 0 to IntegList.Count -1 do
2258with TGraphPointObject(IntegList[i]) do
2259if DrawLine then DrawShading;
2260end; { ShadeArea }
2261
2262{ TfxCanvas.IntegrateYCartesian }
2263var
2264SumSegs: extended;
2265NegSegs: extended;
2266PosSegs: extended;
2267py1, py2: extended;
2268
2269begin
2270IntegList := TList.Create;
2271try
2272NegSegs := 0;
2273PosSegs := 0;
2274SumSegs := SumYSegments(NegSegs, PosSegs); { Cartesian }
2275
2276with IntegrateYForm do
2277begin
2278py1 := EvaluateFunction(IntegMin);
2279py2 := EvaluateFunction(IntegMax);
2280Label5.Caption := FloatToStrF(py1, ffFixed, 13, 4);
2281Label6.Caption := FloatToStrF(py2, ffFixed, 13, 4);
2282
2283NegAreaLabel.Caption := '"Negative" Area = '+
2284FloatToStrF(Abs(NegSegs), ffGeneral, 12, 8);
2285
2286PosAreaLabel.Caption := '"Positive" Area = '+
2287FloatToStrF(PosSegs, ffGeneral, 12, 8);
2288
2289TotalAreaLabel.Caption := 'Total Area = '+
2290FloatToStrF(PosSegs - NegSegs, ffGeneral, 12, 8);
2291
2292SumAreaLabel.Caption := 'Sum Area = '+
2293FloatToStrF(SumSegs, ffGeneral, 12, 8);
2294end;
2295
2296if IntegList.Count > 0 then
2297begin
2298SetupIntegral;
2299ShadeArea;
2300end;
2301finally
2302ClearPointList(IntegList);
2303IntegList := nil;
2304end;
2305end;
2306
2307procedure TfxCanvas.IntegrateBetweenFunctions;
2308procedure PopulateList;
2309var
2310i: integer;
2311h, x, y: extended;
2312p1X, p1Y: integer;
2313
2314begin
2315h := (IntegMax - IntegMin)/GraphData.IntegCount; { calculate step }
2316x := IntegMin;
2317for i := 0 to GraphData.IntegCount do
2318begin
2319y := EvaluateFunction(x);
2320p1X := CoordX(x);
2321p1Y := CoordY(y);
2322
2323IntegList.Add(TGraphLineObject.Create(x, y));
2324TGraphLineObject(IntegList[i]).GraphLine.P1 := point(p1X, p1Y);
2325
2326x := x + h; { next step }
2327end;
2328end;
2329
2330procedure AddDataToList;
2331var
2332i: integer;
2333p1X, p2Y: integer;
2334
2335begin
2336for i := 0 to IntegList.Count -1 do
2337with TGraphLineObject(IntegList[i]).GraphLine do
2338begin
2339y2 := EvaluateFunction(x);
2340p1X := P1.X;
2341p2Y := CoordY(y2);
2342P2 := point(p1X, p2Y);
2343end;
2344end;
2345
2346function SumBetweenSegs(var aNeg, aPos: extended): extended;
2347var
2348i: integer;
2349a, dx, dy1, dy2: extended;
2350gl1, gl2: TGraphLine;
2351
2352begin
2353if IntegMax = IntegMin then
2354begin
2355Result := 0;
2356Exit;
2357end;
2358
2359if IntegMax < IntegMin then
2360begin
2361a := IntegMax;
2362IntegMax := IntegMin;
2363IntegMin := a;
2364with IntegrateXForm do
2365begin
2366EditIntegMin.Text := FloatToStrF(IntegMin, ffGeneral, 13, 4);
2367EditIntegMax.Text := FloatToStrF(IntegMax, ffGeneral, 13, 4);
2368end;
2369end;
2370
2371gl1 := TGraphLineObject(IntegList[0]).GraphLine;
2372gl2 := TGraphLineObject(IntegList[1]).GraphLine;
2373dx := gl2.x - gl1.x;
2374
2375for i := 1 to IntegList.Count -1 do
2376begin
2377gl1 := TGraphLineObject(IntegList[i -1]).GraphLine;
2378gl2 := TGraphLineObject(IntegList[i]).GraphLine;
2379
2380with gl1 do dy1 := y1 - y2;
2381with gl2 do dy2 := y1 - y2;
2382
2383a := dx*(dy1 + dy2)/2;
2384if a > 0 then aPos := aPos + a else aNeg := aNeg - a;
2385end;
2386Result := aPos - aNeg;
2387end;
2388
2389procedure ShadeBetweenArea;
2390var
2391i: integer;
2392px: integer;
2393gl: TGraphLine;
2394
2395begin
2396px := CoordX(IntegMax);
2397for i := 0 to Integlist.Count -1 do
2398begin
2399gl := TGraphLineObject(Integlist[i]).GraphLine;
2400if gl.P1.X <> px then
2401begin
2402PenWidth := 1;
2403PenAlpha := GraphData.AreaAlpha;
2404
2405if gl.y1 < gl.y2
2406then PenColor := GraphData.NegAreaColor
2407else PenColor := GraphData.PosAreaColor;
2408
2409Line(gl.P1.X, gl.P1.Y, gl.P2.X, gl.P2.Y);
2410PenAlpha := 1;
2411end;
2412
2413px := gl.P1.X;
2414end;
2415end;
2416
2417procedure ClearAndFreeList;
2418var
2419i: integer;
2420
2421begin
2422for i := 0 to IntegList.Count -1
2423do TGraphLineObject(IntegList[i]).Free;
2424IntegList.Free;
2425Integlist:= nil;
2426end;
2427
2428
2429var
2430SumSegs: extended;
2431NegSegs: extended;
2432PosSegs: extended;
2433py1, py2: extended;
2434
2435begin
2436with FunctionsForm.CheckListBox do
2437if (Count < 2) or (ItemIndex > 0) then exit;
2438IntegList := TList.Create;
2439try
2440with BetweenForm do
2441begin
2442py1 := EvaluateFunction(IntegMin);
2443py2 := EvaluateFunction(IntegMax);
2444Label5.Caption := FloatToStrF(py1, ffFixed, 13, 4);
2445Label6.Caption := FloatToStrF(py2, ffFixed, 13, 4);
2446end;
2447
2448PopulateList; { setup the data of first function }
2449
2450with FunctionsForm.CheckListBox
2451do GraphData.PlotData := TPlotDataObject(Items.Objects[1]).Data;
2452with FxParser do
2453begin
2454Calculus.Free;
2455with GraphData.PlotData do
2456Calculus := Compile(AnsiLowerCase(FunctStr), ErrorByte);
2457end;
2458
2459AddDataToList; { add the second function's data }
2460
2461NegSegs := 0;
2462PosSegs := 0;
2463SumSegs := SumBetweenSegs(NegSegs, PosSegs);
2464
2465ShadeBetweenArea;
2466with FunctionsForm.CheckListBox
2467do GraphData.PlotData := TPlotDataObject(Items.Objects[0]).Data;
2468
2469with BetweenForm do
2470begin
2471NegAreaLabel.Caption := '"Negative" Area = '+
2472FloatToStrF(NegSegs, ffGeneral, 12, 8);
2473
2474PosAreaLabel.Caption := '"Positive" Area = '+
2475FloatToStrF(PosSegs, ffGeneral, 12, 8);
2476
2477TotalAreaLabel.Caption := 'Total Area = '+
2478FloatToStrF(PosSegs + NegSegs, ffGeneral, 12, 8);
2479
2480SumAreaLabel.Caption := 'Sum Area = '+
2481FloatToStrF(SumSegs, ffGeneral, 12, 8);
2482end;
2483
2484finally
2485ClearAndFreeList;
2486end;
2487end; { TfxCanvas.IntegrateBetweenFunctions }
2488
2489procedure TfxCanvas.IntegrateVolumeX;
2490
2491function SumVolumeXSegments(var aVol, aSur: extended): Boolean;
2492var
2493h: extended; { step }
2494x: extended;
2495y, y1, y2: extended;
2496i, j: integer;
2497
2498begin
2499Result := false;
2500if IntegMax = IntegMin then Exit;
2501
2502if IntegMax < IntegMin then
2503begin
2504x := IntegMax;
2505IntegMax := IntegMin;
2506IntegMin := x;
2507with VolumeXForm do
2508begin
2509EditIntegMin.Text := FloatToStrF(IntegMin, ffGeneral, 13, 4);
2510EditIntegMax.Text := FloatToStrF(IntegMax, ffGeneral, 13, 4);
2511end;
2512end;
2513
2514h := (IntegMax - IntegMin)/GraphData.IntegCount; { calculate step }
2515
2516{ calculate numerical value to be used to display volume X }
2517x := IntegMin;
2518y1 := EvaluateFunction(x);
2519x := x + h;
2520j := 0;
2521for i := 1 to GraphData.IntegCount do
2522{ calculate volume X using V = piR^2*h }
2523begin
2524y2 := EvaluateFunction(x);
2525if not (isNaN(y1) or isNaN(y2) or isInfinite(y1) or isInfinite(y2)) then
2526begin
2527y := (y1 + y2)/2;
2528aVol := aVol + pi*sqr(y)*h; { volume is always positive }
2529aSur := aSur + 2*pi*abs(y)*h;
2530end
2531else Inc(j); { count NaN's }
2532y1 := y2; { update y1 }
2533x := x + h; { next step }
2534end; { for i := 0 to IntegCount do... }
2535{ if all y values are NaN then Result is false }
2536Result := j < GraphData.IntegCount;
2537end; { SumVolumeXSegments }
2538
2539procedure DrawVolumeX;
2540var
2541yCoord: integer;
2542i: integer;
2543StartIndex: integer; { StartIndex = PlotList index for plot start }
2544FinishIndex: integer; { FinishIndex = PlotList index for plot finish }
2545LastXCoord: integer;
2546dx: integer;
2547R1, R2: TRect;
2548
2549const
2550dxDiv: integer = 65;
2551
2552begin
2553yCoord := 2*CoordY(0);
2554
2555{ find start }
2556i := 0;
2557StartIndex := -1;
2558LastXCoord := MaxInt;
2559while (i < PlotList.Count) and (StartIndex < 0) do
2560begin
2561with TGraphPointObject(PlotList[i]) do
2562begin
2563if (x_phi >= IntegMin) and (x_phi <= IntegMax) and
2564DrawLine and not(isNaN(y_r) or isInfinite(y_r)) and
2565(LastXCoord <> PlotPoint.X) then
2566begin
2567StartIndex := i;
2568dx := abs(2*PlotPoint.Y - yCoord) div dxDiv;
2569R1 := Rect(PlotPoint.X - dx +1, PlotPoint.Y,
2570PlotPoint.X + dx +1, yCoord - PlotPoint.Y);
2571end;
2572LastXCoord := PlotPoint.X;
2573end; { with TGraphPointObject(PlotList[i]) do... }
2574Inc(i);
2575end; { (i < PlotList.Count) and (StartIndex < 0)... }
2576
2577{ find finish }
2578i := PlotList.Count -1;
2579FinishIndex := -1;
2580LastXCoord := MaxInt;
2581while (i > 0) and (FinishIndex < 0) do
2582begin
2583with TGraphPointObject(PlotList[i]) do
2584begin
2585if (x_phi >= IntegMin) and (x_phi <= IntegMax) and
2586DrawLine and not(isNaN(y_r) or isInfinite(y_r)) and
2587(LastXCoord <> PlotPoint.X) then
2588begin
2589FinishIndex := i;
2590dx := abs(2*PlotPoint.Y - yCoord) div dxDiv;
2591R2 := Rect(PlotPoint.X - dx, PlotPoint.Y,
2592PlotPoint.X + dx, yCoord - PlotPoint.Y);
2593end;
2594LastXCoord := PlotPoint.X;
2595end; { with TGraphPointObject(PlotList[i]) do... }
2596Dec(i);
2597end; { while (i > 0) and (FinishIndex < 0)... }
2598
2599{ use shade positive pen }
2600PenAlpha := GraphData.AreaAlpha;
2601PenWidth := 1;
2602PenColor := GraphData.PosAreaColor;
2603
2604with R1 do if (Left > 0) and (Right < CanvasSizeX) then
2605begin
2606FillEllipseBB(Left, Top, right, Bottom);
2607FillQuadrantsBB(Left, Top, Right, Bottom, false, true, true, false);
2608end;
2609
2610LastXCoord := MaxInt;
2611{ shade the solid volume X }
2612for i := StartIndex to FinishIndex do
2613with TGraphPointObject(PlotList[i]) do if DrawLine then
2614begin
2615if LastXCoord <> PlotPoint.X then
2616Line(PlotPoint.X, PlotPoint.Y, PlotPoint.X, yCoord - PlotPoint.Y);
2617LastXCoord := PlotPoint.X;
2618end; { for i := StartIndex to FinishIndex do... }
2619
2620with R2 do FillQuadrantsBB(Left, Top, Right, Bottom,
2621true, false, false, true);
2622
2623{ outline solid }
2624PenAlpha := 1;
2625
2626with R1 do if (Left > 0) and (Right < CanvasSizeX)
2627then Arc(Left, Top, Right, Bottom, 3*pion2, pion2);
2628
2629{ plot the positive section of function of f(x)}
2630LastXCoord := MaxInt;
2631for i := StartIndex to FinishIndex do
2632with TGraphPointObject(PlotList[i]) do
2633begin
2634if LastXCoord <> PlotPoint.X then
2635begin
2636if i = StartIndex
2637then MoveTo(PlotPoint.X, PlotPoint.Y)
2638else LineTo(PlotPoint.X, PlotPoint.Y);
2639end;
2640LastXCoord := PlotPoint.X;
2641end; { for i := StartIndex to FinishIndex do... }
2642
2643{ plot the negative function of f(x)}
2644LastXCoord := MaxInt;
2645for i := StartIndex to FinishIndex do
2646with TGraphPointObject(PlotList[i]) do
2647begin
2648if LastXCoord <> PlotPoint.X then
2649begin
2650if i = StartIndex
2651then MoveTo(PlotPoint.X, yCoord - PlotPoint.Y)
2652else LineTo(PlotPoint.X, yCoord - PlotPoint.Y);
2653end;
2654LastXCoord := PlotPoint.X;
2655end; { for i := StartIndex to FinishIndex do... }
2656
2657PenAlpha := GraphData.AreaAlpha;
2658{ use shade negative pen; shade solid's end }
2659PenColor := GraphData.NegAreaColor;
2660
2661with R2 do if (Left > 0) and (Right < CanvasSizeX)
2662then FillEllipseBB(Left, Top, Right, Bottom);
2663
2664PenAlpha := 1;
2665
2666with R2 do if (Left > 0) and (Right < CanvasSizeX)
2667then EllipseBB(Left, Top, Right, Bottom);
2668
2669{ restore plot pen width }
2670PenWidth := GraphData.PlotData.PlotWidth;
2671PenColor := GraphData.PlotData.PlotColor;
2672end;
2673
2674
2675var
2676VolSegs: extended;
2677SurSegs: extended;
2678py1, py2: extended;
2679
2680begin
2681with VolumeXForm do
2682begin
2683py1 := EvaluateFunction(IntegMin);
2684py2 := EvaluateFunction(IntegMax);
2685Label5.Caption := FloatToStrF(py1, ffFixed, 13, 4);
2686Label6.Caption := FloatToStrF(py2, ffFixed, 13, 4);
2687end;
2688try
2689VolSegs := 0; { Cartesian }
2690SurSegs := 0;
2691if not SumVolumeXSegments(VolSegs, SurSegs)
2692then Exit; { SumVolumeXSegments is false there are no values to plot }
2693
2694DrawVolumeX;
2695
2696with VolumeXForm do
2697begin
2698TotalVolumeLabel.Caption :=
2699'Total Volume = '+FloatToStrF(VolSegs, ffGeneral, 12, 8);
2700SurfaceAreaLabel.Caption :=
2701'Surface Area = '+FloatToStrF(SurSegs, ffGeneral, 12, 8);
2702end
2703except
2704end;
2705end;
2706
2707procedure TfxCanvas.IntegrateVolumeY;
2708
2709function SumVolumeYSegments(var aVol, aSur: extended): Boolean;
2710var
2711h: extended; { step }
2712x, x1, x2: extended;
2713y1, y2: extended;
2714i, j: integer;
2715
2716begin
2717Result := false;
2718if IntegMax = IntegMin then Exit;
2719
2720if IntegMax < IntegMin then
2721begin
2722x1 := IntegMax;
2723IntegMax := IntegMin;
2724IntegMin := x1;
2725with VolumeYForm do
2726begin
2727EditIntegMin.Text := FloatToStrF(IntegMin, ffGeneral, 13, 4);
2728EditIntegMax.Text := FloatToStrF(IntegMax, ffGeneral, 13, 4);
2729end;
2730end;
2731
2732h := (IntegMax - IntegMin)/GraphData.IntegCount; { calculate step }
2733
2734{ calculate numerical value to be used to display volume Y }
2735x1 := IntegMin;
2736y1 := EvaluateFunction(x1);
2737x2 := x1 + h;
2738j := 0;
2739for i := 1 to GraphData.IntegCount do
2740{ calculate volume Y using V = piR^2*h }
2741begin
2742y2 := EvaluateFunction(x2);
2743if not (isNaN(y1) or isNaN(y2) or isInfinite(y1) or IsInfinite(y2)) then
2744begin
2745x := (x1 + x2)/2;
2746aVol := aVol + pi*sqr(x)*abs(y2 - y1); { volume is always positive }
2747aSur := aSur + 2*pi*abs(x)*abs(y2 - y1);
2748end
2749else Inc(j);
2750y1 := y2; { update y1 }
2751x1 := x2;
2752x2 := x2 + h; { next step }
2753end; { for i := 0 to IntegCount do... }
2754Result := j < GraphData.IntegCount;
2755end; { SumVolumeYSegments }
2756
2757procedure DrawVolumeY;
2758var
2759xCoord: integer;
2760i: integer;
2761j: integer;
2762StartIndex: integer; { StartIndex = PlotList index for plot start }
2763FinishIndex: integer; { FinishIndex = PlotList index for plot finish }
2764LastXCoord: integer;
2765LastYCoord: integer;
2766dy: integer;
2767R1, R2: TRect;
2768
2769const
2770dyDiv: integer = 65;
2771
2772begin
2773xCoord := 2*CoordX(0);
2774{ find start }
2775i := 0;
2776StartIndex := -1;
2777LastXCoord := MaxInt;
2778while (i < PlotList.Count) and (StartIndex < 0) do
2779begin
2780with TGraphPointObject(PlotList[i]) do
2781begin
2782if (x_phi >= IntegMin) and (x_phi <= IntegMax) and
2783DrawLine and not(isNaN(y_r) or isInfinite(y_r)) and
2784(LastXCoord <> PlotPoint.X) then
2785begin
2786StartIndex := i - 1;
2787with TGraphPointObject(PlotList[StartIndex]) do
2788begin
2789dy := abs(2*PlotPoint.X - xCoord) div dyDiv;
2790R1 := Rect(PlotPoint.X, PlotPoint.Y - dy,
2791xCoord - PlotPoint.X, PlotPoint.Y + dy);
2792end;
2793end;
2794LastXCoord := PlotPoint.X;
2795end; { with TGraphPointObject(PlotList[i]) do... }
2796Inc(i);
2797end; { (i < PlotList.Count) and (StartIndex < 0)... }
2798
2799{ find finish }
2800i := PlotList.Count -2;
2801FinishIndex := -1;
2802LastXCoord := MaxInt;
2803while (i > 0) and (FinishIndex < 0) do
2804begin
2805with TGraphPointObject(PlotList[i]) do
2806begin
2807if (x_phi >= IntegMin) and (x_phi <= IntegMax) and
2808DrawLine and not(isNaN(y_r) or isInfinite(y_r)) and
2809(LastXCoord <> PlotPoint.X) then
2810begin
2811FinishIndex := i + 1;
2812with TGraphPointObject(PlotList[FinishIndex]) do
2813begin
2814dy := abs(2*PlotPoint.X - xCoord) div dyDiv;
2815R2 := Rect(PlotPoint.X, PlotPoint.Y - dy,
2816xCoord - PlotPoint.X, PlotPoint.Y + dy);
2817end;
2818end;
2819LastXCoord := PlotPoint.X;
2820end; { with TGraphPointObject(PlotList[i]) do... }
2821Dec(i);
2822end; { while (i > 0) and (FinishIndex < 0)... }
2823
2824if StartIndex = FinishIndex then Exit;
2825
2826if TGraphPointObject(PlotList[StartIndex]).PlotPoint.Y >
2827TGraphPointObject(PlotList[FinishIndex]).PlotPoint.Y then
2828begin
2829{ use shade positive pen }
2830PenAlpha := GraphData.AreaAlpha;
2831PenWidth := 1;
2832PenColor := GraphData.PosAreaColor;
2833
2834with R1 do
2835begin
2836FillEllipseBB(Left, Top, right, Bottom);
2837FillQuadrantsBB(Left, Top, Right, Bottom, false, false, true, true);
2838end;
2839
2840LastXCoord := MaxInt;
2841LastYCoord := TGraphPointObject(PlotList[StartIndex]).PlotPoint.Y;
2842
2843{ shade the solid volume Y }
2844for i := StartIndex to FinishIndex do
2845with TGraphPointObject(PlotList[i]) do
2846begin
2847if (LastXCoord <> PlotPoint.X) and (LastYCoord <> PlotPoint.Y) then
2848Line(PlotPoint.X, PlotPoint.Y, xCoord - PlotPoint.X, PlotPoint.Y);
2849if DrawLine then
2850begin
2851dy := PlotPoint.Y - LastYCoord;
2852for j := 1 to abs(dy) - 1 do
2853Line(PlotPoint.X + trunc(j/dy), PlotPoint.Y + j,
2854xCoord - PlotPoint.X - trunc(j/dy), PlotPoint.Y + j);
2855end;
2856LastYCoord := PlotPoint.Y;
2857LastXCoord := PlotPoint.X;
2858end; { for i := StartIndex to FinishIndex do... }
2859
2860with R2 do FillQuadrantsBB(Left, Top, Right, Bottom,
2861true, true, false, false);
2862{ outline solid }
2863PenAlpha := 1;
2864
2865with R1 do Arc(Left, Top, Right, Bottom, pi, 0);
2866{ plot the positive section of function of f(x)}
2867LastXCoord := MaxInt;
2868for i := StartIndex to FinishIndex do
2869with TGraphPointObject(PlotList[i]) do
2870begin
2871if LastXCoord <> PlotPoint.X then
2872begin
2873if i = StartIndex
2874then MoveTo(PlotPoint.X, PlotPoint.Y)
2875else LineTo(PlotPoint.X, PlotPoint.Y);
2876end;
2877LastXCoord := PlotPoint.X;
2878end; { for i := StartIndex to FinishIndex do... }
2879
2880{ plot the negative function of f(x)}
2881LastXCoord := MaxInt;
2882for i := StartIndex to FinishIndex do
2883with TGraphPointObject(PlotList[i]) do
2884begin
2885if LastXCoord <> PlotPoint.X then
2886begin
2887if i = StartIndex
2888then MoveTo(xCoord - PlotPoint.X, PlotPoint.Y)
2889else LineTo(xCoord - PlotPoint.X, PlotPoint.Y);
2890end;
2891LastXCoord := PlotPoint.X;
2892end; { for i := StartIndex to FinishIndex do... }
2893
2894PenAlpha := GraphData.AreaAlpha;
2895{ use shade negative pen; shade solid's end }
2896PenColor := GraphData.NegAreaColor;
2897with R2 do if Right < CanvasSizeX
2898then FillEllipseBB(Left, Top, Right, Bottom);
2899
2900PenAlpha := 1;
2901with R2 do EllipseBB(Left, Top, Right, Bottom);
2902
2903{ restore plot pen width }
2904PenWidth := GraphData.PlotData.PlotWidth;
2905PenColor := GraphData.PlotData.PlotColor;
2906end
2907else { TGraphPointObject(PlotList[StartIndex]).PlotPoint.Y <=
2908TGraphPointObject(PlotList[FinishIndex]).PlotPoint.Y }
2909begin
2910{ use shade positive pen }
2911PenAlpha := GraphData.AreaAlpha;
2912PenWidth := 1;
2913PenColor := GraphData.PosAreaColor;
2914
2915with R1 do
2916begin
2917FillEllipseBB(Left, Top, right, Bottom);
2918FillQuadrantsBB(Left, Top, Right, Bottom, true, true, false, false);
2919end;
2920
2921LastXCoord := MaxInt;
2922LastYCoord := TGraphPointObject(PlotList[StartIndex]).PlotPoint.Y;
2923
2924{ shade the solid volume Y }
2925for i := FinishIndex downto StartIndex do
2926with TGraphPointObject(PlotList[i]) do
2927begin
2928if (LastXCoord <> PlotPoint.X) and (LastYCoord <> PlotPoint.Y) then
2929Line(PlotPoint.X, PlotPoint.Y, xCoord - PlotPoint.X, PlotPoint.Y);
2930
2931if (i < FinishIndex) and DrawLine then
2932begin
2933dy := PlotPoint.Y - LastYCoord;
2934for j := 1 to abs(dy) -1 do
2935Line(PlotPoint.X - round(j/dy), PlotPoint.Y + j,
2936xCoord - PlotPoint.X + round(j/dy), PlotPoint.Y + j);
2937end;
2938LastYCoord := PlotPoint.Y;
2939LastXCoord := PlotPoint.X;
2940end; { for i := FinishIndex downto StartIndex do... }
2941
2942with R2 do FillQuadrantsBB(Left, Top, Right, Bottom,
2943false, false, true, true);
2944{ outline solid }
2945PenAlpha := 1;
2946
2947with R1 do Arc(Left, Top, Right, Bottom, 0, pi);
2948{ plot the positive section of function of f(x)}
2949LastXCoord := MaxInt;
2950for i := StartIndex to FinishIndex do
2951with TGraphPointObject(PlotList[i]) do
2952begin
2953if LastXCoord <> PlotPoint.X then
2954begin
2955if i = StartIndex
2956then MoveTo(PlotPoint.X, PlotPoint.Y)
2957else LineTo(PlotPoint.X, PlotPoint.Y);
2958end;
2959LastXCoord := PlotPoint.X;
2960end; { for i := StartIndex to FinishIndex do... }
2961
2962{ plot the negative function of f(x)}
2963LastXCoord := MaxInt;
2964for i := StartIndex to FinishIndex do
2965with TGraphPointObject(PlotList[i]) do
2966begin
2967if LastXCoord <> PlotPoint.X then
2968begin
2969if i = StartIndex
2970then MoveTo(xCoord - PlotPoint.X, PlotPoint.Y)
2971else LineTo(xCoord - PlotPoint.X, PlotPoint.Y);
2972end;
2973LastXCoord := PlotPoint.X;
2974end; { for i := StartIndex to FinishIndex do... }
2975
2976PenAlpha := GraphData.AreaAlpha;
2977{ use shade negative pen; shade solid's end }
2978PenColor := GraphData.NegAreaColor;
2979with R2 do if Right < CanvasSizeX
2980then FillEllipseBB(Left, Top, Right, Bottom);
2981
2982PenAlpha := 1;
2983with R2 do EllipseBB(Left, Top, Right, Bottom);
2984
2985{ restore plot pen width }
2986PenWidth := GraphData.PlotData.PlotWidth;
2987PenColor := GraphData.PlotData.PlotColor;
2988end;
2989end;
2990
2991
2992var
2993VolSegs: extended;
2994SurSegs: extended;
2995py1, py2: extended;
2996
2997begin
2998with VolumeYForm do
2999begin
3000py1 := EvaluateFunction(IntegMin);
3001py2 := EvaluateFunction(IntegMax);
3002Label5.Caption := FloatToStrF(py1, ffFixed, 13, 4);
3003Label6.Caption := FloatToStrF(py2, ffFixed, 13, 4);
3004end;
3005
3006try
3007VolSegs := 0; { Cartesian }
3008SurSegs := 0;
3009if not SumVolumeYSegments(VolSegs, SurSegs)
3010then exit;
3011
3012DrawVolumeY;
3013
3014with VolumeYForm do
3015begin
3016TotalVolumeLabel.Caption :=
3017'Total Volume = '+FloatToStrF(VolSegs, ffGeneral, 12, 8);
3018SurfaceAreaLabel.Caption :=
3019'Surface Area = '+FloatToStrF(SurSegs, ffGeneral, 12, 8);
3020end;
3021except
3022end;
3023end;
3024
3025procedure TfxCanvas.FindfxValues(const y: extended);
3026
3027procedure Interpolate(x1, x2, y1, y2: extended);
3028
3029procedure Display;
3030var
3031sx, sy: string;
3032
3033begin
3034x1 := (x1 + x2)/2;
3035y1 := EvaluateFunction(x1);
3036
3037if x1 < 0
3038then sx := ' '+Format('%g',[x1])
3039else sx := ' '+Format('%g',[x1]);
3040while Length(sx) < 24 do sx := sx + ' ';
3041
3042if y1 < 0
3043then sy := ' '+Format('%g',[y1])
3044else sy := ' '+Format('%g',[y1]);
3045while Length(sy) < 24 do sy := sy + ' ';
3046
3047fxValueForm.ListBox1.AddItem(sx + '|' + sy,
3048TFoundPointObject.Create(x1, 0, y1, GraphData.PlotData.PlotColor, 0));
3049end;
3050
3051{ Interpolate f(x) }
3052const
3053dpMin = 1e-30;
3054
3055var
3056vx, vy: extended;
3057dx, dp: extended;
3058
3059begin
3060dx := (x2 - x1)/2;
3061dp := 1;
3062if y1 < y2 then
3063begin
3064while dp > dpMin do
3065begin
3066vx := x1 + dx;
3067vy := EvaluateFunction(vx);
3068if vy < y then x1 := vx
3069else
3070if vy > y then x2 := vx;
3071dx := dx/2;
3072dp := dp/2;
3073end;
3074end
3075else
3076begin
3077while dp > dpMin do
3078begin
3079vx := x1 + dx;
3080vy := EvaluateFunction(vx);
3081if vy < y then x2 := vx
3082else
3083if vy > y then x1 := vx;
3084dx := dx/2;
3085dp := dp/2;
3086end;
3087end;
3088Display;
3089end;
3090
3091
3092var
3093i: integer;
3094y_rPrior: extended;
3095cy, dy: extended;
3096
3097begin
3098i := 0;
3099y_rPrior := TGraphPointObject(PlotList[i]).y_r;
3100dy := abs(y - y_rPrior); { difference y to find and current y }
3101cy := (GraphData.yMax - GraphData.yMin)/(CanvasSizeY*1000);
3102Inc(i);
3103
3104while i < PlotList.Count do
3105begin
3106with TGraphPointObject(PlotList[i]) do
3107begin
3108if not isNaN(y_r) then
3109begin
3110if (((y_rPrior <= y) and (y_r >= y)) or
3111((y_rPrior >= y) and (y_r <= y)) or (dy < cy))
3112and not isNaN(TGraphPointObject(PlotList[i -1]).y_r)
3113then Interpolate(TGraphPointObject(PlotList[i -1]).x_phi, x_phi,
3114TGraphPointObject(PlotList[i -1]).y_r, y_r);
3115y_rPrior := y_r;
3116dy := abs(y - y_rPrior);
3117end;
3118Inc(i);
3119end;
3120end;
3121end;
3122
3123procedure TfxCanvas.DrawfxPoints;
3124var
3125i: integer;
3126p0, p1, p2: TPoint;
3127
3128begin
3129with fxValueForm.ListBox1 do for i := 0 to Count -1 do
3130with TFoundPointObject(Items.Objects[i]) do
3131begin
3132with GraphData.Grid do
3133begin
3134if xAxisStyle = asLog
3135then p0.X := CoordLogX(xValue)
3136else p0.X := CoordX(xValue);
3137
3138if yAxisStyle = asLog
3139then p0.Y := CoordLogY(yValue)
3140else p0.Y := CoordY(yValue);
3141end;
3142p1.X := p0.X - 8;
3143p1.Y := p0.Y - 7;
3144p2.X := p0.X + 7;
3145p2.Y := p0.Y + 8;
3146
3147PenWidth := 2;
3148PenColor := Color;
3149MoveTo(p1.X, p0.Y);
3150LineTo(p2.X, p0.Y);
3151MoveTo(p0.X, p1.Y);
3152LineTo(p0.X, p2.Y);
3153Ellipse(p0.X, p0.Y, 8, 8);
3154end;
3155end;
3156
3157procedure TfxCanvas.Findfx1Values(const dy: extended);
3158var
3159px: array[1..3] of extended; { 3 points to consider }
3160py: array[1..3] of extended; { 3 points to consider }
3161dybydx: array[1..2] of extended; { 2 intervals to consider }
3162Mean: extended;
3163
3164procedure Interpolate;
3165procedure Display;
3166var
3167sx, sy: string;
3168
3169begin
3170if isNaN(px[2]) or isInfinite(px[2]) or
3171isNaN(Mean) or isInfinite(Mean) then Exit;
3172
3173if px[2] < 0
3174then sx := ' '+Format('%g',[px[2]])
3175else sx := ' '+Format('%g',[px[2]]);
3176while Length(sx) < 24 do sx := sx + ' ';
3177
3178if Mean < 0
3179then sy := ' '+Format('%g',[Mean])
3180else sy := ' '+Format('%g',[Mean]);
3181while Length(sy) < 24 do sy := sy + ' ';
3182
3183fx1ValueForm.ListBox1.AddItem(sx + '|' + sy,
3184TFoundPointObject.Create(px[2], Mean, py[2],
3185GraphData.PlotData.PlotColor, GraphData.dydxColor));
3186end; { Display }
3187
3188var
3189dx: extended;
3190
3191procedure MoveLeft;
3192var
3193j: integer;
3194
3195begin
3196for j := 1 to 3 do px[j] := px[j] - dx;
3197end;
3198
3199procedure MoveRight;
3200var
3201j: integer;
3202
3203begin
3204for j := 1 to 3 do px[j] := px[j] + dx;
3205end;
3206
3207{ Interpolate f'(x) }
3208
3209const
3210xDeltaMin = 7.88860905221012E-31; { 1/2^100 }
3211
3212var
3213xDelta: extended;
3214j: integer;
3215
3216begin
3217xDelta := 1/8;
3218Mean := (dybydx[1] + dybydx[2])/2;
3219dx := (px[2] - px[1])*xDelta;
3220
3221while xDelta > xDeltaMin do
3222begin
3223if Mean > dy then
3224begin
3225if dybydx[2] > dybydx[1] then MoveLeft else MoveRight;
3226end
3227else { Mean <= dy }
3228begin
3229if dybydx[2] > dybydx[1] then MoveRight else MoveLeft;
3230end;
3231
3232for j := 1 to 3 do py[j] := EvaluateFunction(px[j]);
3233
3234for j := 1 to 2 do dybydx[j] := (py[j +1] - py[j])/(px[j +1] - px[j]);
3235
3236Mean := (dybydx[1] + dybydx[2])/2;
3237xDelta := xDelta/2;
3238dx := dx/2;
3239end;
3240
3241Display;
3242end;
3243
3244
3245var
3246i: integer;
3247j: integer;
3248
3249begin
3250i := 1;
3251while i < PlotList.Count -1 do
3252begin
3253for j := 1 to 3 do
3254with TGraphPointObject(PlotList[i + j - 2]) do
3255begin
3256px[j] := x_phi;
3257py[j] := y_r;
3258end;
3259
3260if not(isNaN(py[1]) or isNaN(py[2]) or isNaN(py[3])) then
3261begin
3262{ calculate dy/dx (f'x) for the 2 intervals }
3263for j := 1 to 2 do dybydx[j] := (py[j +1] - py[j])/(px[j +1] - px[j]);
3264
3265if (((dybydx[1] <= dy) and (dybydx[2] >= dy)) or
3266((dybydx[1] >= dy) and (dybydx[2] <= dy)))
3267then Interpolate;
3268end;
3269Inc(i);
3270end;
3271end;
3272
3273procedure TfxCanvas.Drawfx1Points;
3274var
3275i: integer;
3276p0, p1, p2: TPoint;
3277
3278begin
3279with fx1ValueForm.ListBox1 do for i := 0 to Count -1 do
3280with TFoundPointObject(Items.Objects[i]) do
3281begin
3282with GraphData.Grid do
3283begin
3284if xAxisStyle = asLog
3285then p0.X := CoordLogX(xValue)
3286else p0.X := CoordX(xValue);
3287
3288if yAxisStyle = asLog
3289then p0.Y := CoordLogY(yValue)
3290else p0.Y := CoordY(yValue);
3291end;
3292p1.X := p0.X - 8;
3293p1.Y := p0.Y - 7;
3294p2.X := p0.X + 7;
3295p2.Y := p0.Y + 8;
3296
3297PenWidth := 2;
3298PenColor := Color;
3299MoveTo(p1.X, p0.Y);
3300LineTo(p2.X, p0.Y);
3301MoveTo(p0.X, p1.Y);
3302LineTo(p0.X, p2.Y);
3303Ellipse(p0.X, p0.Y, 8, 8);
3304
3305if FunctionsForm.yfx1.Checked then
3306begin
3307if GraphData.Grid.yAxisStyle = asLog
3308then p0.Y := CoordLogY(mValue)
3309else p0.Y := CoordY(mValue);
3310
3311p1.Y := p0.Y - 7;
3312p2.Y := p0.Y + 8;
3313PenColor := mColor;
3314
3315MoveTo(p1.X, p0.Y);
3316LineTo(p2.X, p0.Y);
3317MoveTo(p0.X, p1.Y);
3318LineTo(p0.X, p2.Y);
3319Ellipse(p0.X, p0.Y, 8, 8);
3320end;
3321end;
3322end;
3323
3324procedure TfxCanvas.Findfx2Values(const d2y: Extended);
3325var
3326px: array[1..5] of extended; { 5 points to consider }
3327py: array[1..5] of extended; { 5 points to consider }
3328dybydx: array[1..4] of extended; { 4 intervals to consider }
3329d2ybydx2: array[1..2] of extended; { 2 intervals to consider }
3330Mean: extended;
3331
3332procedure Interpolate;
3333const
3334xDeltaMin = 7.88860905221012E-31; { 1/2^100 }
3335var
3336dx: extended;
3337xDelta: extended;
3338j: integer;
3339
3340procedure Display;
3341var
3342sx, sy: string;
3343begin
3344if isNaN(px[3]) or isInfinite(px[3]) or
3345isNaN(Mean) or isInfinite(Mean) then Exit;
3346if px[3] < 0
3347then sx := ' '+Format('%g',[px[3]])
3348else sx := ' '+Format('%g',[px[3]]);
3349while Length(sx) < 24 do sx := sx + ' ';
3350
3351if Mean < 0
3352then sy := ' '+Format('%g',[Mean])
3353else sy := ' '+Format('%g',[Mean]);
3354while Length(sy) < 24 do sy := sy + ' ';
3355fx2ValueForm.ListBox1.AddItem(sx + '|' + sy,
3356TFoundPointObject.Create(px[3], Mean, py[3],
3357GraphData.PlotData.PlotColor, GraphData.d2ydx2Color));
3358end;
3359
3360
3361procedure MoveLeft;
3362var
3363j: integer;
3364
3365begin
3366for j := 1 to 5 do px[j] := px[j] - dx;
3367end;
3368
3369procedure MoveRight;
3370var
3371j: integer;
3372
3373begin
3374for j := 1 to 5 do px[j] := px[j] + dx;
3375end;
3376
3377
3378begin
3379xDelta := 1/8;
3380Mean := (d2ybydx2[1] + d2ybydx2[2])/2;
3381dx := (px[2] - px[1])*xDelta;
3382
3383while xDelta > xDeltaMin do
3384begin
3385if Mean > d2y then
3386begin
3387if d2ybydx2[2] > d2ybydx2[1] then MoveLeft else MoveRight;
3388end
3389else { Mean <= d2y }
3390begin
3391if d2ybydx2[2] > d2ybydx2[1] then MoveRight else MoveLeft;
3392end;
3393
3394for j := 1 to 5 do py[j] := EvaluateFunction(px[j]);
3395
3396{ calculate dy/dx (f'x) for the four intervals }
3397for j := 1 to 4 do
3398dybydx[j] := (py[j +1] - py[j])/(px[j +1] - px[j]);
3399{ calculate d2y/dx� (f"x) for the two intervals }
3400for j := 1 to 2 do
3401d2ybydx2[j] := (dybydx[j +1] - dybydx[j])/(px[j +1] - px[j]);
3402
3403Mean := (d2ybydx2[1] + d2ybydx2[2])/2;
3404xDelta := xDelta/2;
3405dx := dx/2;
3406end;
3407
3408Display;
3409end;
3410
3411var
3412i: integer;
3413j: integer;
3414
3415begin
3416i := 2;
3417while i < PlotList.Count -2 do
3418begin
3419for j := 1 to 5 do
3420with TGraphPointObject(PlotList[i + j - 3]) do
3421begin
3422px[j] := x_phi;
3423py[j] := y_r;
3424end;
3425
3426if not(isNaN(py[1]) or isNaN(py[2]) or isNaN(py[3]) or
3427isNaN(py[4]) or isNaN(py[5])) then
3428begin
3429{ calculate dy/dx (f'x) for the four intervals }
3430for j := 1 to 4 do
3431dybydx[j] := (py[j +1] - py[j])/(px[j +1] - px[j]);
3432{ calculate d2y/dx� (f"x) for the two intervals }
3433for j := 1 to 2 do
3434d2ybydx2[j] := (dybydx[j +1] - dybydx[j])/(px[j +1] - px[j]);
3435
3436{ (f"x1 <= d2y and f"x2 >= d2y) or (f"x2 <= d2y and f"x1 >= d2y) }
3437if (((d2ybydx2[1] <= d2y) and (d2ybydx2[2] >= d2y)) or
3438((d2ybydx2[1] >= d2y) and (d2ybydx2[2] <= d2y)))
3439then Interpolate;
3440end;
3441
3442Inc(i);
3443end;
3444end;
3445
3446procedure TfxCanvas.Drawfx2Points;
3447var
3448i: integer;
3449p0, p1, p2: TPoint;
3450
3451begin
3452with fx2ValueForm.ListBox1 do for i := 0 to Count -1 do
3453with TFoundPointObject(Items.Objects[i]) do
3454begin
3455with GraphData.Grid do
3456begin
3457if xAxisStyle = asLog
3458then p0.X := CoordLogX(xValue)
3459else p0.X := CoordX(xValue);
3460
3461if yAxisStyle = asLog
3462then p0.Y := CoordLogY(yValue)
3463else p0.Y := CoordY(yValue);
3464end;
3465p1.X := p0.X - 8;
3466p1.Y := p0.Y - 7;
3467p2.X := p0.X + 7;
3468p2.Y := p0.Y + 8;
3469
3470PenWidth := 2;
3471PenColor := Color;
3472MoveTo(p1.X, p0.Y);
3473LineTo(p2.X, p0.Y);
3474MoveTo(p0.X, p1.Y);
3475LineTo(p0.X, p2.Y);
3476Ellipse(p0.X, p0.Y, 8, 8);
3477
3478if FunctionsForm.yfx2.Checked then
3479begin
3480if GraphData.Grid.yAxisStyle = asLog
3481then p0.Y := CoordLogY(mValue)
3482else p0.Y := CoordY(mValue);
3483p1.Y := p0.Y - 7;
3484p2.Y := p0.Y + 8;
3485PenColor := mColor;
3486
3487MoveTo(p1.X, p0.Y);
3488LineTo(p2.X, p0.Y);
3489MoveTo(p0.X, p1.Y);
3490LineTo(p0.X, p2.Y);
3491Ellipse(p0.X, p0.Y, 8, 8);
3492end;
3493end;
3494end;
3495
3496procedure TfxCanvas.DrawCartesianCoordinates;
3497var
3498x, y: integer;
3499
3500begin
3501PenWidth := GraphData.CoordWidth;
3502PenColor := GraphData.CoordColor;
3503
3504with GraphData.Grid do
3505begin
3506if xAxisStyle = asLog
3507then x := CoordLogX(xEvaluate)
3508else x := CoordX(xEvaluate);
3509
3510if yAxisStyle = asLog
3511then y := CoordLogY(yEvaluate)
3512else y := CoordY(yEvaluate);
3513end;
3514
3515MoveTo(x, 0);
3516LineTo(x, CanvasSizeY);
3517MoveTo(0, y);
3518LineTo(CanvasSizeX, y);
3519end;
3520
3521procedure TfxCanvas.DrawPolarCoordinates;
3522var
3523x, y: integer;
3524
3525begin
3526PenWidth := GraphData.CoordWidth;
3527PenColor := GraphData.CoordColor;
3528
3529x := CoordX(yCosxEval);
3530y := CoordY(ySinxEval);
3531MoveTo(CoordX(0), CoordY(0));
3532LineTo(x, y);
3533MoveTo(x, 0);
3534LineTo(x, CanvasSizeY);
3535MoveTo(0, y);
3536LineTo(CanvasSizeX, y);
3537end;
3538
3539procedure TfxCanvas.DrawNumericData;
3540{ Hermite }
3541const
3542StepPts = 500;
3543
3544var
3545ePoints: TList; { list of TGraphPoint }
3546{ Hermite }
3547
3548function sk(x: extended; n: word): extended; {resolution factor }
3549var
3550nt: integer;
3551
3552begin
3553Result := 1;
3554for nt := 1 to n do Result := Result*x;
3555end;
3556
3557function xp(k, j, i: integer): extended;
3558var
3559n: extended;
3560
3561begin
3562n := (j +1)/StepPts;
3563with NumericForm.CheckListBox do
3564with TNumericObject(Items.Objects[i]) do
3565Result := ((2*sk(n, 3) -
35663*sk(n, 2) +1)*TGraphPointObject(ControlPoints[k]).x_phi -
3567(2*sk(n, 3) -
35683*sk(n, 2))*TGraphPointObject(ControlPoints[k +1]).x_phi +
3569(sk(n, 3) -
35702*sk(n, 2) + n)*TGraphPointObject(ePoints[k]).x_phi +
3571(sk(n, 3) -
3572sk(n, 2))*TGraphPointObject(ePoints[k +1]).x_phi);
3573end;
3574
3575function yp(k, j, i: integer): extended;
3576var
3577n: extended;
3578
3579begin
3580n := (j +1)/StepPts;
3581with NumericForm.CheckListBox do
3582with TNumericObject(Items.Objects[i]) do
3583Result := ((2*sk(n, 3) -
35843*sk(n, 2) +1)*TGraphPointObject(ControlPoints[k]).y_r -
3585(2*sk(n, 3) -
35863*sk(n, 2))*TGraphPointObject(ControlPoints[k +1]).y_r +
3587(sk(n, 3) -
35882*sk(n, 2) + n)*TGraphPointObject(ePoints[k]).y_r +
3589(sk(n, 3) -
3590sk(n, 2))*TGraphPointObject(ePoints[k +1]).y_r);
3591
3592end;
3593
3594procedure DrawTarget(const x, y: extended; const c: TColor);
3595var
3596i: integer;
3597p0, p1, p2: TPoint;
3598
3599begin
3600with GraphData.Grid do
3601begin
3602if xAxisStyle = asLog
3603then p0.X := CoordLogX(x)
3604else p0.X := CoordX(x);
3605
3606if yAxisStyle = asLog
3607then p0.Y := CoordLogY(y)
3608else p0.Y := CoordY(y);
3609end;
3610p1.X := p0.X - 8;
3611p1.Y := p0.Y - 7;
3612p2.X := p0.X + 7;
3613p2.Y := p0.Y + 8;
3614PenWidth := 2;
3615PenColor := c;
3616MoveTo(p1.X, p0.Y);
3617LineTo(p2.X, p0.Y);
3618MoveTo(p0.X, p1.Y);
3619LineTo(p0.X, p2.Y);
3620Ellipse(p0.X, p0.Y, 8, 8);
3621end;
3622
3623var
3624FirstPoint, LastPoint: integer;
3625Start, Stop, Step, vx, vy: extended;
3626p, a, d: extended;
3627i, j, k, w: integer;
3628Ordered: Boolean;
3629x_phiWas: extended;
3630c: TColor;
3631
3632{ Hermite }
3633k0: extended; { see CurveRate }
3634ePoint: TGraphPoint;
3635{ Hermite }
3636
3637begin { TfxCanvas.DrawNumericData }
3638with NumericForm.CheckListBox do if Count > 0 then
3639begin
3640for i := 0 to Count -1 do
3641with TNumericObject(Items.Objects[i]) do if Checked[i] then
3642begin
3643if ControlPoints.Count > 0 then
3644begin
3645FirstPoint := 0; { first control point index }
3646{ ignore negative values if Log x axis }
3647if GraphData.Grid.xAxisStyle = asLog then
3648while (FirstPoint < ControlPoints.Count) and
3649(TGraphPointObject(ControlPoints[FirstPoint]).x_phi <= 0)
3650do Inc(FirstPoint);
3651
3652{ ignore negative values if Log y axis }
3653if GraphData.Grid.yAxisStyle = asLog then
3654while (FirstPoint < ControlPoints.Count) and
3655(TGraphPointObject(ControlPoints[FirstPoint]).y_r <= 0)
3656do Inc(FirstPoint);
3657
3658if FirstPoint = ControlPoints.Count then Exit;
3659
3660w := 2*Data.PointSize;
3661PenColor := Data.PointColor;
3662if Data.PointSize < 3 then PenWidth := 2
3663else PenWidth := 2*Data.PointSize div 3 ;
3664
3665x_phiWas := -1e200;
3666
3667LastPoint := ControlPoints.Count -1;
3668
3669{ points must be ordered and not repeat; Loops if first = last }
3670Ordered := TGraphPointObject(ControlPoints[FirstPoint]).x_phi <>
3671TGraphPointObject(ControlPoints[LastPoint]).x_phi;
3672if Data.ShowPoints then
3673begin
3674for j := FirstPoint to LastPoint do
3675with TGraphPointObject(ControlPoints[j]) do
3676begin
3677if GraphData.Grid.xAxisStyle = asLog
3678then PlotPoint.X := CoordLogX(x_phi)
3679else
3680begin
3681if Data.CoordsIdx = 1
3682then PlotPoint.X := CoordX(y_r*Cos(x_phi))
3683else PlotPoint.X := CoordX(x_phi);
3684end;
3685
3686if x_phi < x_phiWas then Ordered := False;
3687x_phiWas := x_phi;
3688
3689if GraphData.Grid.yAxisStyle = asLog
3690then PlotPoint.Y := CoordLogY(y_r)
3691else
3692begin
3693if Data.CoordsIdx = 1
3694then PlotPoint.Y := CoordY(y_r*Sin(x_phi))
3695else PlotPoint.Y := CoordY(y_r);
3696end;
3697
3698case Data.PointStyle of
3699psSquare:
3700begin
3701MoveTo(PlotPoint.X - w, PlotPoint.Y - w);
3702LineTo(PlotPoint.X + w, PlotPoint.Y - w);
3703LineTo(PlotPoint.X + w, PlotPoint.Y + w);
3704LineTo(PlotPoint.X - w, PlotPoint.Y + w);
3705LineTo(PlotPoint.X - w, PlotPoint.Y - w);
3706end;
3707psPlus:
3708begin
3709MoveTo(PlotPoint.X, PlotPoint.Y - w);
3710LineTo(PlotPoint.X, PlotPoint.Y + w +1);
3711MoveTo(PlotPoint.X - w, PlotPoint.Y);
3712LineTo(PlotPoint.X + w, PlotPoint.Y);
3713end;
3714psCross:
3715begin
3716MoveTo(PlotPoint.X + w, PlotPoint.Y - w);
3717LineTo(PlotPoint.X - w, PlotPoint.Y + w +1);
3718MoveTo(PlotPoint.X - w, PlotPoint.Y - w);
3719LineTo(PlotPoint.X + w, PlotPoint.Y + w +1);
3720end;
3721psCircle:
3722Ellipse(PlotPoint.X, PlotPoint.Y, w, w);
3723end;
3724end; { with TPointObject(Points[j]) do... }
3725
3726end;
3727
3728PenColor := Data.PlotColor;
3729PenWidth := Data.PlotWidth;
3730
3731ClearPointList(Plotlist); { clear & free }
3732PlotList := TList.Create;
3733
3734case Data.NumericStyle of
3735nsLinear:
3736begin
3737with TGraphPointObject(ControlPoints[FirstPoint]) do
3738begin
3739if GraphData.Grid.xAxisStyle = asLog
3740then PlotPoint.X := CoordLogX(x_phi)
3741else
3742begin
3743if Data.CoordsIdx = 1
3744then PlotPoint.X := CoordX(y_r*Cos(x_phi))
3745else PlotPoint.X := CoordX(x_phi);
3746end;
3747
3748if GraphData.Grid.yAxisStyle = asLog
3749then PlotPoint.Y := CoordLogY(y_r)
3750else
3751begin
3752if Data.CoordsIdx = 1
3753then PlotPoint.Y := CoordY(y_r*Sin(x_phi))
3754else PlotPoint.Y := CoordY(y_r);
3755end;
3756
3757MoveTo(PlotPoint.X, PlotPoint.Y);
3758end;
3759
3760for j := FirstPoint +1 to LastPoint do
3761with TGraphPointObject(ControlPoints[j]) do
3762begin
3763if GraphData.Grid.xAxisStyle = asLog
3764then PlotPoint.X := CoordLogX(x_phi)
3765else
3766begin
3767if Data.CoordsIdx = 1
3768then PlotPoint.X := CoordX(y_r*Cos(x_phi))
3769else PlotPoint.X := CoordX(x_phi);
3770end;
3771
3772if GraphData.Grid.yAxisStyle = asLog
3773then PlotPoint.Y := CoordLogY(y_r)
3774else
3775begin
3776if Data.CoordsIdx = 1
3777then PlotPoint.Y := CoordY(y_r*Sin(x_phi))
3778else PlotPoint.Y := CoordY(y_r);
3779end;
3780
3781LineTo(PlotPoint.X, PlotPoint.Y);
3782end
3783end; { nsLinear }
3784
3785nsLagrange: if Ordered and (Data.CoordsIdx <> 1) then
3786begin
3787if Data.Extrapolate then
3788begin
3789Start := GraphData.xMin;
3790Stop := GraphData.xMax;
3791end
3792else
3793begin
3794Start := TGraphPointObject(ControlPoints[FirstPoint]).x_phi;
3795Stop := TGraphPointObject(ControlPoints[LastPoint]).x_phi;
3796end;
3797j := TGraphPointObject(ControlPoints[FirstPoint]).PlotPoint.X;
3798k := TGraphPointObject(ControlPoints[LastPoint]).PlotPoint.X;
3799Step := (Stop - Start)/(k - j);
3800vx := Start;
3801while vx <= Stop + Step do
3802begin
3803vy := 0;
3804for j := FirstPoint to LastPoint do
3805begin
3806p := 1;
3807for k := FirstPoint to LastPoint do
3808if j <> k then { if xj = xk then xj - xk = 0 i.e. d = 0 }
3809begin
3810d := TGraphPointObject(ControlPoints[j]).x_phi -
3811TGraphPointObject(ControlPoints[k]).x_phi;
3812a := (vx - TGraphPointObject(ControlPoints[k]).x_phi)/d;
3813p := p*a;
3814end;
3815vy := vy + p*TGraphPointObject(ControlPoints[j]).y_r;
3816end;
3817with PlotList do
3818begin
3819Add(TGraphPointObject.Create(vx, vy));
3820with TGraphPointObject(Items[Count -1]) do
3821begin
3822if GraphData.Grid.xAxisStyle = asLog
3823then PlotPoint.X := CoordLogX(x_phi)
3824else PlotPoint.X := CoordX(x_phi);
3825
3826if GraphData.Grid.yAxisStyle = asLog
3827then PlotPoint.Y := CoordLogY(y_r)
3828else PlotPoint.Y := CoordY(y_r);
3829
3830DrawLine := Count > 1;
3831end;
3832end;
3833vx := vx + Step;
3834end;
3835
3836with GraphData.PlotData do
3837begin
3838PlotWidth := PenWidth;
3839PlotColor := PenColor;
3840end;
3841DrawCartesian(PlotList); { draw the graph }
3842end;
3843
3844nsHermite:
3845
3846begin
3847if ((GraphData.Grid.xAxisStyle = asLog) or
3848(GraphData.Grid.yAxisStyle = asLog)) and
3849(FirstPoint > 0) then Exit;
3850
3851k0 := Data.CurveRate/100;
3852ePoints := TList.Create;
3853if ControlPoints.Count > 1 then
3854begin
3855{ set ePoints; first two ControlPoints k - j = 1 }
3856j := FirstPoint;
3857k := FirstPoint +1;
3858ePoint.x := (TGraphPointObject(ControlPoints[k]).x_phi -
3859TGraphPointObject(ControlPoints[j]).x_phi)*k0;
3860ePoint.y := (TGraphPointObject(ControlPoints[k]).y_r -
3861TGraphPointObject(ControlPoints[j]).y_r)*k0;
3862ePoints.Add(TGraphPointObject.Create(ePoint.x, ePoint.y));
3863{ set ePoints; mid ControlPoints j + 1 - (j - 1) = 2 }
3864for j := FirstPoint +1 to LastPoint -1 do
3865begin
3866ePoint.x := (TGraphPointObject(ControlPoints[j +1]).x_phi -
3867TGraphPointObject(ControlPoints[j -1]).x_phi)*k0;
3868ePoint.y := (TGraphPointObject(ControlPoints[j +1]).y_r -
3869TGraphPointObject(ControlPoints[j -1]).y_r)*k0;
3870ePoints.Add(TGraphPointObject.Create(ePoint.x, ePoint.y));
3871end;
3872{ set ePoints; last two ControlPoints k - j = 1 }
3873j := LastPoint -1;
3874k := LastPoint;
3875ePoint.x := (TGraphPointObject(ControlPoints[k]).x_phi -
3876TGraphPointObject(ControlPoints[j]).x_phi)*k0;
3877ePoint.y := (TGraphPointObject(ControlPoints[k]).y_r -
3878TGraphPointObject(ControlPoints[j]).y_r)*k0;
3879ePoints.Add(TGraphPointObject.Create(ePoint.x, ePoint.y));
3880end;
3881
3882with PlotList do { start PlotList at first control point }
3883begin
3884with TGraphPointObject(ControlPoints[0]) do
3885Add(TGraphPointObject.Create(x_phi, y_r));
3886with TGraphPointObject(Items[Count -1]) do
3887begin
3888if GraphData.Grid.xAxisStyle = asLog
3889then PlotPoint.X := CoordLogX(x_phi)
3890else
3891begin
3892if Data.CoordsIdx = 1
3893then PlotPoint.X := CoordX(y_r*Cos(x_phi))
3894else PlotPoint.X := CoordX(x_phi);
3895end;
3896
3897if GraphData.Grid.yAxisStyle = asLog
3898then PlotPoint.Y := CoordLogY(y_r)
3899else
3900begin
3901if Data.CoordsIdx = 1
3902then PlotPoint.Y := CoordY(y_r*Sin(x_phi))
3903else PlotPoint.Y := CoordY(y_r);
3904end;
3905DrawLine := Count > 1;
3906end;
3907
3908for k := FirstPoint to ControlPoints.Count do
3909if k < ControlPoints.Count -1 then
3910for j := 0 to StepPts -1 do
3911begin
3912with TGraphPointObject(ControlPoints[FirstPoint]) do
3913Add(TGraphPointObject.Create(xp(k, j, i), yp(k, j, i)));
3914with TGraphPointObject(Items[Count -1]) do
3915begin
3916if GraphData.Grid.xAxisStyle = asLog
3917then PlotPoint.X := CoordLogX(x_phi)
3918else
3919begin
3920if Data.CoordsIdx = 1
3921then PlotPoint.X := CoordX(y_r*Cos(x_phi))
3922else PlotPoint.X := CoordX(x_phi);
3923end;
3924
3925if GraphData.Grid.yAxisStyle = asLog
3926then PlotPoint.Y := CoordLogY(y_r)
3927else
3928begin
3929if Data.CoordsIdx = 1
3930then PlotPoint.Y := CoordY(y_r*Sin(x_phi))
3931else PlotPoint.Y := CoordY(y_r);
3932end;
3933DrawLine := Count > 1;
3934end;
3935end;
3936end;
3937
3938with GraphData.PlotData do
3939begin
3940PlotWidth := PenWidth;
3941PlotColor := PenColor;
3942end;
3943
3944DrawCartesian(PlotList); { draw the graph }
3945ClearPointList(ePoints);
3946end;
3947end; { case Data.NumericStyle of }
3948
3949with NumericForm do
3950begin
3951if Visible and (InputRG.ItemIndex > 0) and
3952(CheckListBox.ItemIndex = i) then
3953begin
3954j := CheckListBox.ItemIndex;
3955k := DataListBox.ItemIndex;
3956with TNumericObject(Items.Objects[j]) do
3957begin
3958c := Data.PlotColor;
3959with TGraphPointObject(ControlPoints[k]) do
3960begin
3961vx := x_phi;
3962vy := y_r;
3963end;
3964end;
3965
3966case CoordsRG.ItemIndex of
39670:DrawTarget(vx, vy, c); { Cartesian }
39681:begin { Polar }
3969with TGraphPointObject(ControlPoints[k]) do
3970begin
3971vx := y_r*Cos(x_phi);
3972vy := y_r*Sin(x_phi);
3973DrawTarget(vx, vy, c);
3974Line(CoordX(0), CoordY(0), CoordX(vx), CoordY(vy));
3975end;
3976end;
39772:begin { As Vector }
3978DrawTarget(vx, vy, c);
3979if k > 0 then
3980with TGraphPointObject(ControlPoints[k -1]) do
3981begin
3982vx := x_phi;
3983vy := y_r;
3984DrawTarget(vx, vy, c);
3985end;
3986end;
3987end;
3988end;
3989end;
3990end; { if Points.Count > 0 then... }
3991end; { with TNumericObject(Items.Objects[i]) do if Checked[i] then... }
3992end; { with NumericForm.CheckListBox do if Count > 0 then... }
3993end; { TfxCanvas.DrawNumericData }
3994
3995
3996procedure TfxCanvas.DrawTextBlocks(var rci: TGLRenderContextInfo;
3997var wbf: TGLWindowsBitmapFont);
3998var
3999i, j, k, x, y: integer;
4000
4001begin
4002with TextBlocksForm.BlockListBox do if Count > 0 then
4003begin
4004StopPrimitive;
4005for i := 0 to Count -1 do
4006with TTextDataObject(Items.Objects[i]) do if Checked[i] then
4007begin
4008SetGLWinBitFont(rci, wbf, Data.FontName, Data.FontSize, Data.FontStyle);
4009for j := 0 to Items.Count -1 do if Checked[j] then
4010begin
4011if GraphData.Grid.xAxisStyle = asLog
4012then x := CoordLogX(Data.xLoc)
4013else x := CoordX(Data.xLoc);
4014
4015if GraphData.Grid.yAxisStyle = asLog
4016then y := CoordLogY(Data.yLoc)
4017else y := CoordY(Data.yLoc);
4018
4019for k := 0 to TextLines.Count -1 do
4020with TTextLineObject(TextLines[k])do
4021wbf.TextOut(rci, x, y + k*Data.yInc, Text, Color);
4022end;
4023end;
4024end;
4025with GraphData do SetGLWinBitFont(rci, wbf, FontName, FontSize, FontStyle);
4026SetupFont(rci, wbf);
4027end;
4028
4029procedure TfxCanvas.ClearTextList;
4030var
4031i: integer;
4032
4033begin
4034for i := 0 to TextList.Count -1 do TTextLocObject(TextList[i]).Free;
4035TextList.Free;
4036end;
4037
4038procedure TfxCanvas.ClearPointList(var L: TList);
4039var
4040i: integer;
4041
4042begin
4043if Assigned(L) then
4044begin
4045for i := 0 to L.Count -1 do TGraphPointObject(L[i]).Free;
4046L.Free;
4047L := nil;
4048end;
4049end;
4050
4051function TfxCanvas.SumSegments(var aNeg, aPos: extended): extended;
4052var
4053a: extended; { integral area }
4054h: extended; { step }
4055isOK: Boolean; { OK to draw line }
4056x, x1, x2: extended;
4057y, y1, y2: extended;
4058my: extended;
4059i: integer;
4060m: integer;
4061LastXCoord: integer;
4062
4063begin { SumSegments }
4064if IntegMax = IntegMin then
4065begin
4066Result := 0;
4067Exit;
4068end;
4069
4070if IntegMax < IntegMin then
4071begin
4072a := IntegMax;
4073IntegMax := IntegMin;
4074IntegMin := a;
4075with IntegrateXForm do
4076begin
4077EditIntegMin.Text := FloatToStrF(IntegMin, ffGeneral, 13, 4);
4078EditIntegMax.Text := FloatToStrF(IntegMax, ffGeneral, 13, 4);
4079end;
4080end;
4081
4082h := (IntegMax - IntegMin)/GraphData.IntegCount; { calculate step }
4083a := 0; { initial area = 0 }
4084
4085{ calculate numerical value to be used to display area }
4086x := IntegMin;
4087for i := 0 to GraphData.IntegCount do
4088begin { calculate area using Simpson's rule }
4089{ h/3(y0 + 4y1 + 2y2 + 4y3 +...+ 2y(i-2) + 4y(i-1) + y(i)) }
4090y := EvaluateFunction(x);
4091if not isNaN(y) then
4092begin
4093if odd(i) then m := 4 else
4094if (i > 0) and (i < GraphData.IntegCount) then m := 2 else m := 1;
4095{ sum = (y0 + 4y1 + 2y2 + 4y3 +...+ 2y(i-2) + 4y(i-1) + y(i)) }
4096{ m = 1 4 2 4 2 4 1 }
4097
4098my := m*y; { m*f(x(i)) for i = 0 to Count }
4099a := a + my; { add to sum }
4100if y < 0 then aNeg := aNeg + my else aPos := aPos + my;
4101end;
4102
4103x := x + h; { next step }
4104end; { for i := 0 to IntegCount do... }
4105
4106aNeg := aNeg*h/3;
4107aPos := aPos*h/3;
4108Result := aPos + aNeg;
4109{-------------------------------------------------------------}
4110a := 0; { initial area = 0 }
4111LastXCoord := MaxInt;
4112
4113{ calculate value for each segment to be used to plot integral }
4114IntegYMin := 1.1e308;
4115IntegYMax := -IntegYMin;
4116
4117x := IntegMin; { start }
4118x1 := x + h; { one step }
4119x2 := x1 + h; { two steps }
4120
4121for i := 0 to GraphData.IntegCount div 2 do
4122begin
4123isOK := true;
4124y := EvaluateFunction(x);
4125
4126if isNaN(y) then
4127begin
4128isOK := false;
4129y := 0;
4130end;
4131
4132y1 := EvaluateFunction(x1);
4133if isNaN(y1) then
4134begin
4135isOK := false;
4136y1 := 0;
4137end;
4138
4139y2 := EvaluateFunction(x2);
4140if isNaN(y2) then
4141begin
4142isOK := false;
4143y2 := 0;
4144end;
4145
4146a := a + h*(y + 4*y1 + y2)/3;
4147{ Simpson's rule h/3(y + 4y1 + y2) }
4148y := a + IntegConst;
4149
4150if x1 <= IntegMax then
4151begin
4152if y < IntegYMin then IntegYMin := y;
4153if y > IntegYMax then IntegYMax := y;
4154{ only add a GraphPoint for each pixel horizontally }
4155if LastXCoord <> CoordX(x1) then
4156begin
4157IntegList.Add(TGraphPointObject.Create(x1, y));
4158TGraphPointObject(
4159IntegList[IntegList.Count -1]).DrawLine := isOK;
4160end;
4161LastXCoord := CoordX(x1)
4162end;
4163x := x2; { increase two steps }
4164x1 := x + h; { increase one step }
4165x2 := x1 + h; { increase one step }
4166end;
4167
4168i := 0; { get IntegXMin }
4169with TGraphPointObject(IntegList[i]) do
4170begin
4171isOK := DrawLine;
4172IntegXMin := x_phi;
4173end;
4174
4175while not isOK and (i < IntegList.Count) do
4176begin
4177with TGraphPointObject(IntegList[i]) do isOK := DrawLine;
4178Inc(i);
4179end;
4180if i > 0 then Dec(i);
4181with TGraphPointObject(IntegList[i]) do IntegXMin := x_phi;
4182
4183
4184i := IntegList.Count -1; { get IntegXMax }
4185with TGraphPointObject(IntegList[i]) do
4186begin
4187isOK := DrawLine;
4188IntegXMax := x_phi;
4189end;
4190
4191while not isOK and (i > 0) do
4192begin
4193with TGraphPointObject(IntegList[i]) do isOK := DrawLine;
4194Dec(i);
4195end;
4196if i < IntegList.Count -1 then Inc(i);
4197with TGraphPointObject(IntegList[i]) do IntegXMax := x_phi;
4198end;
4199
4200function TfxCanvas.SumYSegments(var aNeg, aPos: Extended): extended;
4201var
4202a: extended; { integral area }
4203h: extended; { step }
4204x1, x2, y1, y2: extended;
4205i: integer;
4206LastYCoord: integer;
4207
4208begin { SumYSegments }
4209if IntegMax = IntegMin then
4210begin
4211Result := 0;
4212Exit;
4213end;
4214
4215if IntegMax < IntegMin then
4216begin
4217a := IntegMax;
4218IntegMax := IntegMin;
4219IntegMin := a;
4220with IntegrateYForm do
4221begin
4222EditIntegMin.Text := FloatToStrF(IntegMin, ffGeneral, 13, 4);
4223EditIntegMax.Text := FloatToStrF(IntegMax, ffGeneral, 13, 4);
4224end;
4225end;
4226
4227h := (IntegMax - IntegMin)/GraphData.IntegCount; { calculate step }
4228a := 0; { initial area = 0 }
4229
4230LastYCoord := MaxInt;
4231aNeg := a;
4232aPos := a;
4233
4234x1 := IntegMin;
4235x2 := x1 + h;
4236y1 := EvaluateFunction(x1);
4237y2 := EvaluateFunction(x2);
4238
4239for i := 0 to GraphData.IntegCount do
4240begin
4241if not(isNAN(y1) or isNAN(y2)) then
4242begin
4243a := abs(y2 - y1)*(x1 + x2)/2;
4244if (x1 < 0) and (x2 <= 0) then aNeg := aNeg + a else aPos := aPos + a;
4245{ only add a GraphPoint for each pixel vertically }
4246if LastYCoord <> CoordY(y1) then
4247IntegList.Add(TGraphPointObject.Create(x1, y1));
4248TGraphPointObject(IntegList[IntegList.Count -1]).DrawLine := True;
4249end
4250else
4251begin
4252{ only add a GraphPoint for each pixel vertically }
4253if LastYCoord <> CoordY(y1) then
4254IntegList.Add(TGraphPointObject.Create(x1, y1));
4255TGraphPointObject(IntegList[IntegList.Count -1]).DrawLine := False;
4256end;
4257LastYCoord := CoordY(y1);
4258
4259x1 := x2;
4260x2 := x2 + h;
4261y1 := y2;
4262y2 := EvaluateFunction(x2);
4263end;
4264Result := aPos + aNeg;
4265end; { SumYSegments }
4266
4267procedure TfxCanvas.QuadVertices(x, y, xRadius, yRadius: Single;
4268q1, q2, q3, q4: Boolean);
4269var
4270i, n: Integer;
4271s, c: TSingleArray;
4272
4273begin
4274n := Round(MaxFloat(xRadius, yRadius) * 0.1) + 5;
4275SetLength(s, n);
4276SetLength(c, n);
4277Dec(n);
4278PrepareSinCosCache(s, c, 0, 90);
4279ScaleFloatArray(s, yRadius);
4280ScaleFloatArray(c, xRadius);
4281{ first quadrant; top right }
4282if q1 then for i := 0 to n do glVertex2f(x + c[i], y - s[i]);
4283
4284{ second quadrant; top left }
4285if q2 then for i := n - 1 downto 0 do glVertex2f(x - c[i], y - s[i]);
4286
4287{ third quadrant; bottom left }
4288if q3 then for i := 1 to n do glVertex2f(x - c[i], y + s[i]);
4289
4290{ fourth quadrant; bottom right }
4291if q4 then for i := n - 1 downto 0 do glVertex2f(x + c[i], y + s[i]);
4292end;
4293
4294procedure TfxCanvas.FillEllipseBB(const x1, y1, x2, y2: Integer);
4295begin
4296FillEllipse((x1 + x2)*0.5, (y1 + y2)*0.5, Abs(x2 - x1)*0.5, Abs(y2 - y1)*0.5);
4297end;
4298
4299procedure TfxCanvas.FillEllipseBB(const x1, y1, x2, y2: Single);
4300begin
4301FillEllipse((x1 + x2)*0.5, (y1 + y2)*0.5, Abs(x2 - x1)*0.5, Abs(y2 - y1)*0.5);
4302end;
4303
4304procedure TfxCanvas.FillQuadrants(const x, y: Integer;
4305const xRadius, yRadius: Single;
4306q1, q2, q3, q4: Boolean);
4307begin
4308StartPrimitive(GL_TRIANGLE_FAN);
4309glVertex2f(x, y); { not really necessary, but may help with memory stride }
4310QuadVertices(x, y, xRadius, yRadius, q1, q2, q3, q4);
4311StopPrimitive;
4312end;
4313
4314procedure TfxCanvas.FillQuadrantsBB(const x1, y1, x2, y2: Integer;
4315q1, q2, q3, q4: Boolean);
4316begin
4317FillQuadrants((x1 + x2) div 2, (y1 + y2) div 2,
4318Abs(x1 - x2) div 2, Abs(y1 - y2) div 2, q1, q2, q3, q4);
4319end;
4320
4321procedure TfxCanvas.StartRadialFill(const x, y: integer);
4322begin
4323StartPrimitive(GL_TRIANGLE_FAN);
4324glVertex2f(x, y);
4325end;
4326
4327procedure TfxCanvas.FillSector(x, y: Integer);
4328begin
4329glVertex2f(x, y);
4330end;
4331
4332procedure TfxCanvas.StopRadialFill;
4333begin
4334StopPrimitive;
4335end;
4336
4337procedure TfxCanvas.SetupFont(var rci: TGLRenderContextInfo;
4338var wbf: TGLWindowsBitmapFont);
4339begin
4340wbf.TextOut(rci, -10, -30, 'y = f(x)', clRed);
4341CharW := wbf.GetCharWidth('M');
4342CharH := wbf.CharHeight;
4343end;
4344
4345procedure TfxCanvas.SetGLWinBitFont(var rci: TGLRenderContextInfo;
4346var wbf: TGLWindowsBitmapFont;
4347Nm: string; Sz: Integer; St: TFontStyles);
4348begin
4349with wbf.Font do
4350begin
4351Name := Nm;
4352Size := Sz;
4353Style := St;
4354end;
4355end;
4356
4357procedure TfxCanvas.xAxisGradsCalc(var wbf: TGLWindowsBitmapFont);
4358var
4359xCoord: integer;
4360
4361begin
4362CharW := wbf.GetCharWidth('M');
4363CharH := wbf.CharHeight;
4364
4365dxGrad := 0.1;
4366dx10Grad := 1;
4367
4368with GraphData do
4369begin
4370xCoord := CoordX(xMin + dxGrad);
4371
4372{ major X axis graduation lengths }
4373while (xCoord > xMajorGrad) or (xCoord < 0) do
4374begin
4375dxGrad := dxGrad/10;
4376xCoord := CoordX(xMin + dxGrad);
4377end;
4378{ minor X axis graduation lengths }
4379while xCoord < xMinorGrad do
4380begin
4381dxGrad := dxGrad*10;
4382xCoord := CoordX(xMin + dxGrad);
4383end;
4384end;
4385
4386dx10Grad := 10*dxGrad; { major x graduation space }
4387if dxGrad < 1 { calculate number of digits }
4388then xDigits := round(-log10(dxGrad)) -1
4389else xDigits := round(log10(dxGrad)) +1;
4390end;
4391
4392procedure TfxCanvas.yAxisGradsCalc(var wbf: TGLWindowsBitmapFont);
4393var
4394yCoord: integer;
4395
4396begin
4397CharW := wbf.GetCharWidth('M');
4398CharH := wbf.CharHeight;
4399
4400dyGrad := 0.1;
4401dy10Grad := 1;
4402
4403with GraphData do
4404begin
4405yCoord := CoordY(yMin) - CoordY(yMin + dyGrad);
4406{ major Y axis graduation lengths }
4407while (yCoord > yMajorGrad) or (yCoord < 0) do
4408begin
4409dyGrad := dyGrad/10;
4410yCoord := CoordY(yMin) - CoordY(yMin + dyGrad);
4411end;
4412{ minor Y axis graduation lengths }
4413while yCoord < yMinorGrad do
4414begin
4415dyGrad := dyGrad*10;
4416yCoord := CoordY(yMin) - CoordY(yMin + dyGrad);
4417end;
4418end;
4419
4420dy10Grad := 10*dyGrad; { major y graduation space }
4421if dyGrad < 1 { calculate number of digits }
4422then yDigits := round(-log10(dyGrad)) -1
4423else yDigits := round(log10(dyGrad)) +1;
4424end;
4425
4426procedure TfxCanvas.DrawTextList(var rci: TGLRenderContextInfo; L: TList;
4427var wbf: TGLWindowsBitmapFont);
4428var
4429i: integer;
4430t: TTextLocObject;
4431
4432begin
4433StopPrimitive;
4434for i := 0 to L.Count -1 do
4435begin
4436t := TTextLocObject(L.Items[i]);
4437wbf.TextOut(rci, t.xLoc, t.yLoc, t.TextString, t.TextColor);
4438end;
4439end;
4440
4441procedure TfxCanvas.DrawAxes;
4442begin
4443with GraphData.Grid do
4444begin
4445case GridStyle of
4446gsCartesian:
4447begin
4448if xAxisStyle = asLog then DrawXGridLog else DrawXGridLinear;
4449if yAxisStyle = asLog then DrawYGridLog else DrawYGridLinear;
4450end;
4451gsPolar:
4452DrawPolarGrid;
4453end;
4454if xAxisStyle = asLog then DrawXAxisLog else DrawXAxisLinear;
4455if yAxisStyle = asLog then DrawYAxisLog else DrawYAxisLinear;
4456end;
4457end;
4458
4459procedure TfxCanvas.DrawFunctions;
4460var
4461i: integer;
4462
4463begin
4464with FunctionsForm.CheckListBox do
4465begin
4466for i := 0 to Items.Count -1 do if Checked[i] then
4467begin
4468GraphData.PlotData := TPlotDataObject(Items.Objects[i]).Data;
4469ClearPointList(PlotList);
4470PlotList := TList.Create;
4471
4472with FxParser do
4473begin
4474if i > 0 then Calculus.Free;
4475
4476ErrorByte := 0;
4477MainForm.StatusBar.Panels[2].Text := '';
4478with GraphData.PlotData do
4479Calculus := Compile(AnsiLowerCase(FunctStr), ErrorByte);
4480
4481if ErrorByte > 0 then
4482begin
4483with MainForm.StatusBar.Panels[2] do
4484case ErrorByte of
44851:Text := 'Check Brackets for "'+
4486GraphData.PlotData.FunctStr+'"';
44872:Text := 'Unable to Parse "'+
4488GraphData.PlotData.FunctStr+'"';
4489end;
4490end;
4491end;
4492PlotFunction(i = ItemIndex); { Selected := i = ItemIndex }
4493end;
4494end;
4495end;
4496
4497end.
4498