MathgeomGLS

Форк
0
/
Graf.Canvas1d.pas 
4497 строк · 119.4 Кб
1
unit Graf.Canvas1d;
2

3
interface
4

5
uses
6
  Winapi.OpenGL,
7
  System.Types,
8
  System.Classes,
9
  System.SysUtils,
10
  System.Math,
11
  Vcl.Dialogs,
12
  Vcl.Graphics,
13

14
  GLS.OpenGLTokens,
15
  GLS.Context,
16
  GLS.VectorTypes,
17
  GLS.Canvas,
18
  GLS.VectorGeometry,
19
  GLS.Color,
20
  
21
  GLS.State,
22
  GLS.RenderContextInfo,
23
  GLS.WindowsFont,
24

25
  Graf.Global1d,
26
  Graf.Parser1d,
27
  faPrint,
28
  faFunc1d;
29

30
type
31
  TTextLocObject = class(TObject)
32
    constructor Create(x, y: integer; c: TColor; T: string);
33
    destructor Destroy; override;
34
  private
35
  public
36
    TextString: string;
37
    TextColor: integer;
38
    xLoc: integer;
39
    yLoc: integer;
40
  end;
41

42
  TfxCanvas = class(TGLCanvas)
43
  private
44
     
45
    CharW, CharH: integer;  { GLWinBitFont width and height  }
46
    dxGrad, dyGrad: extended;
47
    dx10Grad, dy10Grad: extended;
48
    IntegXMax, IntegXMin: extended;
49
    IntegYMax, IntegYMin: extended;
50
    xDigits, yDigits: integer;
51
    PlotList: TList;        { used to hold function TGraphPointObjects }
52
    yfx1List: TList;        { used to hold y = f'(x) TGraphPointObjects }
53
    yfx2List: TList;        { used to hold y = f"(x) TGraphPointObjects }
54
    IntegList: TList;       { used to hold Integral TGraphPointObjects }
55
    SectorList: TList;      { used to hold polar Integral sectors }
56
    FxParser: TFxParser;
57
    function FormatValue(const n: integer; const v, dv: extended): string;
58
    function CoordX(x: extended): integer;
59
    function CoordY(y: extended): integer;
60
    function CoordLogX(x: extended): integer;
61
    function CoordLogY(y: extended): integer;
62
    function EvaluateFunction(const x: extended): extended;
63
    function ValueX(const x: integer): extended;
64
    function ValueLogX(const x: integer): extended;
65
    procedure AddXAxisText(x: extended;
66
              xCoord, yCoord, halfWd: integer; atTop: Boolean);
67
    procedure AddYAxisText(y: extended;
68
              xCoord, yCoord, halfWd: integer; atRight: Boolean);
69
    procedure DrawXGridLinear;
70
    procedure DrawYGridLinear;
71
    procedure DrawXGridLog;
72
    procedure DrawYGridLog;
73
    procedure DrawPolarGrid;
74
    procedure DrawXAxisLinear;
75
    procedure DrawYAxisLinear;
76
    procedure DrawXAxisLog;
77
    procedure DrawYAxisLog;
78
    procedure PlotFunction(Selected: Boolean);
79
    procedure PlotAsCartesian(Selected: Boolean);
80
    procedure PlotAsPolar(Selected: Boolean);
81
    procedure PopulateCartesian(var L: TList);
82
    procedure PopulateCartesianLogX(var L: TList);
83
    procedure PopulateCartesianLogY(var L: TList);
84
    procedure PopulateCartesianLogXY(var L: TList);
85
    procedure PopulatePolar(var L: TList);
86
    procedure PopulateDerivCartesian(var Ls, L: TList);
87
    procedure PopulateDerivPolar(var Ls, L: TList);
88
    procedure NoNumberCartesian(var L: Tlist; const P, C: TGraphPoint; const i: integer);
89
    procedure NoNumberDerivCartesian(var L: Tlist; const P, C: TGraphPoint; const i: integer);
90
    procedure NoNumberPolar(var L: Tlist; var P, C: TGraphPoint; const i: integer);
91
    procedure InfinityCartesian(var L: Tlist; var P, C: TGraphPoint; const i: integer);
92
    procedure InfinityPolar(var L: Tlist; var P, C: TGraphPoint; const i: integer);
93
    function LineIsValid(var P, C: TGraphPoint): Boolean;
94
    procedure AnalyseCartesian(var L: TList);
95
    procedure AnalyseDerivCartesian(var L: TList);
96
    procedure AnalysePolar(var L: TList);
97
    procedure DrawCartesian(var L: TList);
98
    procedure DrawPolar(var L: TList);
99
    procedure Draw_yfx1(var L: Tlist);
100
    procedure Draw_yfx2(Var L: TList);
101
    procedure IntegrateCartesian;
102
    procedure IntegratePolar;
103
    procedure IntegrateYCartesian;
104
    procedure IntegrateBetweenFunctions;
105
    procedure IntegrateVolumeX;
106
    procedure IntegrateVolumeY;
107
    procedure FindfxValues(const y: extended);
108
    procedure DrawfxPoints;
109
    procedure Findfx1Values(const dy: extended);
110
    procedure Drawfx1Points;
111
    procedure Findfx2Values(const d2y: extended);
112
    procedure Drawfx2Points;
113
    procedure DrawCartesianCoordinates;
114
    procedure DrawPolarCoordinates;
115
    procedure ClearTextList;
116
    procedure ClearPointList(var L: TList);
117
    function SumSegments(var aNeg, aPos: extended): extended;
118
    function SumYSegments(var aNeg, aPos: extended): extended;
119
  protected
120
    procedure QuadVertices(x, y, xRadius, yRadius: Single;
121
                           q1, q2, q3, q4: Boolean);
122
  public
123
    TextList: TList;
124
    constructor Create(bufferSizeX, bufferSizeY: Integer); overload;
125
    destructor Destroy; override;
126
  { Draws a filled ellipse with (x1,y1)-(x2, y2) bounding rectangle }
127
    procedure FillEllipseBB(const x1, y1, x2, y2: Integer); overload;
128
    procedure FillEllipseBB(const x1, y1, x2, y2: Single); overload;
129
    procedure FillQuadrants(const x, y: Integer;
130
                            const xRadius, yRadius: Single;
131
                                  q1, q2, q3, q4: Boolean);
132
    procedure FillQuadrantsBB(const x1, y1, x2, y2: Integer;
133
                                    q1, q2, q3, q4: Boolean);
134
    procedure StartRadialFill(const x, y: Integer);
135
    procedure FillSector(x, y: Integer);
136
    procedure StopRadialFill;
137
    procedure SetupFont(var rci: TGLRenderContextInfo;
138
                        var wbf: TGLWindowsBitmapFont);
139
    procedure SetGLWinBitFont(var rci: TGLRenderContextInfo;
140
                              var wbf: TGLWindowsBitmapFont;
141
                  Nm: string; Sz: integer; St: TFontStyles);
142
    procedure AddFunctionLabelsText;
143
    procedure xAxisGradsCalc(var wbf: TGLWindowsBitmapFont);
144
    procedure yAxisGradsCalc(var wbf: TGLWindowsBitmapFont);
145
    procedure DrawAxes;
146
    procedure DrawTextList(var rci: TGLRenderContextInfo; L: TList;
147
                           var wbf: TGLWindowsBitmapFont);
148
    procedure DrawFunctions;
149
    procedure DrawNumericData;
150
    procedure DrawTextBlocks(var rci: TGLRenderContextInfo;
151
                             var wbf: TGLWindowsBitmapFont);
152
  end;
153

154
//======================================================================
155
implementation
156
//======================================================================
157

158
uses
159
  faGraf1D,
160
  faNumeric,
161
  faTextBlocks,
162
  faIntegrateX,
163
  faIntegrateY,
164
  faBetween,
165
  faVolumeX,
166
  faVolumeY,
167
  faBitmap,
168
  faValueX,
169
  faValueX1,
170
  faValueX2;
171

172
constructor TTextLocObject.Create(x, y: integer; c: TColor; T: string);
173
begin
174
  inherited Create;
175
  xLoc := x;
176
  yLoc := y;
177
  TextColor := c;
178
  TextString := T;
179
end;
180

181
destructor TTextLocObject.Destroy;
182
begin
183
  inherited Destroy;
184
end;
185

186
constructor TfxCanvas.Create(bufferSizeX, bufferSizeY: Integer);
187
begin                                        inherited;
188
  TextList := TList.Create;
189
  PlotList := TList.Create;
190
  FxParser := TFxParser.Create(0);
191
end;
192

193
destructor TfxCanvas.Destroy;
194
begin
195
  ClearTextList;
196
  ClearPointList(Plotlist);
197

198
  with FxParser do
199
  begin
200
    Calculus.Free;
201
    Calculus := nil;
202
    Free;
203
  end;
204
  inherited;
205
end;
206

207
function TfxCanvas.FormatValue(const n: integer; const v, dv: Extended): string;
208
var
209
  s: string;
210
  d: integer;
211

212
begin
213
  d := 1;
214
  if n > 3 then  // decide which format to use
215
  begin
216
    Result := FloatToStrF(v, ffExponent, d, 1);
217
    s := FloatToStrF(v + dv, ffExponent, d, 1);
218

219
    while Result = s do
220
    begin
221
      Inc(d);
222
      Result := FloatToStrF(v, ffExponent, d, 1);
223
      s := FloatToStrF(v + dv, ffExponent, d, 1);
224
    end;
225
    Dec(d);
226

227
    Result := FloatToStrF(v, ffExponent, d, 1);
228
  end
229
  else Result := FloatToStrF(v, ffGeneral, 6, n);
230
end;
231

232
// linear X coordinate
233
function TfxCanvas.CoordX(x: extended): integer;
234
begin
235
  Result := round(CanvasSizeX*(x - GraphData.xMin)/(GraphData.xMax - GraphData.xMin));
236
end;
237

238
// linear Y coordinate
239
function TfxCanvas.CoordY(y: extended): integer;
240
begin
241
  Result := CanvasSizeY -
242
    round(CanvasSizeY*(y - GraphData.yMin)/(GraphData.yMax - GraphData.yMin));
243
end;
244

245
// log X coordinate
246
function TfxCanvas.CoordLogX(x: Extended): integer;
247
begin
248
  Result := round(CanvasSizeX*(Log10(x)-
249
    Log10(GraphData.xMin))/(Log10(GraphData.xMax)-Log10(GraphData.xMin)));
250
end;
251

252
// log Y coordinate
253
function TfxCanvas.CoordLogY(y: Extended): integer;
254
begin
255
  Result := CanvasSizeY -
256
    round(CanvasSizeY*(Log10(y)-Log10(GraphData.yMin))/(Log10(GraphData.yMax)-Log10(GraphData.yMin)));
257
end;
258

259
function TfxCanvas.EvaluateFunction(const x: extended): extended;
260
begin
261
  with FxParser do
262
  if Assigned(Calculus) then
263
  try
264
    VarX.Value := x;
265
    Result := Calculus.Eval;
266
  except
267
    Result := NaN;
268
  end
269
  else Result := 0;
270
end;
271

272
function TfxCanvas.ValueX(const x: integer): extended;
273
begin
274
  with GraphData do Result := xMin + x*(xMax - xMin)/CanvasSizeX;
275
end;
276

277
function TfxCanvas.ValueLogX(const x: integer): extended;
278
var
279
  LogMin, a: extended;
280

281
begin
282
  with GraphData do
283
  begin
284
    LogMin := Log10(xMin);
285
    a := LogMin + x*(Log10(xMax) - LogMin)/CanvasSizeX;
286
  end;
287
  Result := Power(10, a);
288
end;
289

290
procedure TfxCanvas.AddXAxisText(x: extended;
291
                     xCoord, yCoord, halfWd: integer; atTop: Boolean);
292
var
293
  s: string;
294

295
begin
296
  s := FormatValue(xDigits, x, dxGrad );
297

298
  with GraphData do
299
  begin
300
    if Grid.GridStyle = gsCartesian then  // Cartesian grid drawn
301
    begin
302
      if atTop
303
      then TextList.Add(TTextLocObject.Create(
304
                        xCoord + 2*CharW div 3 + halfWd,
305
                        8 + AxisWidth, xAxisColor, s))
306
      else TextList.Add(TTextLocObject.Create(
307
                        xCoord + 2*CharW div 3 + halfWd,
308
                        yCoord - 8 - CharH - AxisWidth ,xAxisColor, s));
309
    end
310
    else
311
    begin
312
      if atTop
313
      then TextList.Add(TTextLocObject.Create(
314
                        xCoord - CharW div 3,
315
                        15 + halfWd, xAxisColor, s))
316
      else TextList.Add(TTextLocObject.Create(
317
                        xCoord - CharW div 3,
318
                        yCoord - 15 - CharH - halfWd, xAxisColor, s));
319
    end;
320
  end;
321
end;
322

323
procedure TfxCanvas.AddYAxisText(y: extended;
324
                   xCoord, yCoord, halfWd: integer; atRight: Boolean);
325
var
326
  s: string;
327

328

329
begin
330
  s := FormatValue(yDigits, y, dyGrad);
331

332
  with GraphData do
333
  begin
334
    if Grid.GridStyle = gsCartesian then  { Cartesian grid drawn }
335
    begin
336
      if atRight
337
      then TextList.Add(TTextLocObject.Create(
338
           CanvasSizeX - Length(s)*CharW - AxisWidth - 5,
339
           yCoord - 3*CharH div 2 - halfWd, yAxisColor, s)) { at right }
340
      else TextList.Add(TTextLocObject.Create(xCoord + 2*CharW + halfWd,
341
           yCoord - 3*CharH div 2 - halfWd, yAxisColor, s));
342
    end
343
    else
344
    begin
345
      if atRight
346
      then TextList.Add(TTextLocObject.Create(
347
           CanvasSizeX - Length(s)*CharW - AxisWidth - 15,
348
           yCoord - 7*CharH div 8, yAxisColor, s))           { at right }
349
      else TextList.Add(TTextLocObject.Create(xCoord + halfWd + 25,
350
           yCoord - 7*CharH div 8, yAxisColor, s));
351
    end;
352
  end;
353
end;
354

355
procedure TfxCanvas.AddFunctionLabelsText;
356
var
357
  i: integer;
358
  x, y: integer;
359
  LabelStr: string;
360

361
begin
362
  with FunctionsForm.CheckListBox do
363
  begin
364
    for i := 0 to Items.Count -1 do if Checked[i] then
365
    begin
366
      with GraphData do
367
      begin
368
        PlotData := TPlotDataObject(Items.Objects[i]).Data;
369
        if Plotdata.ShowLabel and
370
          (PlotData.xLabel > xMin) and (PlotData.xLabel < xMax) and
371
          (PlotData.yLabel > yMin) and (PlotData.yLabel < yMax) then
372
        begin
373
          if PlotData.TextStr = '' then LabelStr := ''
374
          else if PlotData.PlotAsFx
375
          then LabelStr := 'y = '+PlotData.TextStr
376
          else LabelStr := 'r = '+PlotData.TextStr;
377

378
          if Grid.xAxisStyle = asLog
379
          then x := CoordLogX(PlotData.xLabel)
380
          else x := CoordX(PlotData.xLabel);
381

382
          if Grid.yAxisStyle = asLog
383
          then y := CoordLogY(PlotData.yLabel)
384
          else y := CoordY(PlotData.yLabel);
385

386
          TextList.Add(TTextLocObject.Create(x, y,
387
                       PlotData.PlotColor, LabelStr));
388
        end;
389
      end;
390
    end;
391
    GraphData.PlotData := TPlotDataObject(Items.Objects[ItemIndex]).Data;
392
  end;
393
end;
394

395
procedure TfxCanvas.DrawXGridLinear;
396
var
397
  xO, xCoord, c: integer;
398
  atRight: Boolean;
399
  x: extended;
400
  yMinCoord, yMaxCoord: integer;
401

402
begin
403
  with GraphData do
404
  begin
405
    yMinCoord := CoordY(yMin);
406
    yMaxCoord := CoordY(yMax);
407

408
    xO := CoordX(0);                       { x origin, i.e. y axis }
409
    atRight := (xO >= CanvasSizeX - 6*CharW - AxisWidth div 2);
410

411
    x := trunc(xMin/dx10Grad)*dx10Grad;
412
    c := round((xMin - x)/dxGrad);
413
    x := x + c*dxGrad;
414

415
    if c < 0 then Inc(c, 10);
416

417
    while x < xMax do
418
    begin
419
      if c mod 10 = 0 then
420
      begin
421
        PenColor := xAxisColor;
422
        PenWidth := MajorWidth;
423
      end
424
      else
425
      begin
426
        PenColor := GridColor;
427
        PenWidth := MinorWidth;
428
      end;
429

430
      xCoord := CoordX(x);
431

432
      if (abs(xCoord - xO) > 2) or atRight then
433
      begin
434
        MoveTo(xCoord, yMinCoord);
435
        LineTo(xCoord, yMaxCoord);
436
      end;
437

438
      x := x + dxGrad;
439
      Inc(c);
440
    end;
441
  end;
442
end;
443

444
procedure TfxCanvas.DrawYGridLinear;
445
var
446
  yO, yCoord, c: integer;
447
  atTop: Boolean;
448
  y: extended;
449
  xMinCoord, xMaxCoord: integer;
450

451
begin
452
  with GraphData do
453
  begin
454
    xMinCoord := CoordX(xMin);
455
    xMaxCoord := CoordX(xMax);
456

457
    yO := CoordY(0);                       { y origin, i.e. x axis }
458
    atTop := (yO <= 2*CharH + AxisWidth);
459

460
    y := trunc(yMin/dy10Grad)*dy10Grad;
461
    c := round((yMin - y)/dyGrad);
462
    y := y + c*dyGrad;
463

464
    if c < 0 then Inc(c, 10);
465

466
    while y < yMax do
467
    begin
468
      if c mod 10 = 0 then
469
      begin
470
        PenColor := yAxisColor;
471
        PenWidth := MajorWidth;
472
      end
473
      else
474
      begin
475
        PenColor := GridColor;
476
        PenWidth := MinorWidth;
477
      end;
478

479
      yCoord := CoordY(y);
480

481
      if (abs(yCoord - yO) > 2) or atTop then
482
      begin
483
        MoveTo(xMinCoord, yCoord);
484
        LineTo(xMaxCoord, yCoord);
485
      end;
486

487
      y := y + dyGrad;
488
      Inc(c);
489
    end;
490
  end;
491
end;
492

493
procedure TfxCanvas.DrawXGridLog;
494
var
495
  xCoord, ixCoord, yMinCoord, yMaxCoord, i: integer;
496
  x, dx: extended;
497

498
begin
499
  with GraphData do
500
  begin
501
    yMinCoord := CoordY(yMin);
502
    yMaxCoord := CoordY(yMax);
503
    dx := 10*dx10Grad;
504
    xCoord := CoordLogX(dx);
505
    while xCoord > 0 do
506
    begin
507
      PenColor := xAxisColor;
508
      PenWidth := MajorWidth;
509
      MoveTo(xCoord, yMinCoord);
510
      LineTo(xCoord, yMaxCoord);
511
      x := dx;
512
      PenColor := GridColor;
513
      PenWidth := MinorWidth;
514
      for i := 2 to 9 do
515
      begin
516
        x := x + dx;
517
        if x < xMax then
518
        begin
519
          ixCoord := CoordLogX(x);
520
          MoveTo(ixCoord, yMinCoord);
521
          LineTo(ixCoord, yMaxCoord);
522
        end;
523
      end;
524
      dx := dx/10;
525
      xCoord := CoordLogX(dx);
526
    end;
527
    x := dx;
528
    for i := 2 to 9 do
529
    begin
530
      x := x + dx;
531
      if x > xMin then
532
      begin
533
        ixCoord := CoordLogX(x);
534
        MoveTo(ixCoord, yMinCoord);
535
        LineTo(ixCoord, yMaxCoord);
536
      end;
537
    end;
538
  end;
539
end;
540

541
procedure TfxCanvas.DrawYGridLog;
542
var
543
  yCoord, iyCoord, xMinCoord, xMaxCoord, i: integer;
544
  y, dy: extended;
545

546
begin
547
  with GraphData do
548
  begin
549
    xMinCoord := CoordX(xMin);
550
    xMaxCoord := CoordX(xMax);
551
    dy := 10*dy10Grad;
552
    yCoord := CoordLogY(dy);
553
    while yCoord < CanvasSizeY do
554
    begin
555
      PenColor := yAxisColor;
556
      PenWidth := MajorWidth;
557
      MoveTo(xMinCoord, yCoord);
558
      LineTo(xMaxCoord, yCoord);
559
      y := dy;
560
      PenColor := GridColor;
561
      PenWidth := MinorWidth;
562
      for i := 2 to 9 do
563
      begin
564
        y := y + dy;
565
        if y < yMax then
566
        begin
567
          iyCoord := CoordLogy(y);
568
          MoveTo(xMinCoord, iyCoord);
569
          LineTo(xMaxCoord, iyCoord);
570
        end;
571
      end;
572
      dy := dy/10;
573
      yCoord := CoordLogY(dy);
574
    end;
575
    y := dy;
576
    for i := 2 to 9 do
577
    begin
578
      y := y + dy;
579
      if y > yMin then
580
      begin
581
        iyCoord := CoordLogy(y);
582
        MoveTo(xMinCoord, iyCoord);
583
        LineTo(xMaxCoord, iyCoord);
584
      end;
585
    end;
586
  end;
587
end;
588

589
procedure TfxCanvas.DrawPolarGrid;
590
var
591
  rMax, r, dr: extended;
592
  dx, dy: extended;
593

594
const
595
  MaxR = $2000;
596
  dMax = $700;
597

598
begin
599
  with GraphData do
600
  begin
601
    PenColor := GridColor;
602
    PenWidth := MinorWidth;
603
    rMax := 0;
604
    dx := xMax - xMin;
605
    dy := yMax - yMin;
606

607
    r := Hypot(xMin, yMin);
608
    if r > rMax then rMax := r;
609

610
    r := Hypot(xMin, yMax);
611
    if r > rMax then rMax := r;
612

613
    r := Hypot(xMax, yMax);
614
    if r > rMax then rMax := r;
615

616
    r := Hypot(xMax, yMin);
617
    if r > rMax then rMax := r;
618
  end;
619

620
  r := trunc(rMax/dx10Grad)*dx10Grad;
621
  dr := dxGrad;
622

623
                { major X axis graduation lengths }
624
  while rMax/dr > GraphData.xMajorGrad do dr := dr*10;
625

626
  if (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
629
  begin
630
    while r < rMax - 2*dr  do r := r + dr;
631
    while r > 0 do
632
    begin
633
      EllipseBB(CoordX(-r),CoordY(-r),
634
                CoordX(r)+1,CoordY(r)-1);
635
      r := r - dr;
636
    end;
637
  end
638
end;
639

640
procedure TfxCanvas.DrawXAxisLinear;
641
var
642
  halfWd: integer;
643
  xCoord, yCoord: integer;               { holds screen coordinate location }
644
  xO: integer;
645
  x: extended;
646
  c: integer;                                        { for graduation marks }
647
  dCoord: integer;
648
  atTop: Boolean;
649

650
begin
651
  with GraphData do
652
  begin
653
    halfWd := AxisWidth div 2;
654
    yCoord := CoordY(0);                   { coordinate for x axis }
655
    xO := CoordX(0);                       { x origin, i.e. y axis }
656
  { if GridStyle = gsPolar the xAxis may be off canvas
657
    otherwise it will be displayed at the top or bottom of canvas }
658
    if (Grid.GridStyle in [gsAxes, gsCartesian]) or
659
      ((yCoord > 0) and (yCoord < CanvasSizeY + halfWd)) then
660
    begin                             { xAxis is within canvas height range }
661
      PenColor := xAxisColor;
662
      PenWidth := AxisWidth;
663
      atTop := yCoord < 2*CharH + AxisWidth;
664

665
      if atTop then yCoord := halfWd                        { top of canvas }
666
      else if yCoord > CanvasSizeY                       { bottom of canvas }
667
      then yCoord := CanvasSizeY - halfWd;
668

669
      MoveTo(0, yCoord);
670
      LineTo(CanvasSizeX, yCoord);
671

672
      PenWidth := halfWd;
673

674
      x := trunc(xMin/dx10Grad)*dx10Grad;          { graduations for x axis }
675
      c := round((xMin - x)/dxGrad);
676
      x := x + c*dxGrad;
677

678
      if c < 0 then Inc(c, 10);
679
      dCoord := CoordX(x + dxGrad) - CoordX(x);
680

681
      while x < xMax do
682
      begin                      { calculate coordinate for each graduation }
683
        xCoord := CoordX(x);
684

685
        if atTop then MoveTo(xCoord, AxisWidth) else MoveTo(xCoord, yCoord);
686

687
        if c mod 5 = 0 then                { larger mark for 5th graduation }
688
        begin
689
          if abs(xCoord - xO) > 2 then     { is not y axis }
690
          begin
691
            if c mod 10 = 0 then
692
            begin
693
              if atTop then LineTo(xCoord, 16 + halfWd)
694
              else LineTo(xCoord, yCoord - 16 - halfWd);
695
              AddXAxisText(x, xCoord, yCoord, halfWd, atTop);
696
            end
697
            else
698
            begin
699
              if atTop then LineTo(xCoord, 11 + halfWd)
700
              else LineTo(xCoord, yCoord - 11 - halfWd);
701
              if (trunc(x) = x) and (dCoord >= 5*xMinorGrad)
702
              then AddXAxisText(x, xCoord, yCoord, halfWd, atTop);
703
           end;
704
          end;                                              { is not y axis }
705
        end
706
        else
707
        begin
708
          if atTop then LineTo(xCoord, 7 + AxisWidth)
709
          else LineTo(xCoord, yCoord - 6 - halfWd);
710
        { small graduation mark }
711
          if (trunc(x) = x) and (dCoord >= xMajorGrad)
712
          then AddXAxisText(x, xCoord, yCoord, halfWd, atTop);
713
        end;
714
        x := x + dxGrad;
715
        Inc(c);
716
      end;  { while x < xMax do... }
717
    end
718
  end;
719
end;
720

721
procedure TfxCanvas.DrawYAxisLinear;
722
var
723
  halfWd: integer;
724
  xCoord, yCoord: integer;               { holds screen coordinate location }
725
  yO: integer;
726
  y: extended;
727
  c: integer;                                        { for graduation marks }
728
  dCoord: integer;
729
  atRight: Boolean;
730

731
begin
732
  with GraphData do
733
  begin
734
    halfWd := AxisWidth div 2;
735
    xCoord := CoordX(0);                   { coordinate for y axis }
736
    yO := CoordY(0);                       { y origin, i.e. x axis }
737
  { if GridStyle = gsPolar the yAxis may be off canvas
738
    otherwise it will be displayed at the left or right of canvas }
739
    if (Grid.GridStyle in [gsAxes, gsCartesian]) or
740
      ((xCoord > 0) and (xCoord < CanvasSizeX + halfWd)) then
741
    begin                              { yAxis is within canvas width range }
742
      PenColor := yAxisColor;
743
      PenWidth := AxisWidth;
744
      atRight := xCoord > CanvasSizeX - 6*CharW - halfWd;
745

746
      if atRight then xCoord := CanvasSizeX - halfWd         { canvas right }
747
                 else if xCoord < 0 then xCoord := halfWd;    { canvas left }
748

749
      MoveTo(xCoord, 0);
750
      LineTo(xCoord, CanvasSizeY);
751

752
      PenWidth := halfWd;
753

754
      y := trunc(yMin/dy10Grad)*dy10Grad;          { graduations for y axis }
755
      c := round((yMin - y)/dyGrad);
756
      y := y + c*dyGrad;
757

758
      if c < 0 then Inc(c, 10);
759
      dCoord := CoordY(y) - CoordY(y + dyGrad);
760

761
      while y < yMax do
762
      begin                      { calculate coordinate for each graduation }
763
        yCoord := CoordY(y);
764

765
        if atRight then MoveTo(CanvasSizeX - AxisWidth, yCoord)
766
                   else MoveTo(xCoord, yCoord);
767

768
        if c mod 5 = 0 then                { larger mark for 5th graduation }
769
        begin
770
          if abs(yCoord - yO) > 2 then     { is not x axis }
771
          begin
772
            if c mod 10 = 0 then
773
            begin
774
              if atRight
775
              then LineTo(CanvasSizeX - 15 - halfWd, yCoord)
776
              else LineTo(xCoord + 15 + halfWd, yCoord);
777
              AddYAxisText(y, xCoord, yCoord, halfWd, atRight);
778
            end
779
            else
780
            begin
781
              if atRight
782
              then LineTo(CanvasSizeX - 10 - halfWd, yCoord)
783
              else LineTo(xCoord + 10 + halfWd, yCoord);
784
              if (trunc(y) = y) and (dCoord > 5*yMinorGrad)
785
              then AddYAxisText(y, xCoord, yCoord, halfWd, atRight);
786
            end;
787
          end;                                              { is not x axis }
788
        end
789
        else
790
        begin
791
          if atRight
792
          then LineTo(CanvasSizeX - 7 - AxisWidth, yCoord)
793
          else LineTo(xCoord + 5 + halfWd, yCoord);
794
        { small graduation mark }
795
          if (trunc(y) = y) and (dCoord >= yMajorGrad)
796
          then AddYAxisText(y, xCoord, yCoord, halfWd, atRight);
797
        end;
798
        y := y + dyGrad;
799
        Inc(c);
800
      end;  { while y < yMax do... }
801
    end;
802
  end;
803
end;
804

805
procedure TfxCanvas.DrawXAxisLog;
806
var
807
  xCoord, ixCoord, yCoord, halfWd, i: integer;
808
  x, dx: extended;
809
  s: string;
810
  atTop: Boolean;
811

812
begin
813
  with GraphData do
814
  begin
815
    halfWd := AxisWidth div 2;
816

817
    if Grid.yAxisStyle = asLog then yCoord := CanvasSizeY
818
    else 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
821
    otherwise it will be displayed at the top or bottom of the canvas }
822
    if (Grid.GridStyle in [gsAxes, gsCartesian]) or
823
      ((yCoord > 0) and (yCoord < CanvasSizeY + halfWd)) then
824
    begin                             { xAxis is within canvas height range }
825
      PenColor := xAxisColor;
826
      PenWidth := AxisWidth;
827
      atTop := yCoord < 2*CharH + AxisWidth;
828

829
      if atTop then yCoord := halfWd                        { top of canvas }
830
      else if yCoord > CanvasSizeY                       { bottom of canvas }
831
      then yCoord := CanvasSizeY - halfWd;
832

833
      MoveTo(0, yCoord);
834
      LineTo(CanvasSizeX, yCoord);
835

836
      PenWidth := halfWd;
837
      dx := 10*dx10Grad;
838

839
      xCoord := CoordLogX(dx);
840
      while xCoord > 0 do
841
      begin
842
        MoveTo(xCoord, yCoord);
843
        if atTop then LineTo(xCoord, 15 + halfWd)
844
        else LineTo(xCoord, yCoord - 15 -HalfWd);
845
        x := dx;
846
        s := FormatValue(xDigits, x, dxGrad);
847
        if CoordLogX(x + 10*dx)-xCoord > Length(' '+s)*CharW then
848
        AddXAxisText(x, xCoord - CharW div 2, yCoord, halfWd, atTop);
849
        for i := 2 to 9 do
850
        begin
851
          x := x + dx;
852
          if x < xMax then
853
          begin
854
            ixCoord := CoordLogX(x);
855
            MoveTo(ixCoord, yCoord);
856
            if i = 5 then
857
            begin
858
              if atTop then LineTo(ixCoord, 11 + halfWd)
859
              else LineTo(ixCoord, yCoord - 11 -HalfWd);
860
            end
861
            else
862
            begin
863
              if atTop then LineTo(ixCoord, 7 + HalfWd)
864
              else LineTo(ixCoord, yCoord - 6 -HalfWd); { small graduation mark }
865
            end;
866
            s := FormatValue(xDigits, x, dxGrad);
867
            if CoordLogX(x + dx)-ixCoord > Length(' '+s)*CharW then
868
            AddXAxisText(x, ixCoord - CharW div 2, yCoord, halfWd, atTop);
869
          end;
870
        end;
871
        dx := dx/10;
872
        xCoord := CoordLogX(dx);
873
      end;
874

875
      x := dx;
876
      for i := 2 to 9 do
877
      begin
878
        x := x + dx;
879
        if x > xMin then
880
        begin
881
          ixCoord := CoordLogX(x);
882
          MoveTo(ixCoord, yCoord);
883
          if i = 5 then
884
          begin
885
            if atTop then LineTo(ixCoord, 11 + halfWd)
886
            else LineTo(ixCoord, yCoord - 11 -HalfWd);
887
          end
888
          else
889
          begin
890
            if atTop then LineTo(ixCoord, 7 + HalfWd)
891
            else LineTo(ixCoord, yCoord - 6 -HalfWd); { small graduation mark }
892
          end;
893
          s := FormatValue(xDigits, x, dxGrad);
894
          if CoordLogX(x + dx)-ixCoord > Length(' '+s)*CharW then
895
          AddXAxisText(x, ixCoord - CharW div 2, yCoord, halfWd, atTop);
896
        end;
897
      end;
898
    end;
899
  end;
900
end;
901

902
procedure TfxCanvas.DrawYAxisLog;
903
var
904
  xCoord, yCoord, iyCoord, halfWd, i: integer;
905
  y, dy: extended;
906
  atRight: Boolean;
907

908
begin
909
  with GraphData do
910
  begin
911
    halfWd := AxisWidth div 2;
912

913
    if Grid.xAxisStyle = asLog then xCoord := 0
914
    else xCoord := CoordX(0);              { coordinate for y axis }
915

916
  { if GridStyle = gsPolar and xAxis is not Log the yAxis may be off canvas
917
    otherwise it will be displayed at the left or right of the canvas }
918
    if (Grid.GridStyle in [gsAxes, gsCartesian]) or
919
      ((xCoord > 0) and (xCoord < CanvasSizeX + halfWd)) then
920
    begin                              { yAxis is within canvas width range }
921
      PenColor := yAxisColor;
922
      PenWidth := AxisWidth;
923
      atRight := xCoord > CanvasSizeX - 6*CharW - halfWd;
924

925
      if atRight then xCoord := CanvasSizeX - halfWd         { canvas right }
926
      else if xCoord < 0 then xCoord := halfWd;              { canvas left }
927

928
      MoveTo(xCoord, 0);
929
      LineTo(xCoord, CanvasSizeY);
930

931
      PenWidth := halfWd;
932
      dy := 10*dy10Grad;
933
      yCoord := CoordLogY(dy);
934

935
      while yCoord < CanvasSizeY do
936
      begin
937
        MoveTo(xCoord, yCoord);
938
        if atRight then LineTo(CanvasSizeX - 15 - halfWd, yCoord)
939
        else LineTo(xCoord + 15 + halfWd, yCoord);
940
        y := dy;
941
        if 3*CharH div 2 < yCoord - CoordLogY(y + 10*dy) then
942
        AddYAxisText(y, xCoord - CharW div 2,
943
                        yCoord + CharH div 3, halfWd, atRight);
944

945
        for i := 2 to 9 do
946
        begin
947
          y := y + dy;
948
          if y < yMax then
949
          begin
950
            iyCoord := CoordLogY(y);
951
            MoveTo(xCoord, iyCoord);
952
            if i = 5 then
953
            begin
954
              if atRight then LineTo(CanvasSizeX - 11 - halfWd, iyCoord)
955
              else LineTo(xCoord + 11 + halfWd, iyCoord);
956
            end
957
            else
958
            begin
959
              if atRight then LineTo(CanvasSizeX - 7 - halfWd, iyCoord)
960
              else LineTo(xCoord + 6 + halfWd, iyCoord); { small graduation mark }
961
            end;
962
            if 3*CharH div 2 < iyCoord - CoordLogY(y + dy) then
963
            AddYAxisText(y, xCoord - CharW div 2,
964
                           iyCoord + CharH div 3, halfWd, atRight);
965
          end;
966
        end;
967

968
        dy := dy/10;
969
        yCoord := CoordLogY(dy);
970
      end;
971

972
      y := dy;
973
      for i := 2 to 9 do
974
      begin
975
        y := y + dy;
976
        if y > yMin then
977
        begin
978
          iyCoord := CoordLogY(y);
979
          MoveTo(xCoord, iyCoord);
980
          if i = 5 then
981
          begin
982
            if atRight then LineTo(CanvasSizeX - 11 - halfWd, iyCoord)
983
            else LineTo(xCoord + 11 + halfWd, iyCoord);
984
          end
985
          else
986
          begin
987
            if atRight then LineTo(CanvasSizeX - 7 - halfWd, iyCoord)
988
            else LineTo(xCoord + 6 + halfWd, iyCoord); { small graduation mark }
989
          end;
990
          if 3*CharH div 2 < iyCoord - CoordLogY(y + dy) then
991
          AddYAxisText(y, xCoord - CharW div 2,
992
                         iyCoord + CharH div 3, halfWd, atRight);
993
        end;
994
      end;
995
    end;
996
  end;
997
end;
998

999
procedure TfxCanvas.PlotFunction(Selected: Boolean);
1000
var
1001
  LabelStr: string;
1002

1003
    function GetStringWidth(const s: string): integer;
1004
    var
1005
      i : integer;
1006

1007
    begin  { GetStringWidth }
1008
      Result := 0;
1009
      for i := 1 to Length(s)
1010
      do Result := Result + MainForm.GLWinBitFont.GetCharWidth(Char(s[i])) +1;
1011
    end;   { GetStringWidth }
1012

1013
begin
1014
  with GraphData, PlotData, FxParser do
1015
  begin
1016
    if PlotAsFx then LabelStr := 'y = ' + TextStr
1017
                else LabelStr := 'r = ' + TextStr;
1018

1019
    PenColor := PlotColor;
1020
    if ShowLabel and (ErrorByte = 0) and
1021
      (PlotData.xLabel > xMin) and (PlotData.xLabel < xMax) and
1022
      (PlotData.yLabel > yMin) and (PlotData.yLabel < yMax) then
1023
    begin  { display the label rectangle }
1024
      if Selected and (BitmapForm = nil) and (PrintForm = nil) then
1025
      begin  { display a rectangle around the label }
1026
        PenWidth := 1;
1027

1028
        with LabelRect do
1029
        begin
1030
          Right := GetStringWidth(LabelStr+'   ');
1031
          Bottom := round(4*MainForm.GLWinBitFont.CharHeight/3);
1032

1033
          if Grid.xAxisStyle = asLog
1034
          then Left := CoordLogX(xLabel) -
1035
                       2*MainForm.GLWinBitFont.GetCharWidth(' ')
1036
          else Left := CoordX(xLabel) -
1037
                       2*MainForm.GLWinBitFont.GetCharWidth(' ');
1038

1039
          if Grid.yAxisStyle = asLog
1040
          then Top := CoordLogY(yLabel) -
1041
                      round(MainForm.GLWinBitFont.CharHeight/8)
1042
          else Top := CoordY(yLabel) -
1043
                      round(MainForm.GLWinBitFont.CharHeight/8);
1044

1045
          Right := Left + Right;
1046
          Bottom := Top + Bottom;
1047
          RoundRect(Left, Top, Right, Bottom, 9, 9);
1048
        end;
1049
      end;  { if Selected... then... }
1050
    end;  { if ShowLabel then... }
1051

1052
    PenWidth := PlotWidth;
1053

1054
    if (ErrorByte = 0) and Assigned(Calculus) then
1055
    begin
1056
      if PlotAsFx
1057
      then PlotAsCartesian(Selected)
1058
      else PlotAsPolar(Selected);
1059
    end;
1060
  end;
1061
end;
1062

1063
procedure TfxCanvas.PlotAsCartesian(Selected: Boolean);
1064
begin
1065
{ evaluate y for each x & calculate plot point }
1066
  if GraphData.Grid.xAxisStyle = asLog then
1067
  begin
1068
    if GraphData.Grid.yAxisStyle = asLog
1069
    then PopulateCartesianLogXY(PlotList)
1070
    else PopulateCartesianLogX(PlotList);
1071
  end
1072
  else
1073
  if GraphData.Grid.yAxisStyle = asLog
1074
  then PopulateCartesianLogY(PlotList)
1075
  else PopulateCartesian(PlotList);
1076

1077
  AnalyseCartesian(PlotList);  { determine which lines are to be drawn }
1078

1079
  if Selected then with FunctionsForm do
1080
  begin
1081
    if Integrate2x.Checked then IntegrateCartesian else
1082
    if Integrate2y.Checked then IntegrateYCartesian else
1083
    if Between1.Checked then IntegrateBetweenFunctions else
1084
    if VolumeX1.Checked then IntegrateVolumeX;
1085
    if VolumeY1.Checked then IntegrateVolumeY;
1086
    if fxValueForm.Visible and fxValueForm.DisplayOK
1087
    then FindfxValues(fxValueForm.fxValueToFind);
1088
    if fx1ValueForm.Visible and fx1ValueForm.DisplayOK
1089
    then Findfx1Values(fx1ValueForm.fx1ValueToFind);
1090
    if fx2ValueForm.Visible and fx2ValueForm.DisplayOK
1091
    then Findfx2Values(fx2ValueForm.fx2ValueToFind);
1092
  end;
1093
{ next line hides the function used for the integrate volume }
1094
  if not (Selected and
1095
         (VolumeXForm.HideFunctionCheckBox.Checked or
1096
          VolumeYForm.HideFunctionCheckBox.Checked)) then
1097
  DrawCartesian(PlotList);     { draw the graph }
1098

1099
  if Selected then with FunctionsForm do
1100
  begin
1101
    if yfx1.Checked then  { dy/dx }
1102
    begin
1103
      yfx1List := TList.Create;
1104
      try
1105
        PopulateDerivCartesian(PlotList, yfx1List);
1106
        AnalyseDerivCartesian(yfx1List);
1107
        Draw_yfx1(yfx1List);
1108
        if yfx2.Checked then  {d2y/dx2 }
1109
        begin
1110
          yfx2List := TList.Create;
1111
          try
1112
            PopulateDerivCartesian(yfx1List, yfx2List);
1113
            AnalyseDerivCartesian(yfx2List);
1114
            Draw_yfx2(yfx2List);
1115
          finally
1116
            ClearPointList(yfx2List);
1117
          end;
1118
        end;
1119
      finally
1120
        ClearPointList(yfx1List);
1121
      end;
1122
    end;
1123

1124
    if EvaluateButton.Tag = 1 then
1125
    begin
1126
      yEvaluate := EvaluateFunction(xEvaluate);
1127
      ShowCartesianEvaluate;
1128
      DrawCartesianCoordinates;
1129
    end;
1130
  end;
1131
  if FunctionsForm.fxValue.Checked then DrawfxPoints;
1132
  if FunctionsForm.fx1Value.Checked then Drawfx1Points;
1133
  if FunctionsForm.fx2Value.Checked then Drawfx2Points;
1134
end;
1135

1136
procedure TfxCanvas.PlotAsPolar(Selected: Boolean);
1137
begin
1138
  PopulatePolar(PlotList); { evaluate r for each phi & calculate plot point }
1139
  AnalysePolar(PlotList);  { determine which lines are to be drawn }
1140

1141
  if FunctionsForm.Integrate2x.Checked and Selected then IntegratePolar;
1142

1143
  DrawPolar(PlotList);     { draw the graph }
1144

1145
  if Selected then with FunctionsForm do
1146
  begin
1147
    if yfx1.Checked then
1148
    begin
1149
      yfx1List := TList.Create;
1150
      try
1151
        PopulateDerivPolar(PlotList, yfx1List);
1152
        AnalysePolar(yfx1List);
1153
        Draw_yfx1(yfx1List);
1154
        if yfx2.Checked then
1155
        begin
1156
          yfx2List := TList.Create;
1157
          try
1158
            PopulateDerivPolar(yfx1List, yfx2List);
1159
            AnalysePolar(yfx2List);
1160
            Draw_yfx2(yfx2List);
1161
          finally
1162
            ClearPointList(yfx2List);
1163
          end;
1164
        end;
1165
      finally
1166
        ClearPointList(yfx1List);
1167
      end;
1168
    end;
1169

1170
    if EvaluateButton.Tag = 1 then
1171
    begin
1172
      yEvaluate := EvaluateFunction(xEvaluate);
1173
      ShowPolarEvaluate;
1174
      DrawPolarCoordinates;
1175
    end;
1176
  end;
1177
end;
1178

1179
procedure TfxCanvas.PopulateCartesian(var L: TList);
1180
var
1181
  i, n: integer;
1182
  vx, vy: extended;
1183

1184
begin
1185
  n := round(GraphData.PlotData.xInc);  { xInc may have decimals }
1186
  if n < 1 then n := 1;                 { each pixel }
1187

1188
  i := 0;
1189

1190
  while i <= CanvasSizeX do
1191
  begin
1192
    vx := ValueX(i);
1193
    try
1194
      vy := EvaluateFunction(vx);
1195
    except
1196
      vy := NaN;
1197
    end;
1198

1199
    L.Add(TGraphPointObject.Create(vx, vy));
1200
    with TGraphPointObject(L[L.Count -1]) do
1201
    begin
1202
      PlotPoint.X := CoordX(vx);
1203
      PlotPoint.Y := CoordY(vy);
1204
      DrawLine := false;  { set all false initially }
1205
    end;
1206
    Inc(i, n);
1207
  end;  { while i <= CanvasSizeX do... }
1208
end;
1209

1210
procedure TfxCanvas.PopulateCartesianLogX(var L: TList);
1211
var
1212
  i, n: integer;
1213
  vx, vy: extended;
1214

1215
begin
1216
  i := 0;
1217
  n := round(GraphData.PlotData.xInc);
1218
  if n < 1 then n := 1;  { plot all points for each pixel }
1219

1220
  while i <= CanvasSizeX + n do
1221
  begin
1222
    vx := ValueLogX(i);
1223
    try
1224
      vy := EvaluateFunction(vx);
1225
    except
1226
      vy := NaN;
1227
    end;
1228

1229
    L.Add(TGraphPointObject.Create(vx, vy));
1230

1231
    with TGraphPointObject(L[L.Count -1]) do
1232
    begin
1233
      PlotPoint.X := CoordLogX(vx);
1234
      PlotPoint.Y := CoordY(vy);
1235
      DrawLine := false;  { set all false initially }
1236
    end;
1237
    Inc(i, n);
1238
  end;
1239
end;
1240

1241
procedure TfxCanvas.PopulateCartesianLogY(var L: TList);
1242
var
1243
  i, n: integer;
1244
  vx, vy: extended;
1245

1246
begin
1247
  i := 0;
1248
  n := round(GraphData.PlotData.xInc);
1249
  if n < 1 then n := 1;  { plot all points for each pixel }
1250

1251
  while i <= CanvasSizeX + n do
1252
  begin
1253
    vx := ValueX(i);
1254
    try
1255
      vy := EvaluateFunction(vx);
1256
    except
1257
      vy := NaN;
1258
    end;
1259

1260
    L.Add(TGraphPointObject.Create(vx, vy));
1261

1262
    with TGraphPointObject(L[L.Count -1]) do
1263
    begin
1264
      PlotPoint.X := CoordX(vx);
1265
      with GraphData do
1266
      begin
1267
        if vy < yMin then PlotPoint.Y := CoordLogY(yMin) + 2 else
1268
        if vy > yMax then PlotPoint.Y := CoordLogY(yMax) - 2
1269
        else PlotPoint.Y := CoordLogY(vy);
1270
      end;
1271
      DrawLine := false;  { set all false initially }
1272
    end;
1273
    Inc(i, n);
1274
  end;
1275
end;
1276

1277
procedure TfxCanvas.PopulateCartesianLogXY(var L: TList);
1278
var
1279
  i, n: integer;
1280
  vx, vy: extended;
1281

1282
begin
1283
  i := 0;
1284
  n := round(GraphData.PlotData.xInc);
1285
  if n < 1 then n := 1;  { plot all points for each pixel }
1286

1287
  while i <= CanvasSizeX + n do
1288
  begin
1289
    vx := ValueLogX(i);
1290
    try
1291
      vy := EvaluateFunction(vx);
1292
    except
1293
      vy := NaN;
1294
    end;
1295

1296
    L.Add(TGraphPointObject.Create(vx, vy));
1297

1298
    with TGraphPointObject(L[L.Count -1]) do
1299
    begin
1300
      PlotPoint.X := CoordLogX(vx);
1301
      with GraphData do
1302
      begin
1303
        if vy < yMin then PlotPoint.Y := CoordLogY(yMin) + 2 else
1304
        if vy > yMax then PlotPoint.Y := CoordLogY(yMax) - 2
1305
        else PlotPoint.Y := CoordLogY(vy);
1306
      end;
1307
      DrawLine := false;  { set all false initially }
1308
    end;
1309
    Inc(i, n);
1310
  end;
1311
end;
1312

1313
procedure TfxCanvas.PopulatePolar(var L: TList);
1314
var
1315
  vPhi, vr: extended;
1316

1317
begin
1318
  with GraphData, PlotData do
1319
  begin
1320
    vPhi := SegMin;
1321

1322
    while vPhi <= SegMax + PhiInc do
1323
    begin
1324
      try
1325
        vr := EvaluateFunction(vPhi);
1326
      except
1327
        vr := NaN;
1328
      end;
1329

1330
      L.Add(TGraphPointObject.Create(vPhi, vr));
1331

1332
      with TGraphPointObject(L[L.Count -1]) do
1333
      begin
1334
        PlotPoint.X := CoordX(vr*Cos(vPhi));
1335
        PlotPoint.Y := CoordY(vr*Sin(vPhi));
1336
        DrawLine := false;  { set all false initially }
1337
      end;
1338
      vPhi := vPhi + PhiInc;  { next step }
1339
    end;
1340
  end;
1341
end;
1342

1343
procedure TfxCanvas.PopulateDerivCartesian(var Ls: TList; var L: TList);
1344
var
1345
  i: integer;
1346
  p1, p2, p: TGraphPoint;
1347
  m: extended;
1348

1349
begin
1350
  for i := 1 to Ls.Count -2 do
1351
  begin
1352
    with TGraphPointObject(Ls[i -1]) do
1353
    begin
1354
      p1.x := x_phi;
1355
      p1.y := y_r;
1356
    end;
1357

1358
    with TGraphPointObject(Ls[i]) do
1359
    begin
1360
      p.x := x_phi;
1361
      p.y := y_r;
1362
    end;
1363

1364
    with TGraphPointObject(Ls[i +1]) do
1365
    begin
1366
      p2.x := x_phi;
1367
      p2.y := y_r;
1368
    end;
1369

1370
    m := (p2.y - p1.y)/(p2.x - p1.x);
1371
    L.Add(TGraphPointObject.Create(p.x, m));
1372

1373
    with TGraphPointObject(L[L.Count -1]) do
1374
    begin
1375
      with GraphData, Grid do
1376
      begin
1377
        if xAxisStyle = asLog
1378
        then PlotPoint.X := CoordLogX(x_phi)
1379
        else PlotPoint.X := CoordX(x_phi);
1380

1381
        if yAxisStyle = asLog then
1382
        begin
1383
          if y_r < yMin then PlotPoint.Y := CoordLogY(yMin) + 2 else
1384
          if y_r > yMax then PlotPoint.Y := CoordLogY(yMax) - 2
1385
          else PlotPoint.Y := CoordLogY(y_r);
1386
        end
1387
        else PlotPoint.Y := CoordY(y_r);
1388
      end;
1389
      DrawLine := false;
1390
    end;
1391
  end;
1392
end;
1393

1394
procedure TfxCanvas.PopulateDerivPolar(var Ls: TList; var L: TList);
1395
var
1396
  i: integer;
1397
  p1, p2, p: TGraphPoint;
1398
  m: extended;
1399

1400
begin
1401
  for i := 1 to Ls.Count -2 do
1402
  begin
1403
    with TGraphPointObject(Ls[i -1]) do
1404
    begin
1405
      p1.x := x_phi;
1406
      p1.y := y_r;
1407
    end;
1408

1409
    with TGraphPointObject(Ls[i]) do
1410
    begin
1411
      p.x := x_phi;
1412
      p.y := y_r;
1413
    end;
1414

1415
    with TGraphPointObject(Ls[i +1]) do
1416
    begin
1417
      p2.x := x_phi;
1418
      p2.y := y_r;
1419
    end;
1420

1421
    m := (p2.y - p1.y)/(p2.x - p1.x);
1422
    L.Add(TGraphPointObject.Create(p.x, m));
1423

1424
    with TGraphPointObject(L[L.Count -1]) do
1425
    begin
1426
      PlotPoint.X := CoordX(y_r*Cos(x_phi));
1427
      PlotPoint.Y := CoordY(y_r*Sin(x_phi));
1428
      DrawLine := false;
1429
    end;
1430
  end;
1431
end;
1432

1433
procedure TfxCanvas.NoNumberCartesian(var L: TList; const P, C: TGraphPoint;
1434
                                    const i: integer);
1435
{ ChecknoNumber checks prior and current graph values for validity.
1436
  If not valid then prior point is adjusted to a more accurate X, Y values }
1437
const
1438
  dpMin = 1e-9;
1439

1440
  function StartPoint(const n: integer): extended;
1441
  var
1442
    vx, vy, dx, dp: extended;
1443

1444
  begin
1445
    Result := NaN;
1446
    with TGraphPointObject(L[n]) do
1447
    begin
1448
      if GraphData.Grid.xAxisStyle = asLog
1449
      then vx := ValueLogX(PlotPoint.X -1)
1450
      else vx := ValueX(PlotPoint.X -1);
1451
      dx := (vx - x_phi);
1452
      dp := 1;     { one pixel }
1453
      while dp > dpMin do
1454
      begin
1455
        vy := EvaluateFunction(vx);
1456
        if isNaN(vy) then vx := vx - dx
1457
        else
1458
        begin
1459
          Result := vx;
1460
          vx := vx + dx;
1461
        end;
1462
        dx := dx/2;
1463
        dp := dp/2;
1464
      end;
1465
    end;
1466
  end;
1467

1468
  function StopPoint(const n: integer): extended;
1469
  var
1470
    vx, vy, dx, dp: extended;
1471

1472
  begin
1473
    Result := NaN;
1474
    with TGraphPointObject(L[n]) do
1475
    begin
1476
      if GraphData.Grid.xAxisStyle = asLog
1477
      then vx := ValueLogX(PlotPoint.X -1)
1478
      else vx := ValueX(PlotPoint.X -1);
1479
      dx := (x_phi - vx);
1480
      dp := 1;     { one pixel }
1481
      while dp > dpMin do
1482
      begin
1483
        vy := EvaluateFunction(vx);
1484
        if isNaN(vy) then vx := vx - dx
1485
        else
1486
        begin
1487
          Result := vx;
1488
          vx := vx + dx;
1489
        end;
1490
        dx := dx/2;
1491
        dp := dp/2;
1492
      end;
1493
    end;
1494
  end;
1495

1496
var
1497
  sy: extended;
1498
  b: Boolean;
1499

1500
begin
1501
  if isNaN(P.y) and not isNaN(C.y) then
1502
  begin
1503
    sy := EvaluateFunction(StartPoint(i));
1504
    with TGraphPointObject(L[i - 1]) do PlotPoint.Y := CoordY(sy);
1505
    Exit;
1506
  end;
1507
{ in some cases this is needed to trigger the next option }
1508
  b := (i + 2 < L.Count) and isNaN(TGraphPointObject(L[i + 2]).y_r);
1509
  if not isNaN(P.y) and isNaN(C.y) and b then
1510
  begin
1511
    sy := EvaluateFunction(StopPoint(i + 1));
1512
    with TGraphPointObject(L[i + 1]).PlotPoint do Y := CoordY(sy);
1513
  end;
1514
end;
1515

1516
procedure TfxCanvas.NoNumberDerivCartesian(var L: TList; const P, C: TGraphPoint;
1517
                                         const i: integer);
1518
{ ChecknoNumber checks prior and current graph values for validity.
1519
  If not valid then prior point is adjusted to a more accurate X, Y values }
1520
var
1521
  delta: integer;
1522

1523
begin
1524
  try
1525
    if isNaN(P.y) and not isNaN(C.y) then
1526
    begin
1527
      with TGraphPointObject(L[i +1])
1528
      do delta := C.PlotPoint.Y - PlotPoint.Y;
1529
      with TGraphPointObject(L[i -1]).PlotPoint do
1530
      begin
1531
        X := C.PlotPoint.X;
1532
        Y := C.PlotPoint.Y + delta;
1533
      end;
1534
      Exit;
1535
    end;
1536

1537
    if not isNaN(P.y) and isNaN(C.y) then
1538
    begin
1539
      with TGraphPointObject(L[i -2])
1540
      do delta := P.PlotPoint.Y - PlotPoint.Y;
1541
      with TGraphPointObject(L[i -1]).PlotPoint do
1542
      begin
1543
        X := C.PlotPoint.X;
1544
        Y := P.PlotPoint.Y + delta;
1545
      end;
1546
    end;
1547
  except
1548
  end;
1549
end;
1550

1551
procedure TfxCanvas.NoNumberPolar(var L: TList; var P, C: TGraphPoint;
1552
                                const i: Integer);
1553
begin
1554
  if isNaN(P.y) and not isNaN(C.y) then
1555
  begin
1556
    with TGraphPointObject(L[i - 1]).PlotPoint do
1557
    begin
1558
      X := C.PlotPoint.X;
1559
      Y := C.PlotPoint.Y;
1560
    end;
1561
  end;
1562
  if not isNaN(P.y) and isNaN(C.y) then
1563
  begin
1564
    with TGraphPointObject(L[i]).PlotPoint do
1565
    begin
1566
      X := P.PlotPoint.X;
1567
      Y := P.PlotPoint.Y;
1568
    end;
1569
  end;
1570
end;
1571

1572
procedure TfxCanvas.InfinityCartesian(var L: Tlist; var P, C: TGraphPoint;
1573
                                    const i: integer);
1574
{ CheckInfinity checks prior and current graph values for infinity.
1575
  If one is and the other is not then the y value of the prior plot point
1576
  needs to be adjusted either to the top or bottom of the viewer. }
1577
begin
1578
  if isInfinite(P.y) and not isInfinite(C.y)
1579
  then with TGraphPointObject(L[i -1]).PlotPoint do
1580
  begin
1581
    case Sign(P.y) of
1582
   -1:Y := CanvasSizeY;      { -INF: bottom }
1583
    0:Y := C.PlotPoint.Y;    { may never happen }
1584
    1:Y := 0;                { +INF: top }
1585
    end;
1586
  end;
1587

1588
  if not isInfinite(P.y) and isInfinite(C.y)
1589
  then with TGraphPointObject(L[i -1]).PlotPoint do
1590
  begin
1591
    case Sign(C.y) of
1592
   -1:Y := CanvasSizeY;      { -INF: bottom }
1593
    0:Y := C.PlotPoint.Y;    { may never happen }
1594
    1:Y := 0;                { +INF: top }
1595
    end;
1596
  end;
1597
end;
1598

1599
procedure  TfxCanvas.InfinityPolar(var L: Tlist; var P, C: TGraphPoint;
1600
                                 const i: integer);
1601
begin
1602
{ CheckInfinity checks prior and current graph values for infinity.
1603
  If one is and the other is not then the y value of the prior
1604
  plot point needs to be adjusted. }
1605
  if isInfinite(P.y) and not isInfinite(C.y) then
1606
  begin
1607
    with TGraphPointObject(L[i -1]).PlotPoint do
1608
    begin
1609
      X := C.PlotPoint.X;
1610
      Y := C.PlotPoint.Y;
1611
    end;
1612
  end;
1613

1614
  if not isInfinite(P.y) and isInfinite(C.y) then
1615
  begin
1616
    with TGraphPointObject(L[i]).PlotPoint do
1617
    begin
1618
      X := P.PlotPoint.X;
1619
      Y := P.PlotPoint.Y;
1620
    end;
1621
  end;
1622
end;
1623

1624
function TfxCanvas.LineIsValid(var P, C: TGraphPoint): Boolean;
1625
begin
1626
{ if the line is not valid it will not be drawn }
1627
  if not GraphData.PlotData.IsContinuous then
1628
  begin
1629
    if isNaN(C.y) or IsInfinite(C.y) then
1630
    begin
1631
      Result := false;
1632
      Exit;
1633
    end;
1634

1635
    if (C.PlotPoint.Y <= 0) and (P.PlotPoint.Y >= CanvasSizeY) or
1636
       (P.PlotPoint.Y <= 0) and (C.PlotPoint.Y >= CanvasSizeY) then
1637
    begin
1638
      Result := false;
1639
      Exit;
1640
    end;
1641
  end;
1642
  Result := true;
1643
end;
1644

1645
procedure TfxCanvas.AnalyseCartesian(var L: TList);
1646
var
1647
  i: integer;
1648
  Prior, Current: TGraphPoint;
1649

1650
begin
1651
  i := 0;
1652

1653
  with TGraphPointObject(L[i]) do
1654
  begin
1655
    Prior.PlotPoint := PlotPoint;
1656
    Prior.x := x_phi;
1657
    Prior.y := y_r;
1658
  end;
1659

1660
  Inc(i);  { start from L[1]; first point is a MoveTo not a LineTo
1661
               i.e. DrawLine is false }
1662
  while i < L.Count do
1663
  begin    { integer plot points; down is greater }
1664
    with TGraphPointObject(L[i]) do
1665
    begin
1666
      Current.PlotPoint := PlotPoint;
1667
      Current.x := x_phi;
1668
      Current.y := y_r;
1669

1670
      if GraphData.PlotData.IsSegment then
1671
      begin  { plot only segment }
1672
        with GraphData.PlotData do
1673
        if (x_phi >= SegMin) and (x_phi <= SegMax) then
1674
        begin
1675
          NoNumberCartesian(L, Prior, Current, i);
1676
          InfinityCartesian(L, Prior, Current, i);
1677
          DrawLine := LineIsValid(Prior, Current);
1678
        end;
1679
      end
1680
      else
1681
      begin  { complete plot }
1682
        NoNumberCartesian(L, Prior, Current, i);
1683
        InfinityCartesian(L, Prior, Current, i);
1684
        DrawLine := LineIsValid(Prior, Current);
1685
      end;
1686
    end;  { with TGraphPointObject(L[i]) do... }
1687

1688
    Prior := Current;  { update Prior }
1689
    Inc(i);  { next step }
1690
  end;  { while i < L.Count do... }
1691
end;
1692

1693
procedure TfxCanvas.AnalyseDerivCartesian(var L: TList);
1694
var
1695
  i: integer;
1696
  Prior, Current: TGraphPoint;
1697

1698
begin
1699
  i := 0;
1700

1701
  with TGraphPointObject(L[i]) do
1702
  begin
1703
    Prior.PlotPoint := PlotPoint;
1704
    Prior.x := x_phi;
1705
    Prior.y := y_r;
1706
  end;
1707

1708
  Inc(i);  { start from L[1]; first point is a MoveTo not a LineTo
1709
               i.e. DrawLine is false }
1710
  while i < L.Count do
1711
  begin    { integer plot points; down is greater }
1712
    with TGraphPointObject(L[i]) do
1713
    begin
1714
      Current.PlotPoint := PlotPoint;
1715
      Current.x := x_phi;
1716
      Current.y := y_r;
1717
      if GraphData.PlotData.IsSegment then
1718
      begin  { plot only segment }
1719
        with GraphData.PlotData do
1720
        if (x_phi >= SegMin) and (x_phi <= SegMax) then
1721
        begin
1722
          NoNumberDerivCartesian(L, Prior, Current, i);
1723
          InfinityCartesian(L, Prior, Current, i);
1724
          DrawLine := LineIsValid(Prior, Current);
1725
        end;
1726
      end
1727
      else
1728
      begin  { complete plot }
1729
        NoNumberDerivCartesian(L, Prior, Current, i);
1730
        InfinityCartesian(L, Prior, Current, i);
1731
        DrawLine := LineIsValid(Prior, Current);
1732
      end;
1733
    end;  { with TGraphPointObject(L[i]) do... }
1734

1735
    Prior := Current;  { update Prior }
1736
    Inc(i);  { next step }
1737
  end;  { while i < L.Count do... }
1738
end;
1739

1740
procedure TfxCanvas.AnalysePolar(var L: TList);
1741
var
1742
  idx: integer;
1743
  Prior, Current: TGraphPoint;
1744

1745
begin
1746
  idx := 0;
1747

1748
  with TGraphPointObject(L[idx]) do
1749
  begin
1750
    Prior.PlotPoint := PlotPoint;
1751
    Prior.x := x_phi;
1752
    Prior.y := y_r;
1753
  end;
1754

1755
  Inc(idx);
1756

1757
  while idx < L.Count do
1758
  begin
1759
    with TGraphPointObject(L[idx]) do
1760
    begin
1761
      Current.PlotPoint := PlotPoint;
1762
      Current.x := x_phi;
1763
      Current.y := y_r;
1764

1765
      NoNumberPolar(L, Prior, Current, idx);
1766
      InfinityPolar(L, Prior, Current, idx);
1767
      DrawLine := LineIsValid(Prior, Current);
1768
    end;
1769
    Prior := Current;  { update Prior }
1770
    Inc(idx);  { next step }
1771
  end;  { while i < L.Count do... }
1772
end;
1773

1774
procedure TfxCanvas.DrawCartesian(var L: TList);
1775
var
1776
  i: integer;
1777
  x0: integer;
1778

1779
begin
1780
  with GraphData, PlotData do
1781
  begin
1782
    PenWidth := PlotWidth;
1783
    PenColor := PlotColor;
1784
    x0 := MaxInt;
1785
  end;
1786

1787
  for i := 0 to L.Count -1 do
1788
  with TGraphPointObject(L[i]) do
1789
  begin
1790
    if x0 <> PlotPoint.X then
1791
    if DrawLine then LineTo(PlotPoint.X, PlotPoint.Y)
1792
                else MoveTo(PlotPoint.X, PlotPoint.Y);
1793
    x0 := PlotPoint.X;
1794
  end;
1795
end;
1796

1797
procedure TfxCanvas.DrawPolar(var L: TList);
1798
var
1799
  i: integer;
1800

1801
begin
1802
  with GraphData, PlotData do
1803
  begin
1804
    PenWidth := PlotWidth;
1805
    PenColor := PlotColor;
1806
  end;
1807

1808
  for i := 0 to L.Count -1 do
1809
  with TGraphPointObject(L[i]) do
1810
  if DrawLine then LineTo(PlotPoint.X, PlotPoint.Y)
1811
              else MoveTo(PlotPoint.X, PlotPoint.Y);
1812
end;
1813

1814
procedure TfxCanvas.Draw_yfx1(var L: TList);
1815
var
1816
  i: integer;
1817
  x0: integer;
1818

1819
begin
1820
  PenWidth := GraphData.dydxWidth;
1821
  PenColor := GraphData.dydxColor;
1822
  x0 := MaxInt;
1823

1824
  for i := 0 to L.Count -1 do
1825
  with TGraphPointObject(L[i]) do
1826
  begin
1827
    if x0 <> PlotPoint.X then
1828
    if DrawLine then LineTo(PlotPoint.X, PlotPoint.Y)
1829
                else MoveTo(PlotPoint.X, PlotPoint.Y);
1830
    x0 := PlotPoint.X;
1831
  end;
1832
end;
1833

1834
procedure TfxCanvas.Draw_yfx2(var L: TList);
1835
var
1836
  i: integer;
1837
  x0: integer;
1838

1839
begin
1840
  PenWidth := GraphData.d2ydx2Width;
1841
  PenColor := GraphData.d2ydx2Color;
1842
  x0 := MaxInt;
1843

1844
  for i := 0 to L.Count -1 do
1845
  with TGraphPointObject(L[i]) do
1846
  begin
1847
    if x0 <> PlotPoint.X then
1848
    if DrawLine then LineTo(PlotPoint.X, PlotPoint.Y)
1849
                else MoveTo(PlotPoint.X, PlotPoint.Y);
1850
    x0 := PlotPoint.X;
1851
  end;
1852
end;
1853

1854
procedure TfxCanvas.IntegrateCartesian;
1855

1856
  procedure SetupIntegral;
1857
  var
1858
    i: integer;
1859

1860
  begin   { SetupIntegral }
1861
    if Assigned(IntegList) then
1862
    for i := 0 to IntegList.Count -1 do
1863
    with TGraphPointObject(IntegList[i]) do
1864
    begin
1865
      PlotPoint.X := CoordX(x_phi);
1866
      PlotPoint.Y := CoordY(y_r);
1867
      if i = 0 then DrawLine := false;
1868
    end;
1869
  end;    { SetupIntegral }
1870

1871
    procedure ShadeArea;
1872
    var
1873
      i: integer;
1874
      yCoord: integer;
1875

1876
      procedure DrawShading;
1877
      var
1878
        yValue: extended;
1879
        x, y: integer;
1880

1881
      begin
1882
        with TGraphPointObject(IntegList[i]) do
1883
        begin
1884
          x := PlotPoint.X;
1885
          yValue := EvaluateFunction(x_phi);
1886

1887
          PenWidth := 1;
1888
          PenAlpha := GraphData.AreaAlpha;
1889
          y := CoordY(yValue);
1890

1891
          if yValue < 0
1892
          then PenColor := GraphData.NegAreaColor
1893
          else PenColor := GraphData.PosAreaColor;
1894

1895
          Line(x, yCoord, x, y);
1896
          PenAlpha := 1;
1897
        end;
1898
      end;
1899

1900
    begin   { ShadeArea }
1901
      yCoord := CoordY(0);
1902
      for i := 0 to IntegList.Count -1 do
1903
      with TGraphPointObject(IntegList[i]) do
1904
      if DrawLine then DrawShading;
1905
    end;    { ShadeArea }
1906

1907
    procedure DrawIntegral;
1908
    var
1909
      i: integer;
1910

1911
    begin   { DrawIntegral }
1912
      PenColor := GraphData.ydxColor;
1913
      PenWidth := GraphData.ydxWidth;
1914
      for i := 0 to IntegList.Count -1 do
1915
      with TGraphPointObject(IntegList[i]) do
1916
      if DrawLine
1917
      then LineTo(PlotPoint.X, PlotPoint.Y)
1918
      else MoveTo(PlotPoint.X, PlotPoint.Y);
1919
    end;    { DrawIntegral }
1920

1921
        { TfxCanvas.IntegrateCartesian }
1922
var
1923
  SumSegs: extended;
1924
  NegSegs: extended;
1925
  PosSegs: extended;
1926

1927
begin
1928
  IntegList := TList.Create;
1929
  try
1930
    NegSegs := 0;
1931
    PosSegs := 0;
1932
    SumSegs := SumSegments(NegSegs, PosSegs);  { Cartesian }
1933

1934
    with IntegrateXForm do
1935
    begin
1936
      if IntegCheckBox.Checked then { Plot Integral selected }
1937
      begin
1938
        MinIntegXLabel.Caption := 'Minimum: x = '+
1939
        FloatToStrF(IntegXMin, ffGeneral, 12, 8);
1940
        MinIntegYLabel.Caption := 'Minimum: y = '+
1941
        FloatToStrF(IntegYMin, ffGeneral, 12, 8);
1942

1943
        MaxIntegXLabel.Caption := 'Maximum: x = '+
1944
        FloatToStrF(IntegXMax, ffGeneral, 12, 8);
1945
        MaxIntegYLabel.Caption := 'Maximum: y = '+
1946
        FloatToStrF(IntegYMax, ffGeneral, 12, 8);
1947
      end;
1948
      AreaLabel.Caption := 'Integral P[a, b] = '+
1949
      FloatToStrF(SumSegs, ffGeneral, 12, 8);
1950

1951
      NegAreaLabel.Caption := '"Negative" Area = '+
1952
      FloatToStrF(-NegSegs, ffGeneral, 12, 8);
1953

1954
      PosAreaLabel.Caption := '"Positive" Area = '+
1955
      FloatToStrF(PosSegs, ffGeneral, 12, 8);
1956

1957
      TotalAreaLabel.Caption := 'Total Area = '+
1958
      FloatToStrF(PosSegs - NegSegs, ffGeneral, 12, 8);
1959

1960
      SumAreaLabel.Caption := 'Sum Area = '+
1961
      FloatToStrF(SumSegs, ffGeneral, 12, 8);
1962
    end;
1963

1964
    if IntegList.Count > 0 then
1965
    begin
1966
      SetupIntegral;
1967
      if IntegrateXForm.PlotIntegrated and piArea = piArea then ShadeArea;
1968
      if IntegrateXForm.PlotIntegrated and piShow = piShow then DrawIntegral;
1969
    end;
1970
  finally
1971
    ClearPointList(IntegList);
1972
    IntegList := nil;
1973
  end;
1974
end;    { TfxCanvas.IntegrateCartesian }
1975

1976
procedure TfxCanvas.IntegratePolar;
1977
  function SumSectors(var aNeg, aPos: extended): extended;
1978
  var
1979
    a: extended;      { area }
1980
    h: extended;      { step }
1981
    phi, phi1, phi2: extended;
1982
    i: integer;
1983
    r, r1, r2: extended;
1984
    m: extended;
1985
    xCoord: integer;
1986
    yCoord: integer;
1987
    LastXCoord: integer;
1988
    LastYCoord: integer;
1989

1990
  begin  { SumSectors }
1991
    if KeepRange then
1992
    begin
1993
      IntegMin := KeptMin;
1994
      IntegMax := KeptMax;
1995
    end
1996
    else with GraphData, PlotData do
1997
    begin
1998
      if IsSegment then
1999
      begin
2000
        IntegMin := SegMin;
2001
        IntegMax := SegMax;
2002
      end
2003
      else if PlotAsFx then
2004
      begin
2005
        IntegMin := xMin;
2006
        IntegMax := xMax;
2007
      end;
2008
    end;
2009

2010
    if IntegMax = IntegMin then
2011
    begin
2012
      Result := 0;
2013
      Exit;
2014
    end;
2015

2016
    if IntegMax < IntegMin then
2017
    begin
2018
      a := IntegMax;
2019
      IntegMax := IntegMin;
2020
      IntegMin := a;
2021
      with IntegrateXForm do
2022
      begin
2023
        EditIntegMin.Text := FloatToStrF(IntegMin, ffGeneral, 13, 4);
2024
        EditIntegMax.Text := FloatToStrF(IntegMax, ffGeneral, 13, 4);
2025
      end;
2026
    end;
2027
    LastXCoord := MaxInt;
2028
    LastYCoord := MaxInt;
2029

2030
    h := (IntegMax - IntegMin)/GraphData.IntegCount;  { calculate step }
2031
    a := 0;  { initial area = 0 }
2032

2033
  { calculate numerical value to be used to display area }
2034
    phi1 := IntegMin;
2035
    phi2 := phi1 + h;  { h = d� }
2036

2037
    for i := 1 to GraphData.IntegCount do
2038
    begin  { calculate area using a = 0.5*r(mean)^2*d� }
2039
      phi := (phi1 + phi2)/2;                { mean phi }
2040

2041
      r1 := EvaluateFunction(phi1); { r1 = f(�1) }
2042
      r2 := EvaluateFunction(phi2); { r2 = f(�2) }
2043
      r := (r1 + r2)/2;             { mean r }
2044

2045
      if not isNaN(r) then
2046
      begin
2047
        m := h*sqr(r)/2;                       { area of sector }
2048
        a := a + m;                            { add to total area }
2049

2050
        xCoord := CoordX(r*Cos(Phi));
2051
        yCoord := CoordY(r*Sin(phi));
2052

2053
        if (LastXCoord <> xCoord) or (LastYCoord <> yCoord)
2054
        then SectorList.Add(TGraphPointObject.Create(phi, r));
2055

2056
        LastXCoord := xCoord;
2057
        LastYCoord := yCoord;
2058

2059
        if r < 0 then aNeg := aNeg + m else aPos := aPos + m;
2060
      end;
2061

2062
      phi1 := phi2;                   { step }
2063
      phi2 := phi2 + h;
2064
    end;
2065
    Result := aPos - aNeg;
2066
  end;   { SumSectors }
2067

2068
  procedure SetupIntegral;
2069
  var
2070
    i: integer;
2071

2072
  begin   { SetupIntegral }
2073
    if Assigned(IntegList) then
2074
    for i := 0 to IntegList.Count -1 do
2075
    with TGraphPointObject(IntegList[i]) do
2076
    begin
2077
      PlotPoint.X := CoordX(y_r*Cos(x_phi));
2078
      PlotPoint.Y := CoordY(y_r*Sin(x_phi));
2079
      if i = 0 then DrawLine := false;
2080
    end;
2081
  end;    { SetupIntegral }
2082

2083
  procedure ShadeArea;
2084
  var
2085
    i: integer;
2086
    p1, p2: TPoint;
2087
    yCoord: integer;
2088
    xCoord: integer;
2089
    r: extended;
2090

2091
    procedure DrawShading;
2092
    begin
2093
      with TGraphPointObject(SectorList[i]) do
2094
      begin
2095
        p1.x := xCoord;
2096
        r := EvaluateFunction(x_phi);
2097
        p2.x := CoordX(r*Cos(x_phi));
2098

2099
        p1.y := yCoord;
2100
        p2.y := CoordY(r*Sin(x_Phi));
2101
        if y_r < 0
2102
        then PenColor := GraphData.NegAreaColor
2103
        else PenColor := GraphData.PosAreaColor;
2104
        FillSector(p2.x, p2.Y);
2105
      end;
2106
    end;    { DrawShading }
2107

2108
  begin   { ShadeArea }
2109
    yCoord := CoordY(0);     { coordinate for x axis }
2110
    xCoord := CoordX(0);     { coordinate for y axis }
2111

2112
    PenWidth := 1;
2113
    PenAlpha := GraphData.AreaAlpha;
2114
    StartRadialFill(xCoord, yCoord);
2115

2116
    for i := 0 to Sectorlist.Count -1 do
2117
    with TGraphPointObject(SectorList[i]) do DrawShading;
2118
    PenAlpha := 1;
2119
    PenWidth := GraphData.PlotData.PlotWidth;
2120
    StopRadialFill;
2121
  end;    { ShadeArea }
2122

2123
  procedure DrawIntegral;
2124
  var
2125
    i: integer;
2126

2127
  begin   { DrawIntegral }
2128
    if Assigned(IntegList) then
2129
    PenColor := GraphData.ydxColor;
2130
    PenWidth := GraphData.ydxWidth;
2131
    for i := 0 to IntegList.Count -1 do
2132
    with TGraphPointObject(IntegList[i]) do
2133
    if DrawLine
2134
    then LineTo(PlotPoint.X, PlotPoint.Y)
2135
    else MoveTo(PlotPoint.X, PlotPoint.Y);
2136
  end;    { DrawIntegral }
2137

2138
        { TfxCanvas.IntegratePolar }
2139
var
2140
  SumSect: extended;   { calculate sector area using a = 0.5*r(mean)^2*d�  }
2141
  NegSect: extended;
2142
  PosSect: extended;
2143

2144
  NegSegs: extended;
2145
  PosSegs: extended;
2146

2147
begin
2148
  SectorList := TList.Create;
2149
  NegSect := 0;
2150
  PosSect := 0;
2151
  SumSect := SumSectors(NegSect, PosSect);  { polar sectors }
2152

2153
  if IntegrateXForm.PlotIntegrated and piShow = piShow then
2154
  begin
2155
    IntegList := TList.Create;
2156
    NegSegs := 0;
2157
    PosSegs := 0;
2158
    SumSegments(NegSegs, PosSegs);  { integral values }
2159
  end;
2160

2161
  try
2162
    with IntegrateXForm do
2163
    begin
2164
      if IntegCheckBox.Checked then { Plot Integral selected }
2165
      begin
2166
        MinIntegXLabel.Caption := 'Minimum: � = '+
2167
        FloatToStrF(IntegXMin, ffGeneral, 12, 8);
2168
        MinIntegYLabel.Caption := 'Minimum: r = '+
2169
        FloatToStrF(IntegYMin, ffGeneral, 12, 8);
2170

2171
        MaxIntegXLabel.Caption := 'Maximum: � = '+
2172
        FloatToStrF(IntegXMax, ffGeneral, 12, 8);
2173
        MaxIntegYLabel.Caption := 'Maximum: r = '+
2174
        FloatToStrF(IntegYMax, ffGeneral, 12, 8);
2175
      end;
2176

2177
      AreaLabel.Caption := 'Integral P[a, b] = '+
2178
      FloatToStrF(SumSect, ffGeneral, 12, 8);
2179

2180
      NegAreaLabel.Caption := '"Negative" Area = '+
2181
      FloatToStrF(NegSect, ffGeneral, 12, 8);
2182

2183
      PosAreaLabel.Caption := '"Positive" Area = '+
2184
      FloatToStrF(PosSect, ffGeneral, 12, 8);
2185

2186
      TotalAreaLabel.Caption := 'Total Area = '+
2187
      FloatToStrF(PosSect + NegSect, ffGeneral, 12, 8);
2188

2189
      SumAreaLabel.Caption := 'Sum Area = '+
2190
      FloatToStrF(SumSect, ffGeneral, 12, 8);
2191
    end;
2192

2193
    if SectorList.Count > 0 then
2194
    begin
2195
      SetupIntegral;
2196
      if IntegrateXForm.PlotIntegrated and piArea = piArea then ShadeArea;
2197
      if IntegrateXForm.PlotIntegrated and piShow = piShow then DrawIntegral;
2198
    end;
2199

2200
  finally
2201
    ClearPointList(SectorList);
2202
    SectorList := nil;
2203

2204
    ClearPointList(IntegList);
2205
    IntegList := nil;
2206
  end;
2207
end;    { TfxCanvas.IntegratePolar }
2208

2209
procedure TfxCanvas.IntegrateYCartesian;
2210

2211
  procedure SetupIntegral;
2212
  var
2213
    i: integer;
2214

2215
  begin   { SetupIntegral }
2216
    if Assigned(IntegList) then
2217
    for i := 0 to IntegList.Count -1 do
2218
    with TGraphPointObject(IntegList[i]) do
2219
    begin
2220
      PlotPoint.X := CoordX(x_phi);
2221
      PlotPoint.Y := CoordY(y_r);
2222
      if i = 0 then DrawLine := false;
2223
    end;
2224
  end;    { SetupIntegral }
2225

2226
  procedure ShadeArea;
2227
  var
2228
    i: integer;
2229
    xCoord: integer;
2230

2231
    procedure DrawShading;
2232
    var
2233
      yValue: extended;
2234
      x, y: integer;
2235

2236
    begin
2237
      with TGraphPointObject(IntegList[i]) do
2238
      begin
2239
        x := PlotPoint.X;
2240
        yValue := EvaluateFunction(x_phi);
2241

2242
        PenWidth := 1;
2243
        PenAlpha := GraphData.AreaAlpha;
2244
        y := CoordY(yValue);
2245

2246
        if x_Phi < 0
2247
        then PenColor := GraphData.NegAreaColor
2248
        else PenColor := GraphData.PosAreaColor;
2249

2250
        Line(x, y, xCoord, y);
2251
        PenAlpha := 1;
2252
      end;
2253
    end;
2254

2255
  begin   { ShadeArea }
2256
    xCoord := CoordX(0);
2257
    for i := 0 to IntegList.Count -1 do
2258
    with TGraphPointObject(IntegList[i]) do
2259
    if DrawLine then DrawShading;
2260
  end;    { ShadeArea }
2261

2262
        { TfxCanvas.IntegrateYCartesian }
2263
var
2264
  SumSegs: extended;
2265
  NegSegs: extended;
2266
  PosSegs: extended;
2267
  py1, py2: extended;
2268

2269
begin
2270
  IntegList := TList.Create;
2271
  try
2272
    NegSegs := 0;
2273
    PosSegs := 0;
2274
    SumSegs := SumYSegments(NegSegs, PosSegs);  { Cartesian }
2275

2276
    with IntegrateYForm do
2277
    begin
2278
      py1 := EvaluateFunction(IntegMin);
2279
      py2 := EvaluateFunction(IntegMax);
2280
      Label5.Caption := FloatToStrF(py1, ffFixed, 13, 4);
2281
      Label6.Caption := FloatToStrF(py2, ffFixed, 13, 4);
2282

2283
      NegAreaLabel.Caption := '"Negative" Area = '+
2284
      FloatToStrF(Abs(NegSegs), ffGeneral, 12, 8);
2285

2286
      PosAreaLabel.Caption := '"Positive" Area = '+
2287
      FloatToStrF(PosSegs, ffGeneral, 12, 8);
2288

2289
      TotalAreaLabel.Caption := 'Total Area = '+
2290
      FloatToStrF(PosSegs - NegSegs, ffGeneral, 12, 8);
2291

2292
      SumAreaLabel.Caption := 'Sum Area = '+
2293
      FloatToStrF(SumSegs, ffGeneral, 12, 8);
2294
    end;
2295

2296
    if IntegList.Count > 0 then
2297
    begin
2298
      SetupIntegral;
2299
      ShadeArea;
2300
    end;
2301
  finally
2302
    ClearPointList(IntegList);
2303
    IntegList := nil;
2304
  end;
2305
end;
2306

2307
procedure TfxCanvas.IntegrateBetweenFunctions;
2308
  procedure PopulateList;
2309
  var
2310
    i: integer;
2311
    h, x, y: extended;
2312
    p1X, p1Y: integer;
2313

2314
  begin
2315
    h := (IntegMax - IntegMin)/GraphData.IntegCount;  { calculate step }
2316
    x := IntegMin;
2317
    for i := 0 to GraphData.IntegCount do
2318
    begin
2319
      y := EvaluateFunction(x);
2320
      p1X := CoordX(x);
2321
      p1Y := CoordY(y);
2322

2323
      IntegList.Add(TGraphLineObject.Create(x, y));
2324
      TGraphLineObject(IntegList[i]).GraphLine.P1 := point(p1X, p1Y);
2325

2326
      x := x + h;    { next step }
2327
    end;
2328
  end;
2329

2330
  procedure AddDataToList;
2331
  var
2332
    i: integer;
2333
    p1X, p2Y: integer;
2334

2335
  begin
2336
    for i := 0 to IntegList.Count -1 do
2337
    with TGraphLineObject(IntegList[i]).GraphLine do
2338
    begin
2339
      y2 := EvaluateFunction(x);
2340
      p1X := P1.X;
2341
      p2Y := CoordY(y2);
2342
      P2 := point(p1X, p2Y);
2343
    end;
2344
  end;
2345

2346
  function SumBetweenSegs(var aNeg, aPos: extended): extended;
2347
  var
2348
    i: integer;
2349
    a, dx, dy1, dy2: extended;
2350
    gl1, gl2: TGraphLine;
2351

2352
  begin
2353
    if IntegMax = IntegMin then
2354
    begin
2355
      Result := 0;
2356
      Exit;
2357
    end;
2358

2359
    if IntegMax < IntegMin then
2360
    begin
2361
      a := IntegMax;
2362
      IntegMax := IntegMin;
2363
      IntegMin := a;
2364
      with IntegrateXForm do
2365
      begin
2366
        EditIntegMin.Text := FloatToStrF(IntegMin, ffGeneral, 13, 4);
2367
        EditIntegMax.Text := FloatToStrF(IntegMax, ffGeneral, 13, 4);
2368
      end;
2369
    end;
2370

2371
    gl1 := TGraphLineObject(IntegList[0]).GraphLine;
2372
    gl2 := TGraphLineObject(IntegList[1]).GraphLine;
2373
    dx := gl2.x - gl1.x;
2374

2375
    for i := 1 to IntegList.Count -1 do
2376
    begin
2377
      gl1 := TGraphLineObject(IntegList[i -1]).GraphLine;
2378
      gl2 := TGraphLineObject(IntegList[i]).GraphLine;
2379

2380
      with gl1 do dy1 := y1 - y2;
2381
      with gl2 do dy2 := y1 - y2;
2382

2383
      a := dx*(dy1 + dy2)/2;
2384
      if a > 0 then aPos := aPos + a else aNeg := aNeg - a;
2385
    end;
2386
    Result := aPos - aNeg;
2387
  end;
2388

2389
  procedure ShadeBetweenArea;
2390
  var
2391
    i: integer;
2392
    px: integer;
2393
    gl: TGraphLine;
2394

2395
  begin
2396
    px := CoordX(IntegMax);
2397
    for i := 0 to Integlist.Count -1 do
2398
    begin
2399
      gl := TGraphLineObject(Integlist[i]).GraphLine;
2400
      if gl.P1.X <> px then
2401
      begin
2402
        PenWidth := 1;
2403
        PenAlpha := GraphData.AreaAlpha;
2404

2405
        if  gl.y1 < gl.y2
2406
        then PenColor := GraphData.NegAreaColor
2407
        else PenColor := GraphData.PosAreaColor;
2408

2409
        Line(gl.P1.X, gl.P1.Y, gl.P2.X, gl.P2.Y);
2410
        PenAlpha := 1;
2411
      end;
2412

2413
      px := gl.P1.X;
2414
    end;
2415
  end;
2416

2417
  procedure ClearAndFreeList;
2418
  var
2419
    i: integer;
2420

2421
  begin
2422
    for i := 0 to IntegList.Count -1
2423
    do TGraphLineObject(IntegList[i]).Free;
2424
    IntegList.Free;
2425
    Integlist:= nil;
2426
  end;
2427

2428

2429
var
2430
  SumSegs: extended;
2431
  NegSegs: extended;
2432
  PosSegs: extended;
2433
  py1, py2: extended;
2434

2435
begin
2436
  with FunctionsForm.CheckListBox do
2437
  if (Count < 2) or (ItemIndex > 0) then exit;
2438
  IntegList := TList.Create;
2439
  try
2440
    with BetweenForm do
2441
    begin
2442
      py1 := EvaluateFunction(IntegMin);
2443
      py2 := EvaluateFunction(IntegMax);
2444
      Label5.Caption := FloatToStrF(py1, ffFixed, 13, 4);
2445
      Label6.Caption := FloatToStrF(py2, ffFixed, 13, 4);
2446
    end;
2447

2448
    PopulateList;       { setup the data of first function }
2449

2450
    with FunctionsForm.CheckListBox
2451
    do GraphData.PlotData := TPlotDataObject(Items.Objects[1]).Data;
2452
    with FxParser do
2453
    begin
2454
      Calculus.Free;
2455
      with GraphData.PlotData do
2456
      Calculus := Compile(AnsiLowerCase(FunctStr), ErrorByte);
2457
    end;
2458

2459
    AddDataToList;      { add the second function's data }
2460

2461
    NegSegs := 0;
2462
    PosSegs := 0;
2463
    SumSegs := SumBetweenSegs(NegSegs, PosSegs);
2464

2465
    ShadeBetweenArea;
2466
    with FunctionsForm.CheckListBox
2467
    do GraphData.PlotData := TPlotDataObject(Items.Objects[0]).Data;
2468

2469
    with BetweenForm do
2470
    begin
2471
      NegAreaLabel.Caption := '"Negative" Area = '+
2472
      FloatToStrF(NegSegs, ffGeneral, 12, 8);
2473

2474
      PosAreaLabel.Caption := '"Positive" Area = '+
2475
      FloatToStrF(PosSegs, ffGeneral, 12, 8);
2476

2477
      TotalAreaLabel.Caption := 'Total Area = '+
2478
      FloatToStrF(PosSegs + NegSegs, ffGeneral, 12, 8);
2479

2480
      SumAreaLabel.Caption := 'Sum Area = '+
2481
      FloatToStrF(SumSegs, ffGeneral, 12, 8);
2482
    end;
2483

2484
  finally
2485
    ClearAndFreeList;
2486
  end;
2487
end;    { TfxCanvas.IntegrateBetweenFunctions }
2488

2489
procedure TfxCanvas.IntegrateVolumeX;
2490

2491
  function SumVolumeXSegments(var aVol, aSur: extended): Boolean;
2492
  var
2493
    h: extended;      { step }
2494
    x: extended;
2495
    y, y1, y2: extended;
2496
    i, j: integer;
2497

2498
  begin
2499
    Result := false;
2500
    if IntegMax = IntegMin then Exit;
2501

2502
    if IntegMax < IntegMin then
2503
    begin
2504
      x := IntegMax;
2505
      IntegMax := IntegMin;
2506
      IntegMin := x;
2507
      with VolumeXForm do
2508
      begin
2509
        EditIntegMin.Text := FloatToStrF(IntegMin, ffGeneral, 13, 4);
2510
        EditIntegMax.Text := FloatToStrF(IntegMax, ffGeneral, 13, 4);
2511
      end;
2512
    end;
2513

2514
    h := (IntegMax - IntegMin)/GraphData.IntegCount;  { calculate step }
2515

2516
  { calculate numerical value to be used to display volume X }
2517
    x := IntegMin;
2518
    y1 := EvaluateFunction(x);
2519
    x := x + h;
2520
    j := 0;
2521
    for i := 1 to GraphData.IntegCount do
2522
 { calculate volume X using V = piR^2*h }
2523
    begin
2524
      y2 := EvaluateFunction(x);
2525
      if not (isNaN(y1) or isNaN(y2) or isInfinite(y1) or isInfinite(y2)) then
2526
      begin
2527
        y := (y1 + y2)/2;
2528
        aVol := aVol + pi*sqr(y)*h;  { volume is always positive }
2529
        aSur := aSur + 2*pi*abs(y)*h;
2530
      end
2531
      else Inc(j);   { count NaN's }
2532
      y1 := y2;      { update y1 }
2533
      x := x + h;    { next step }
2534
    end;  { for i := 0 to IntegCount do... }
2535
  { if all y values are NaN then Result is false }
2536
    Result := j < GraphData.IntegCount;
2537
  end;   { SumVolumeXSegments }
2538

2539
  procedure DrawVolumeX;
2540
  var
2541
    yCoord: integer;
2542
    i: integer;
2543
    StartIndex: integer;    { StartIndex = PlotList index for plot start }
2544
    FinishIndex: integer;   { FinishIndex = PlotList index for plot finish }
2545
    LastXCoord: integer;
2546
    dx: integer;
2547
    R1, R2: TRect;
2548

2549
  const
2550
    dxDiv: integer = 65;
2551

2552
  begin
2553
    yCoord := 2*CoordY(0);
2554

2555
  { find start }
2556
    i := 0;
2557
    StartIndex := -1;
2558
    LastXCoord := MaxInt;
2559
    while (i < PlotList.Count) and (StartIndex < 0) do
2560
    begin
2561
      with TGraphPointObject(PlotList[i]) do
2562
      begin
2563
        if (x_phi >= IntegMin) and (x_phi <= IntegMax) and
2564
            DrawLine and not(isNaN(y_r) or isInfinite(y_r)) and
2565
           (LastXCoord <> PlotPoint.X) then
2566
        begin
2567
          StartIndex := i;
2568
          dx := abs(2*PlotPoint.Y - yCoord) div dxDiv;
2569
          R1 := Rect(PlotPoint.X - dx +1, PlotPoint.Y,
2570
                     PlotPoint.X + dx +1, yCoord - PlotPoint.Y);
2571
        end;
2572
        LastXCoord := PlotPoint.X;
2573
      end;  { with TGraphPointObject(PlotList[i]) do... }
2574
      Inc(i);
2575
    end;  { (i < PlotList.Count) and (StartIndex < 0)... }
2576

2577
  { find finish }
2578
    i := PlotList.Count -1;
2579
    FinishIndex := -1;
2580
    LastXCoord := MaxInt;
2581
    while (i > 0) and (FinishIndex < 0) do
2582
    begin
2583
      with TGraphPointObject(PlotList[i]) do
2584
      begin
2585
        if (x_phi >= IntegMin) and (x_phi <= IntegMax) and
2586
            DrawLine and not(isNaN(y_r) or isInfinite(y_r)) and
2587
           (LastXCoord <> PlotPoint.X) then
2588
        begin
2589
          FinishIndex := i;
2590
          dx := abs(2*PlotPoint.Y - yCoord) div dxDiv;
2591
          R2 := Rect(PlotPoint.X - dx, PlotPoint.Y,
2592
                     PlotPoint.X + dx, yCoord - PlotPoint.Y);
2593
        end;
2594
        LastXCoord := PlotPoint.X;
2595
      end;  { with TGraphPointObject(PlotList[i]) do... }
2596
      Dec(i);
2597
    end;  { while (i > 0) and (FinishIndex < 0)... }
2598

2599
  { use shade positive pen }
2600
    PenAlpha := GraphData.AreaAlpha;
2601
    PenWidth := 1;
2602
    PenColor := GraphData.PosAreaColor;
2603

2604
    with R1 do if (Left > 0) and (Right < CanvasSizeX) then
2605
    begin
2606
      FillEllipseBB(Left, Top, right, Bottom);
2607
      FillQuadrantsBB(Left, Top, Right, Bottom, false, true, true, false);
2608
    end;
2609

2610
    LastXCoord := MaxInt;
2611
  { shade the solid volume X }
2612
    for i := StartIndex to FinishIndex do
2613
    with TGraphPointObject(PlotList[i]) do if DrawLine then
2614
    begin
2615
      if LastXCoord <> PlotPoint.X then
2616
      Line(PlotPoint.X, PlotPoint.Y, PlotPoint.X, yCoord - PlotPoint.Y);
2617
      LastXCoord := PlotPoint.X;
2618
    end;  { for i := StartIndex to FinishIndex do... }
2619

2620
    with R2 do FillQuadrantsBB(Left, Top, Right, Bottom,
2621
                               true, false, false, true);
2622

2623
  { outline solid }
2624
    PenAlpha := 1;
2625

2626
    with R1 do if (Left > 0) and (Right < CanvasSizeX)
2627
    then Arc(Left, Top, Right, Bottom, 3*pion2, pion2);
2628

2629
  { plot the positive section of function of f(x)}
2630
    LastXCoord := MaxInt;
2631
    for i := StartIndex to FinishIndex do
2632
    with TGraphPointObject(PlotList[i]) do
2633
    begin
2634
      if LastXCoord <> PlotPoint.X then
2635
      begin
2636
        if i = StartIndex
2637
        then MoveTo(PlotPoint.X, PlotPoint.Y)
2638
        else LineTo(PlotPoint.X, PlotPoint.Y);
2639
      end;
2640
      LastXCoord := PlotPoint.X;
2641
    end;  { for i := StartIndex to FinishIndex do... }
2642

2643
  { plot the negative function of f(x)}
2644
    LastXCoord := MaxInt;
2645
    for i := StartIndex to FinishIndex do
2646
    with TGraphPointObject(PlotList[i]) do
2647
    begin
2648
      if LastXCoord <> PlotPoint.X then
2649
      begin
2650
        if i = StartIndex
2651
        then MoveTo(PlotPoint.X, yCoord - PlotPoint.Y)
2652
        else LineTo(PlotPoint.X, yCoord - PlotPoint.Y);
2653
      end;
2654
      LastXCoord := PlotPoint.X;
2655
    end;  { for i := StartIndex to FinishIndex do... }
2656

2657
    PenAlpha := GraphData.AreaAlpha;
2658
  { use shade negative pen; shade solid's end }
2659
    PenColor := GraphData.NegAreaColor;
2660

2661
    with R2 do if (Left > 0) and (Right < CanvasSizeX)
2662
    then FillEllipseBB(Left, Top, Right, Bottom);
2663

2664
    PenAlpha := 1;
2665

2666
    with R2 do if (Left > 0) and (Right < CanvasSizeX)
2667
    then EllipseBB(Left, Top, Right, Bottom);
2668

2669
  { restore plot pen width }
2670
    PenWidth := GraphData.PlotData.PlotWidth;
2671
    PenColor := GraphData.PlotData.PlotColor;
2672
  end;
2673

2674

2675
var
2676
  VolSegs: extended;
2677
  SurSegs: extended;
2678
  py1, py2: extended;
2679

2680
begin
2681
  with VolumeXForm do
2682
  begin
2683
    py1 := EvaluateFunction(IntegMin);
2684
    py2 := EvaluateFunction(IntegMax);
2685
    Label5.Caption := FloatToStrF(py1, ffFixed, 13, 4);
2686
    Label6.Caption := FloatToStrF(py2, ffFixed, 13, 4);
2687
  end;
2688
  try
2689
    VolSegs := 0;  { Cartesian }
2690
    SurSegs := 0;
2691
    if not SumVolumeXSegments(VolSegs, SurSegs)
2692
    then Exit;  { SumVolumeXSegments is false there are no values to plot }
2693

2694
    DrawVolumeX;
2695

2696
    with VolumeXForm do
2697
    begin
2698
      TotalVolumeLabel.Caption :=
2699
     'Total Volume = '+FloatToStrF(VolSegs, ffGeneral, 12, 8);
2700
      SurfaceAreaLabel.Caption :=
2701
     'Surface Area = '+FloatToStrF(SurSegs, ffGeneral, 12, 8);
2702
    end
2703
  except
2704
  end;
2705
end;
2706

2707
procedure TfxCanvas.IntegrateVolumeY;
2708

2709
  function SumVolumeYSegments(var aVol, aSur: extended): Boolean;
2710
  var
2711
    h: extended;      { step }
2712
    x, x1, x2: extended;
2713
    y1, y2: extended;
2714
    i, j: integer;
2715

2716
  begin
2717
    Result := false;
2718
    if IntegMax = IntegMin then Exit;
2719

2720
    if IntegMax < IntegMin then
2721
    begin
2722
      x1 := IntegMax;
2723
      IntegMax := IntegMin;
2724
      IntegMin := x1;
2725
      with VolumeYForm do
2726
      begin
2727
        EditIntegMin.Text := FloatToStrF(IntegMin, ffGeneral, 13, 4);
2728
        EditIntegMax.Text := FloatToStrF(IntegMax, ffGeneral, 13, 4);
2729
      end;
2730
    end;
2731

2732
    h := (IntegMax - IntegMin)/GraphData.IntegCount;  { calculate step }
2733

2734
  { calculate numerical value to be used to display volume Y }
2735
    x1 := IntegMin;
2736
    y1 := EvaluateFunction(x1);
2737
    x2 := x1 + h;
2738
    j := 0;
2739
    for i := 1 to GraphData.IntegCount do
2740
 { calculate volume Y using V = piR^2*h }
2741
    begin
2742
      y2 := EvaluateFunction(x2);
2743
      if not (isNaN(y1) or isNaN(y2) or isInfinite(y1) or IsInfinite(y2)) then
2744
      begin
2745
        x := (x1 + x2)/2;
2746
        aVol := aVol + pi*sqr(x)*abs(y2 - y1); { volume is always positive }
2747
        aSur := aSur + 2*pi*abs(x)*abs(y2 - y1);
2748
      end
2749
      else Inc(j);
2750
      y1 := y2;        { update y1 }
2751
      x1 := x2;
2752
      x2 := x2 + h;    { next step }
2753
    end;  { for i := 0 to IntegCount do... }
2754
    Result := j < GraphData.IntegCount;
2755
  end;   { SumVolumeYSegments }
2756

2757
  procedure DrawVolumeY;
2758
  var
2759
    xCoord: integer;
2760
    i: integer;
2761
    j: integer;
2762
    StartIndex: integer;    { StartIndex = PlotList index for plot start }
2763
    FinishIndex: integer;   { FinishIndex = PlotList index for plot finish }
2764
    LastXCoord: integer;
2765
    LastYCoord: integer;
2766
    dy: integer;
2767
    R1, R2: TRect;
2768

2769
  const
2770
    dyDiv: integer = 65;
2771

2772
  begin
2773
    xCoord := 2*CoordX(0);
2774
  { find start }
2775
    i := 0;
2776
    StartIndex := -1;
2777
    LastXCoord := MaxInt;
2778
    while (i < PlotList.Count) and (StartIndex < 0) do
2779
    begin
2780
      with TGraphPointObject(PlotList[i]) do
2781
      begin
2782
        if (x_phi >= IntegMin) and (x_phi <= IntegMax) and
2783
            DrawLine and not(isNaN(y_r) or isInfinite(y_r)) and
2784
           (LastXCoord <> PlotPoint.X) then
2785
        begin
2786
          StartIndex := i - 1;
2787
          with TGraphPointObject(PlotList[StartIndex]) do
2788
          begin
2789
            dy := abs(2*PlotPoint.X - xCoord) div dyDiv;
2790
            R1 := Rect(PlotPoint.X, PlotPoint.Y - dy,
2791
                       xCoord - PlotPoint.X, PlotPoint.Y + dy);
2792
          end;
2793
        end;
2794
        LastXCoord := PlotPoint.X;
2795
      end;  { with TGraphPointObject(PlotList[i]) do... }
2796
      Inc(i);
2797
    end;  { (i < PlotList.Count) and (StartIndex < 0)... }
2798

2799
  { find finish }
2800
    i := PlotList.Count -2;
2801
    FinishIndex := -1;
2802
    LastXCoord := MaxInt;
2803
    while (i > 0) and (FinishIndex < 0) do
2804
    begin
2805
      with TGraphPointObject(PlotList[i]) do
2806
      begin
2807
        if (x_phi >= IntegMin) and (x_phi <= IntegMax) and
2808
            DrawLine and not(isNaN(y_r) or isInfinite(y_r)) and
2809
           (LastXCoord <> PlotPoint.X) then
2810
        begin
2811
          FinishIndex := i + 1;
2812
          with TGraphPointObject(PlotList[FinishIndex]) do
2813
          begin
2814
            dy := abs(2*PlotPoint.X - xCoord) div dyDiv;
2815
            R2 := Rect(PlotPoint.X, PlotPoint.Y - dy,
2816
                       xCoord - PlotPoint.X, PlotPoint.Y + dy);
2817
          end;
2818
        end;
2819
        LastXCoord := PlotPoint.X;
2820
      end;  { with TGraphPointObject(PlotList[i]) do... }
2821
      Dec(i);
2822
    end;  { while (i > 0) and (FinishIndex < 0)... }
2823

2824
    if StartIndex = FinishIndex then Exit;
2825

2826
    if TGraphPointObject(PlotList[StartIndex]).PlotPoint.Y >
2827
       TGraphPointObject(PlotList[FinishIndex]).PlotPoint.Y then
2828
    begin
2829
    { use shade positive pen }
2830
      PenAlpha := GraphData.AreaAlpha;
2831
      PenWidth := 1;
2832
      PenColor := GraphData.PosAreaColor;
2833

2834
      with R1 do
2835
      begin
2836
        FillEllipseBB(Left, Top, right, Bottom);
2837
        FillQuadrantsBB(Left, Top, Right, Bottom, false, false, true, true);
2838
      end;
2839

2840
      LastXCoord := MaxInt;
2841
      LastYCoord := TGraphPointObject(PlotList[StartIndex]).PlotPoint.Y;
2842

2843
    { shade the solid volume Y }
2844
      for i := StartIndex to FinishIndex do
2845
      with TGraphPointObject(PlotList[i]) do
2846
      begin
2847
        if (LastXCoord <> PlotPoint.X) and (LastYCoord <> PlotPoint.Y) then
2848
        Line(PlotPoint.X, PlotPoint.Y, xCoord - PlotPoint.X, PlotPoint.Y);
2849
        if DrawLine then
2850
        begin
2851
          dy := PlotPoint.Y - LastYCoord;
2852
          for j := 1 to abs(dy) - 1 do
2853
          Line(PlotPoint.X + trunc(j/dy), PlotPoint.Y + j,
2854
               xCoord - PlotPoint.X - trunc(j/dy), PlotPoint.Y + j);
2855
        end;
2856
        LastYCoord := PlotPoint.Y;
2857
        LastXCoord := PlotPoint.X;
2858
      end;  { for i := StartIndex to FinishIndex do... }
2859

2860
      with R2 do FillQuadrantsBB(Left, Top, Right, Bottom,
2861
                                 true, true, false, false);
2862
    { outline solid }
2863
      PenAlpha := 1;
2864

2865
      with R1 do Arc(Left, Top, Right, Bottom, pi, 0);
2866
      { plot the positive section of function of f(x)}
2867
      LastXCoord := MaxInt;
2868
      for i := StartIndex to FinishIndex do
2869
      with TGraphPointObject(PlotList[i]) do
2870
      begin
2871
        if LastXCoord <> PlotPoint.X then
2872
        begin
2873
          if i = StartIndex
2874
          then MoveTo(PlotPoint.X, PlotPoint.Y)
2875
          else LineTo(PlotPoint.X, PlotPoint.Y);
2876
        end;
2877
        LastXCoord := PlotPoint.X;
2878
      end;  { for i := StartIndex to FinishIndex do... }
2879

2880
    { plot the negative function of f(x)}
2881
      LastXCoord := MaxInt;
2882
      for i := StartIndex to FinishIndex do
2883
      with TGraphPointObject(PlotList[i]) do
2884
      begin
2885
        if LastXCoord <> PlotPoint.X then
2886
        begin
2887
          if i = StartIndex
2888
          then MoveTo(xCoord - PlotPoint.X, PlotPoint.Y)
2889
          else LineTo(xCoord - PlotPoint.X, PlotPoint.Y);
2890
        end;
2891
        LastXCoord := PlotPoint.X;
2892
      end;  { for i := StartIndex to FinishIndex do... }
2893

2894
      PenAlpha := GraphData.AreaAlpha;
2895
    { use shade negative pen; shade solid's end }
2896
      PenColor := GraphData.NegAreaColor;
2897
      with R2 do if Right < CanvasSizeX
2898
                 then FillEllipseBB(Left, Top, Right, Bottom);
2899

2900
      PenAlpha := 1;
2901
      with R2 do EllipseBB(Left, Top, Right, Bottom);
2902

2903
    { restore plot pen width }
2904
      PenWidth := GraphData.PlotData.PlotWidth;
2905
      PenColor := GraphData.PlotData.PlotColor;
2906
    end
2907
    else { TGraphPointObject(PlotList[StartIndex]).PlotPoint.Y <=
2908
           TGraphPointObject(PlotList[FinishIndex]).PlotPoint.Y  }
2909
    begin
2910
    { use shade positive pen }
2911
      PenAlpha := GraphData.AreaAlpha;
2912
      PenWidth := 1;
2913
      PenColor := GraphData.PosAreaColor;
2914

2915
      with R1 do
2916
      begin
2917
        FillEllipseBB(Left, Top, right, Bottom);
2918
        FillQuadrantsBB(Left, Top, Right, Bottom, true, true, false, false);
2919
      end;
2920

2921
      LastXCoord := MaxInt;
2922
      LastYCoord := TGraphPointObject(PlotList[StartIndex]).PlotPoint.Y;
2923

2924
    { shade the solid volume Y }
2925
      for i := FinishIndex downto StartIndex  do
2926
      with TGraphPointObject(PlotList[i]) do
2927
      begin
2928
        if (LastXCoord <> PlotPoint.X) and (LastYCoord <> PlotPoint.Y) then
2929
        Line(PlotPoint.X, PlotPoint.Y, xCoord - PlotPoint.X, PlotPoint.Y);
2930

2931
        if (i < FinishIndex) and DrawLine then
2932
        begin
2933
          dy := PlotPoint.Y - LastYCoord;
2934
          for j := 1 to abs(dy) -1 do
2935
          Line(PlotPoint.X - round(j/dy), PlotPoint.Y + j,
2936
               xCoord - PlotPoint.X + round(j/dy), PlotPoint.Y + j);
2937
        end;
2938
        LastYCoord := PlotPoint.Y;
2939
        LastXCoord := PlotPoint.X;
2940
      end;  { for i := FinishIndex downto StartIndex do... }
2941

2942
      with R2 do FillQuadrantsBB(Left, Top, Right, Bottom,
2943
                                 false, false, true, true);
2944
    { outline solid }
2945
      PenAlpha := 1;
2946

2947
      with R1 do Arc(Left, Top, Right, Bottom, 0, pi);
2948
    { plot the positive section of function of f(x)}
2949
      LastXCoord := MaxInt;
2950
      for i := StartIndex to FinishIndex do
2951
      with TGraphPointObject(PlotList[i]) do
2952
      begin
2953
        if LastXCoord <> PlotPoint.X then
2954
        begin
2955
          if i = StartIndex
2956
          then MoveTo(PlotPoint.X, PlotPoint.Y)
2957
          else LineTo(PlotPoint.X, PlotPoint.Y);
2958
        end;
2959
        LastXCoord := PlotPoint.X;
2960
      end;  { for i := StartIndex to FinishIndex do... }
2961

2962
    { plot the negative function of f(x)}
2963
      LastXCoord := MaxInt;
2964
      for i := StartIndex to FinishIndex do
2965
      with TGraphPointObject(PlotList[i]) do
2966
      begin
2967
        if LastXCoord <> PlotPoint.X then
2968
        begin
2969
          if i = StartIndex
2970
          then MoveTo(xCoord - PlotPoint.X, PlotPoint.Y)
2971
          else LineTo(xCoord - PlotPoint.X, PlotPoint.Y);
2972
        end;
2973
        LastXCoord := PlotPoint.X;
2974
      end;  { for i := StartIndex to FinishIndex do... }
2975

2976
      PenAlpha := GraphData.AreaAlpha;
2977
    { use shade negative pen; shade solid's end }
2978
      PenColor := GraphData.NegAreaColor;
2979
      with R2 do if Right < CanvasSizeX
2980
                 then FillEllipseBB(Left, Top, Right, Bottom);
2981

2982
      PenAlpha := 1;
2983
      with R2 do EllipseBB(Left, Top, Right, Bottom);
2984

2985
    { restore plot pen width }
2986
      PenWidth := GraphData.PlotData.PlotWidth;
2987
      PenColor := GraphData.PlotData.PlotColor;
2988
    end;
2989
  end;
2990

2991

2992
var
2993
  VolSegs: extended;
2994
  SurSegs: extended;
2995
  py1, py2: extended;
2996

2997
begin
2998
  with VolumeYForm do
2999
  begin
3000
    py1 := EvaluateFunction(IntegMin);
3001
    py2 := EvaluateFunction(IntegMax);
3002
    Label5.Caption := FloatToStrF(py1, ffFixed, 13, 4);
3003
    Label6.Caption := FloatToStrF(py2, ffFixed, 13, 4);
3004
  end;
3005

3006
  try
3007
    VolSegs := 0;  { Cartesian }
3008
    SurSegs := 0;
3009
    if not SumVolumeYSegments(VolSegs, SurSegs)
3010
    then exit;
3011

3012
    DrawVolumeY;
3013

3014
    with VolumeYForm do
3015
    begin
3016
      TotalVolumeLabel.Caption :=
3017
     'Total Volume = '+FloatToStrF(VolSegs, ffGeneral, 12, 8);
3018
      SurfaceAreaLabel.Caption :=
3019
     'Surface Area = '+FloatToStrF(SurSegs, ffGeneral, 12, 8);
3020
    end;
3021
  except
3022
  end;
3023
end;
3024

3025
procedure TfxCanvas.FindfxValues(const y: extended);
3026

3027
  procedure Interpolate(x1, x2, y1, y2: extended);
3028

3029
    procedure Display;
3030
    var
3031
      sx, sy: string;
3032

3033
    begin
3034
      x1 := (x1 + x2)/2;
3035
      y1 := EvaluateFunction(x1);
3036

3037
      if x1 < 0
3038
      then sx := ' '+Format('%g',[x1])
3039
      else sx := '  '+Format('%g',[x1]);
3040
      while Length(sx) < 24 do sx := sx + ' ';
3041

3042
      if y1 < 0
3043
      then sy := ' '+Format('%g',[y1])
3044
      else sy := '  '+Format('%g',[y1]);
3045
      while Length(sy) < 24 do sy := sy + ' ';
3046

3047
      fxValueForm.ListBox1.AddItem(sx + '|' + sy,
3048
      TFoundPointObject.Create(x1, 0, y1, GraphData.PlotData.PlotColor, 0));
3049
    end;
3050

3051
          { Interpolate f(x) }
3052
  const
3053
    dpMin = 1e-30;
3054

3055
  var
3056
    vx, vy: extended;
3057
    dx, dp: extended;
3058

3059
  begin
3060
    dx := (x2 - x1)/2;
3061
    dp := 1;
3062
    if y1 < y2 then
3063
    begin
3064
      while dp > dpMin do
3065
      begin
3066
        vx := x1 + dx;
3067
        vy := EvaluateFunction(vx);
3068
        if vy < y then x1 := vx
3069
        else
3070
        if vy > y then x2 := vx;
3071
        dx := dx/2;
3072
        dp := dp/2;
3073
      end;
3074
    end
3075
    else
3076
    begin
3077
      while dp > dpMin do
3078
      begin
3079
        vx := x1 + dx;
3080
        vy := EvaluateFunction(vx);
3081
        if vy < y then x2 := vx
3082
        else
3083
        if vy > y then x1 := vx;
3084
        dx := dx/2;
3085
        dp := dp/2;
3086
      end;
3087
    end;
3088
    Display;
3089
  end;
3090

3091

3092
var
3093
  i: integer;
3094
  y_rPrior: extended;
3095
  cy, dy: extended;
3096

3097
begin
3098
  i := 0;
3099
  y_rPrior := TGraphPointObject(PlotList[i]).y_r;
3100
  dy := abs(y - y_rPrior);  { difference y to find and current y }
3101
  cy := (GraphData.yMax - GraphData.yMin)/(CanvasSizeY*1000);
3102
  Inc(i);
3103

3104
  while i < PlotList.Count do
3105
  begin
3106
    with TGraphPointObject(PlotList[i]) do
3107
    begin
3108
      if not isNaN(y_r) then
3109
      begin
3110
        if (((y_rPrior <= y) and (y_r >= y)) or
3111
            ((y_rPrior >= y) and (y_r <= y)) or (dy < cy))
3112
        and not isNaN(TGraphPointObject(PlotList[i -1]).y_r)
3113
        then Interpolate(TGraphPointObject(PlotList[i -1]).x_phi, x_phi,
3114
                         TGraphPointObject(PlotList[i -1]).y_r, y_r);
3115
        y_rPrior := y_r;
3116
        dy := abs(y - y_rPrior);
3117
      end;
3118
      Inc(i);
3119
    end;
3120
  end;
3121
end;
3122

3123
procedure TfxCanvas.DrawfxPoints;
3124
var
3125
  i: integer;
3126
  p0, p1, p2: TPoint;
3127

3128
begin
3129
  with fxValueForm.ListBox1 do for i := 0 to Count -1 do
3130
  with TFoundPointObject(Items.Objects[i]) do
3131
  begin
3132
    with GraphData.Grid do
3133
    begin
3134
      if xAxisStyle = asLog
3135
      then p0.X := CoordLogX(xValue)
3136
      else p0.X := CoordX(xValue);
3137

3138
      if yAxisStyle = asLog
3139
      then p0.Y := CoordLogY(yValue)
3140
      else p0.Y := CoordY(yValue);
3141
    end;
3142
    p1.X := p0.X - 8;
3143
    p1.Y := p0.Y - 7;
3144
    p2.X := p0.X + 7;
3145
    p2.Y := p0.Y + 8;
3146

3147
    PenWidth := 2;
3148
    PenColor := Color;
3149
    MoveTo(p1.X, p0.Y);
3150
    LineTo(p2.X, p0.Y);
3151
    MoveTo(p0.X, p1.Y);
3152
    LineTo(p0.X, p2.Y);
3153
    Ellipse(p0.X, p0.Y, 8, 8);
3154
  end;
3155
end;
3156

3157
procedure TfxCanvas.Findfx1Values(const dy: extended);
3158
var
3159
  px: array[1..3] of extended;       { 3 points to consider }
3160
  py: array[1..3] of extended;       { 3 points to consider }
3161
  dybydx: array[1..2] of extended;   { 2 intervals to consider }
3162
  Mean: extended;
3163

3164
  procedure Interpolate;
3165
    procedure Display;
3166
    var
3167
      sx, sy: string;
3168

3169
    begin
3170
      if isNaN(px[2]) or isInfinite(px[2]) or
3171
         isNaN(Mean) or isInfinite(Mean) then Exit;
3172

3173
      if px[2] < 0
3174
      then sx := ' '+Format('%g',[px[2]])
3175
      else sx := '  '+Format('%g',[px[2]]);
3176
      while Length(sx) < 24 do sx := sx + ' ';
3177

3178
      if Mean < 0
3179
      then sy := ' '+Format('%g',[Mean])
3180
      else sy := '  '+Format('%g',[Mean]);
3181
      while Length(sy) < 24 do sy := sy + ' ';
3182

3183
      fx1ValueForm.ListBox1.AddItem(sx + '|' + sy,
3184
      TFoundPointObject.Create(px[2], Mean, py[2],
3185
       GraphData.PlotData.PlotColor, GraphData.dydxColor));
3186
    end;    { Display }
3187

3188
  var
3189
    dx: extended;
3190

3191
    procedure MoveLeft;
3192
    var
3193
      j: integer;
3194

3195
    begin
3196
      for j := 1 to 3 do px[j] := px[j] - dx;
3197
    end;
3198

3199
    procedure MoveRight;
3200
    var
3201
      j: integer;
3202

3203
    begin
3204
      for j := 1 to 3 do px[j] := px[j] + dx;
3205
    end;
3206

3207
 { Interpolate f'(x) }
3208

3209
  const
3210
    xDeltaMin = 7.88860905221012E-31;  { 1/2^100 }
3211

3212
  var
3213
    xDelta: extended;
3214
    j: integer;
3215

3216
  begin
3217
    xDelta := 1/8;
3218
    Mean := (dybydx[1] + dybydx[2])/2;
3219
    dx := (px[2] - px[1])*xDelta;
3220

3221
    while xDelta > xDeltaMin do
3222
    begin
3223
      if Mean > dy then
3224
      begin
3225
        if dybydx[2] > dybydx[1] then MoveLeft else MoveRight;
3226
      end
3227
      else  { Mean <= dy }
3228
      begin
3229
        if dybydx[2] > dybydx[1] then MoveRight else MoveLeft;
3230
      end;
3231

3232
      for j := 1 to 3 do py[j] := EvaluateFunction(px[j]);
3233

3234
      for j := 1 to 2 do dybydx[j] := (py[j +1] - py[j])/(px[j +1] - px[j]);
3235

3236
      Mean := (dybydx[1] + dybydx[2])/2;
3237
      xDelta := xDelta/2;
3238
      dx := dx/2;
3239
    end;
3240

3241
    Display;
3242
  end;
3243

3244

3245
var
3246
  i: integer;
3247
  j: integer;
3248

3249
begin
3250
  i := 1;
3251
  while i < PlotList.Count -1 do
3252
  begin
3253
    for j := 1 to 3 do
3254
    with TGraphPointObject(PlotList[i + j - 2]) do
3255
    begin
3256
      px[j] := x_phi;
3257
      py[j] := y_r;
3258
    end;
3259

3260
    if not(isNaN(py[1]) or isNaN(py[2]) or isNaN(py[3])) then
3261
    begin
3262
    { calculate dy/dx (f'x) for the 2 intervals }
3263
      for j := 1 to 2 do dybydx[j] := (py[j +1] - py[j])/(px[j +1] - px[j]);
3264

3265
      if (((dybydx[1] <= dy) and (dybydx[2] >= dy)) or
3266
          ((dybydx[1] >= dy) and (dybydx[2] <= dy)))
3267
      then Interpolate;
3268
    end;
3269
    Inc(i);
3270
  end;
3271
end;
3272

3273
procedure TfxCanvas.Drawfx1Points;
3274
var
3275
  i: integer;
3276
  p0, p1, p2: TPoint;
3277

3278
begin
3279
  with fx1ValueForm.ListBox1 do for i := 0 to Count -1 do
3280
  with TFoundPointObject(Items.Objects[i]) do
3281
  begin
3282
    with GraphData.Grid do
3283
    begin
3284
      if xAxisStyle = asLog
3285
      then p0.X := CoordLogX(xValue)
3286
      else p0.X := CoordX(xValue);
3287

3288
      if yAxisStyle = asLog
3289
      then p0.Y := CoordLogY(yValue)
3290
      else p0.Y := CoordY(yValue);
3291
    end;
3292
    p1.X := p0.X - 8;
3293
    p1.Y := p0.Y - 7;
3294
    p2.X := p0.X + 7;
3295
    p2.Y := p0.Y + 8;
3296

3297
    PenWidth := 2;
3298
    PenColor := Color;
3299
    MoveTo(p1.X, p0.Y);
3300
    LineTo(p2.X, p0.Y);
3301
    MoveTo(p0.X, p1.Y);
3302
    LineTo(p0.X, p2.Y);
3303
    Ellipse(p0.X, p0.Y, 8, 8);
3304

3305
    if FunctionsForm.yfx1.Checked then
3306
    begin
3307
      if GraphData.Grid.yAxisStyle = asLog
3308
      then p0.Y := CoordLogY(mValue)
3309
      else p0.Y := CoordY(mValue);
3310

3311
      p1.Y := p0.Y - 7;
3312
      p2.Y := p0.Y + 8;
3313
      PenColor := mColor;
3314

3315
      MoveTo(p1.X, p0.Y);
3316
      LineTo(p2.X, p0.Y);
3317
      MoveTo(p0.X, p1.Y);
3318
      LineTo(p0.X, p2.Y);
3319
      Ellipse(p0.X, p0.Y, 8, 8);
3320
    end;
3321
  end;
3322
end;
3323

3324
procedure TfxCanvas.Findfx2Values(const d2y: Extended);
3325
var
3326
  px: array[1..5] of extended;       { 5 points to consider }
3327
  py: array[1..5] of extended;       { 5 points to consider }
3328
  dybydx: array[1..4] of extended;   { 4 intervals to consider }
3329
  d2ybydx2: array[1..2] of extended; { 2 intervals to consider }
3330
  Mean: extended;
3331

3332
  procedure Interpolate;
3333
  const
3334
    xDeltaMin = 7.88860905221012E-31;  { 1/2^100 }
3335
  var
3336
    dx: extended;
3337
    xDelta: extended;
3338
    j: integer;
3339

3340
    procedure Display;
3341
    var
3342
      sx, sy: string;
3343
    begin
3344
      if isNaN(px[3]) or isInfinite(px[3]) or
3345
         isNaN(Mean) or isInfinite(Mean) then Exit;
3346
      if px[3] < 0
3347
      then sx := ' '+Format('%g',[px[3]])
3348
      else sx := '  '+Format('%g',[px[3]]);
3349
      while Length(sx) < 24 do sx := sx + ' ';
3350

3351
      if Mean < 0
3352
      then sy := ' '+Format('%g',[Mean])
3353
      else sy := '  '+Format('%g',[Mean]);
3354
      while Length(sy) < 24 do sy := sy + ' ';
3355
      fx2ValueForm.ListBox1.AddItem(sx + '|' + sy,
3356
      TFoundPointObject.Create(px[3], Mean, py[3],
3357
       GraphData.PlotData.PlotColor, GraphData.d2ydx2Color));
3358
    end;
3359

3360

3361
    procedure MoveLeft;
3362
    var
3363
      j: integer;
3364

3365
    begin
3366
      for j := 1 to 5 do px[j] := px[j] - dx;
3367
    end;
3368

3369
    procedure MoveRight;
3370
    var
3371
      j: integer;
3372

3373
    begin
3374
      for j := 1 to 5 do px[j] := px[j] + dx;
3375
    end;
3376

3377

3378
  begin
3379
    xDelta := 1/8;
3380
    Mean := (d2ybydx2[1] + d2ybydx2[2])/2;
3381
    dx := (px[2] - px[1])*xDelta;
3382

3383
    while xDelta > xDeltaMin do
3384
    begin
3385
      if Mean > d2y then
3386
      begin
3387
        if d2ybydx2[2] > d2ybydx2[1] then MoveLeft else MoveRight;
3388
      end
3389
      else  { Mean <= d2y }
3390
      begin
3391
        if d2ybydx2[2] > d2ybydx2[1] then MoveRight else MoveLeft;
3392
      end;
3393

3394
      for j := 1 to 5 do py[j] := EvaluateFunction(px[j]);
3395

3396
    { calculate dy/dx (f'x) for the four intervals }
3397
      for j := 1 to 4 do
3398
      dybydx[j] := (py[j +1] - py[j])/(px[j +1] - px[j]);
3399
    { calculate d2y/dx� (f"x) for the two intervals  }
3400
      for j := 1 to 2 do
3401
      d2ybydx2[j] := (dybydx[j +1] - dybydx[j])/(px[j +1] - px[j]);
3402

3403
      Mean := (d2ybydx2[1] + d2ybydx2[2])/2;
3404
      xDelta := xDelta/2;
3405
      dx := dx/2;
3406
    end;
3407

3408
    Display;
3409
  end;
3410

3411
var
3412
  i: integer;
3413
  j: integer;
3414

3415
begin
3416
  i := 2;
3417
  while i < PlotList.Count -2 do
3418
  begin
3419
    for j := 1 to 5 do
3420
    with TGraphPointObject(PlotList[i + j - 3]) do
3421
    begin
3422
      px[j] := x_phi;
3423
      py[j] := y_r;
3424
    end;
3425

3426
    if not(isNaN(py[1]) or isNaN(py[2]) or isNaN(py[3]) or
3427
           isNaN(py[4]) or isNaN(py[5])) then
3428
    begin
3429
    { calculate dy/dx (f'x) for the four intervals }
3430
      for j := 1 to 4 do
3431
      dybydx[j] := (py[j +1] - py[j])/(px[j +1] - px[j]);
3432
    { calculate d2y/dx� (f"x) for the two intervals  }
3433
      for j := 1 to 2 do
3434
      d2ybydx2[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) }
3437
      if (((d2ybydx2[1] <= d2y) and (d2ybydx2[2] >= d2y)) or
3438
          ((d2ybydx2[1] >= d2y) and (d2ybydx2[2] <= d2y)))
3439
      then Interpolate;
3440
    end;
3441

3442
    Inc(i);
3443
  end;
3444
end;
3445

3446
procedure TfxCanvas.Drawfx2Points;
3447
var
3448
  i: integer;
3449
  p0, p1, p2: TPoint;
3450

3451
begin
3452
  with fx2ValueForm.ListBox1 do for i := 0 to Count -1 do
3453
  with TFoundPointObject(Items.Objects[i]) do
3454
  begin
3455
    with GraphData.Grid do
3456
    begin
3457
      if xAxisStyle = asLog
3458
      then p0.X := CoordLogX(xValue)
3459
      else p0.X := CoordX(xValue);
3460

3461
      if yAxisStyle = asLog
3462
      then p0.Y := CoordLogY(yValue)
3463
      else p0.Y := CoordY(yValue);
3464
    end;
3465
    p1.X := p0.X - 8;
3466
    p1.Y := p0.Y - 7;
3467
    p2.X := p0.X + 7;
3468
    p2.Y := p0.Y + 8;
3469

3470
    PenWidth := 2;
3471
    PenColor := Color;
3472
    MoveTo(p1.X, p0.Y);
3473
    LineTo(p2.X, p0.Y);
3474
    MoveTo(p0.X, p1.Y);
3475
    LineTo(p0.X, p2.Y);
3476
    Ellipse(p0.X, p0.Y, 8, 8);
3477

3478
    if FunctionsForm.yfx2.Checked then
3479
    begin
3480
      if GraphData.Grid.yAxisStyle = asLog
3481
      then p0.Y := CoordLogY(mValue)
3482
      else p0.Y := CoordY(mValue);
3483
      p1.Y := p0.Y - 7;
3484
      p2.Y := p0.Y + 8;
3485
      PenColor := mColor;
3486

3487
      MoveTo(p1.X, p0.Y);
3488
      LineTo(p2.X, p0.Y);
3489
      MoveTo(p0.X, p1.Y);
3490
      LineTo(p0.X, p2.Y);
3491
      Ellipse(p0.X, p0.Y, 8, 8);
3492
    end;
3493
  end;
3494
end;
3495

3496
procedure TfxCanvas.DrawCartesianCoordinates;
3497
var
3498
  x, y: integer;
3499

3500
begin
3501
  PenWidth := GraphData.CoordWidth;
3502
  PenColor := GraphData.CoordColor;
3503

3504
  with GraphData.Grid do
3505
  begin
3506
    if xAxisStyle = asLog
3507
    then x := CoordLogX(xEvaluate)
3508
    else x := CoordX(xEvaluate);
3509

3510
    if yAxisStyle = asLog
3511
    then y := CoordLogY(yEvaluate)
3512
    else y := CoordY(yEvaluate);
3513
  end;
3514

3515
  MoveTo(x, 0);
3516
  LineTo(x, CanvasSizeY);
3517
  MoveTo(0, y);
3518
  LineTo(CanvasSizeX, y);
3519
end;
3520

3521
procedure TfxCanvas.DrawPolarCoordinates;
3522
var
3523
  x, y: integer;
3524

3525
begin
3526
  PenWidth := GraphData.CoordWidth;
3527
  PenColor := GraphData.CoordColor;
3528

3529
  x := CoordX(yCosxEval);
3530
  y := CoordY(ySinxEval);
3531
  MoveTo(CoordX(0), CoordY(0));
3532
  LineTo(x, y);
3533
  MoveTo(x, 0);
3534
  LineTo(x, CanvasSizeY);
3535
  MoveTo(0, y);
3536
  LineTo(CanvasSizeX, y);
3537
end;
3538

3539
procedure TfxCanvas.DrawNumericData;
3540
{ Hermite }
3541
const
3542
  StepPts = 500;
3543

3544
var
3545
  ePoints: TList;               { list of TGraphPoint }
3546
{ Hermite }
3547

3548
  function sk(x: extended; n: word): extended;  {resolution factor }
3549
  var
3550
    nt: integer;
3551

3552
  begin
3553
    Result := 1;
3554
    for nt := 1 to n do Result := Result*x;
3555
  end;
3556

3557
  function xp(k, j, i: integer): extended;
3558
  var
3559
    n: extended;
3560

3561
  begin
3562
    n := (j +1)/StepPts;
3563
    with NumericForm.CheckListBox do
3564
    with TNumericObject(Items.Objects[i]) do
3565
    Result := ((2*sk(n, 3) -
3566
                3*sk(n, 2) +1)*TGraphPointObject(ControlPoints[k]).x_phi -
3567
               (2*sk(n, 3) -
3568
                3*sk(n, 2))*TGraphPointObject(ControlPoints[k +1]).x_phi +
3569
               (sk(n, 3) -
3570
                2*sk(n, 2) + n)*TGraphPointObject(ePoints[k]).x_phi +
3571
               (sk(n, 3) -
3572
                sk(n, 2))*TGraphPointObject(ePoints[k +1]).x_phi);
3573
  end;
3574

3575
  function yp(k, j, i: integer): extended;
3576
  var
3577
    n: extended;
3578

3579
  begin
3580
    n := (j +1)/StepPts;
3581
    with NumericForm.CheckListBox do
3582
    with TNumericObject(Items.Objects[i]) do
3583
    Result := ((2*sk(n, 3) -
3584
                3*sk(n, 2) +1)*TGraphPointObject(ControlPoints[k]).y_r -
3585
               (2*sk(n, 3) -
3586
                3*sk(n, 2))*TGraphPointObject(ControlPoints[k +1]).y_r +
3587
               (sk(n, 3) -
3588
                2*sk(n, 2) + n)*TGraphPointObject(ePoints[k]).y_r +
3589
               (sk(n, 3) -
3590
                sk(n, 2))*TGraphPointObject(ePoints[k +1]).y_r);
3591

3592
  end;
3593

3594
  procedure DrawTarget(const x, y: extended; const c: TColor);
3595
  var
3596
    i: integer;
3597
    p0, p1, p2: TPoint;
3598

3599
  begin
3600
    with GraphData.Grid do
3601
    begin
3602
      if xAxisStyle = asLog
3603
      then p0.X := CoordLogX(x)
3604
      else p0.X := CoordX(x);
3605

3606
      if yAxisStyle = asLog
3607
      then p0.Y := CoordLogY(y)
3608
      else p0.Y := CoordY(y);
3609
    end;
3610
    p1.X := p0.X - 8;
3611
    p1.Y := p0.Y - 7;
3612
    p2.X := p0.X + 7;
3613
    p2.Y := p0.Y + 8;
3614
    PenWidth := 2;
3615
    PenColor := c;
3616
    MoveTo(p1.X, p0.Y);
3617
    LineTo(p2.X, p0.Y);
3618
    MoveTo(p0.X, p1.Y);
3619
    LineTo(p0.X, p2.Y);
3620
    Ellipse(p0.X, p0.Y, 8, 8);
3621
  end;
3622

3623
var
3624
  FirstPoint, LastPoint: integer;
3625
  Start, Stop, Step, vx, vy: extended;
3626
  p, a, d: extended;
3627
  i, j, k, w: integer;
3628
  Ordered: Boolean;
3629
  x_phiWas: extended;
3630
  c: TColor;
3631

3632
{ Hermite }
3633
  k0: extended;   { see CurveRate }
3634
  ePoint: TGraphPoint;
3635
{ Hermite }
3636

3637
begin   { TfxCanvas.DrawNumericData }
3638
  with NumericForm.CheckListBox do if Count > 0 then
3639
  begin
3640
    for i := 0 to Count -1 do
3641
    with TNumericObject(Items.Objects[i]) do if Checked[i] then
3642
    begin
3643
      if ControlPoints.Count > 0 then
3644
      begin
3645
        FirstPoint := 0;  { first control point index }
3646
      { ignore negative values if Log x axis }
3647
        if GraphData.Grid.xAxisStyle = asLog then
3648
        while (FirstPoint < ControlPoints.Count) and
3649
              (TGraphPointObject(ControlPoints[FirstPoint]).x_phi <= 0)
3650
          do Inc(FirstPoint);
3651

3652
      { ignore negative values if Log y axis }
3653
        if GraphData.Grid.yAxisStyle = asLog then
3654
        while (FirstPoint < ControlPoints.Count) and
3655
              (TGraphPointObject(ControlPoints[FirstPoint]).y_r <= 0)
3656
        do Inc(FirstPoint);
3657

3658
        if FirstPoint = ControlPoints.Count then Exit;
3659

3660
        w := 2*Data.PointSize;
3661
        PenColor := Data.PointColor;
3662
        if Data.PointSize < 3 then PenWidth := 2
3663
        else PenWidth := 2*Data.PointSize div 3 ;
3664

3665
        x_phiWas := -1e200;
3666

3667
        LastPoint := ControlPoints.Count -1;
3668

3669
      { points must be ordered and not repeat; Loops if first = last }
3670
        Ordered := TGraphPointObject(ControlPoints[FirstPoint]).x_phi <>
3671
                   TGraphPointObject(ControlPoints[LastPoint]).x_phi;
3672
        if Data.ShowPoints then
3673
        begin
3674
          for j := FirstPoint to LastPoint do
3675
          with TGraphPointObject(ControlPoints[j]) do
3676
          begin
3677
            if GraphData.Grid.xAxisStyle = asLog
3678
            then PlotPoint.X := CoordLogX(x_phi)
3679
            else
3680
            begin
3681
              if Data.CoordsIdx = 1
3682
              then PlotPoint.X := CoordX(y_r*Cos(x_phi))
3683
              else PlotPoint.X := CoordX(x_phi);
3684
            end;
3685

3686
            if x_phi < x_phiWas then Ordered := False;
3687
            x_phiWas := x_phi;
3688

3689
            if GraphData.Grid.yAxisStyle = asLog
3690
            then PlotPoint.Y := CoordLogY(y_r)
3691
            else
3692
            begin
3693
              if Data.CoordsIdx = 1
3694
              then PlotPoint.Y := CoordY(y_r*Sin(x_phi))
3695
              else PlotPoint.Y := CoordY(y_r);
3696
            end;
3697

3698
            case Data.PointStyle of
3699
            psSquare:
3700
            begin
3701
              MoveTo(PlotPoint.X - w, PlotPoint.Y - w);
3702
              LineTo(PlotPoint.X + w, PlotPoint.Y - w);
3703
              LineTo(PlotPoint.X + w, PlotPoint.Y + w);
3704
              LineTo(PlotPoint.X - w, PlotPoint.Y + w);
3705
              LineTo(PlotPoint.X - w, PlotPoint.Y - w);
3706
            end;
3707
            psPlus:
3708
              begin
3709
                MoveTo(PlotPoint.X, PlotPoint.Y - w);
3710
                LineTo(PlotPoint.X, PlotPoint.Y + w +1);
3711
                MoveTo(PlotPoint.X - w, PlotPoint.Y);
3712
                LineTo(PlotPoint.X + w, PlotPoint.Y);
3713
              end;
3714
            psCross:
3715
              begin
3716
                MoveTo(PlotPoint.X + w, PlotPoint.Y - w);
3717
                LineTo(PlotPoint.X - w, PlotPoint.Y + w +1);
3718
                MoveTo(PlotPoint.X - w, PlotPoint.Y - w);
3719
                LineTo(PlotPoint.X + w, PlotPoint.Y + w +1);
3720
              end;
3721
            psCircle:
3722
                Ellipse(PlotPoint.X, PlotPoint.Y, w, w);
3723
            end;
3724
          end;  { with TPointObject(Points[j]) do... }
3725

3726
        end;
3727

3728
        PenColor := Data.PlotColor;
3729
        PenWidth := Data.PlotWidth;
3730

3731
        ClearPointList(Plotlist);   { clear & free }
3732
        PlotList := TList.Create;
3733

3734
        case Data.NumericStyle of
3735
        nsLinear:
3736
          begin
3737
            with TGraphPointObject(ControlPoints[FirstPoint]) do
3738
            begin
3739
              if GraphData.Grid.xAxisStyle = asLog
3740
              then PlotPoint.X := CoordLogX(x_phi)
3741
              else
3742
              begin
3743
                if Data.CoordsIdx = 1
3744
                then PlotPoint.X := CoordX(y_r*Cos(x_phi))
3745
                else PlotPoint.X := CoordX(x_phi);
3746
              end;
3747

3748
              if GraphData.Grid.yAxisStyle = asLog
3749
              then PlotPoint.Y := CoordLogY(y_r)
3750
              else
3751
              begin
3752
                if Data.CoordsIdx = 1
3753
                then PlotPoint.Y := CoordY(y_r*Sin(x_phi))
3754
                else PlotPoint.Y := CoordY(y_r);
3755
              end;
3756

3757
              MoveTo(PlotPoint.X, PlotPoint.Y);
3758
            end;
3759

3760
            for j := FirstPoint +1 to LastPoint do
3761
            with TGraphPointObject(ControlPoints[j]) do
3762
            begin
3763
              if GraphData.Grid.xAxisStyle = asLog
3764
              then PlotPoint.X := CoordLogX(x_phi)
3765
              else
3766
              begin
3767
                if Data.CoordsIdx = 1
3768
                then PlotPoint.X := CoordX(y_r*Cos(x_phi))
3769
                else PlotPoint.X := CoordX(x_phi);
3770
              end;
3771

3772
              if GraphData.Grid.yAxisStyle = asLog
3773
              then PlotPoint.Y := CoordLogY(y_r)
3774
              else
3775
              begin
3776
                if Data.CoordsIdx = 1
3777
                then PlotPoint.Y := CoordY(y_r*Sin(x_phi))
3778
                else PlotPoint.Y := CoordY(y_r);
3779
              end;
3780

3781
              LineTo(PlotPoint.X, PlotPoint.Y);
3782
            end
3783
          end;  { nsLinear }
3784

3785
        nsLagrange: if Ordered and (Data.CoordsIdx <> 1) then
3786
          begin
3787
            if Data.Extrapolate then
3788
            begin
3789
              Start := GraphData.xMin;
3790
              Stop := GraphData.xMax;
3791
            end
3792
            else
3793
            begin
3794
              Start := TGraphPointObject(ControlPoints[FirstPoint]).x_phi;
3795
              Stop :=  TGraphPointObject(ControlPoints[LastPoint]).x_phi;
3796
            end;
3797
            j := TGraphPointObject(ControlPoints[FirstPoint]).PlotPoint.X;
3798
            k := TGraphPointObject(ControlPoints[LastPoint]).PlotPoint.X;
3799
            Step := (Stop - Start)/(k - j);
3800
            vx := Start;
3801
            while vx <= Stop + Step do
3802
            begin
3803
              vy := 0;
3804
              for j := FirstPoint to LastPoint do
3805
              begin
3806
                p := 1;
3807
                for k := FirstPoint to LastPoint do
3808
                if j <> k then  { if xj = xk then xj - xk = 0 i.e. d = 0 }
3809
                begin
3810
                  d := TGraphPointObject(ControlPoints[j]).x_phi -
3811
                       TGraphPointObject(ControlPoints[k]).x_phi;
3812
                  a := (vx - TGraphPointObject(ControlPoints[k]).x_phi)/d;
3813
                  p := p*a;
3814
                end;
3815
                vy := vy + p*TGraphPointObject(ControlPoints[j]).y_r;
3816
              end;
3817
              with PlotList do
3818
              begin
3819
                Add(TGraphPointObject.Create(vx, vy));
3820
                with TGraphPointObject(Items[Count -1]) do
3821
                begin
3822
                  if GraphData.Grid.xAxisStyle = asLog
3823
                  then PlotPoint.X := CoordLogX(x_phi)
3824
                  else PlotPoint.X := CoordX(x_phi);
3825

3826
                  if GraphData.Grid.yAxisStyle = asLog
3827
                  then PlotPoint.Y := CoordLogY(y_r)
3828
                  else PlotPoint.Y := CoordY(y_r);
3829

3830
                  DrawLine := Count > 1;
3831
                end;
3832
              end;
3833
              vx := vx + Step;
3834
            end;
3835

3836
            with GraphData.PlotData do
3837
            begin
3838
              PlotWidth := PenWidth;
3839
              PlotColor := PenColor;
3840
            end;
3841
            DrawCartesian(PlotList);     { draw the graph }
3842
          end;
3843

3844
        nsHermite:
3845

3846
          begin
3847
            if ((GraphData.Grid.xAxisStyle = asLog) or
3848
               (GraphData.Grid.yAxisStyle = asLog)) and
3849
               (FirstPoint > 0) then Exit;
3850

3851
            k0 := Data.CurveRate/100;
3852
            ePoints := TList.Create;
3853
            if ControlPoints.Count > 1 then
3854
            begin
3855
            { set ePoints; first two ControlPoints k - j = 1 }
3856
              j := FirstPoint;
3857
              k := FirstPoint +1;
3858
              ePoint.x := (TGraphPointObject(ControlPoints[k]).x_phi -
3859
                           TGraphPointObject(ControlPoints[j]).x_phi)*k0;
3860
              ePoint.y := (TGraphPointObject(ControlPoints[k]).y_r -
3861
                           TGraphPointObject(ControlPoints[j]).y_r)*k0;
3862
              ePoints.Add(TGraphPointObject.Create(ePoint.x, ePoint.y));
3863
            { set ePoints; mid ControlPoints j + 1 - (j - 1) = 2 }
3864
              for j := FirstPoint +1 to LastPoint -1 do
3865
              begin
3866
                ePoint.x := (TGraphPointObject(ControlPoints[j +1]).x_phi -
3867
                             TGraphPointObject(ControlPoints[j -1]).x_phi)*k0;
3868
                ePoint.y := (TGraphPointObject(ControlPoints[j +1]).y_r -
3869
                             TGraphPointObject(ControlPoints[j -1]).y_r)*k0;
3870
                ePoints.Add(TGraphPointObject.Create(ePoint.x, ePoint.y));
3871
              end;
3872
            { set ePoints; last two ControlPoints k - j = 1 }
3873
              j := LastPoint -1;
3874
              k := LastPoint;
3875
              ePoint.x := (TGraphPointObject(ControlPoints[k]).x_phi -
3876
                           TGraphPointObject(ControlPoints[j]).x_phi)*k0;
3877
              ePoint.y := (TGraphPointObject(ControlPoints[k]).y_r -
3878
                           TGraphPointObject(ControlPoints[j]).y_r)*k0;
3879
              ePoints.Add(TGraphPointObject.Create(ePoint.x, ePoint.y));
3880
            end;
3881

3882
            with PlotList do  { start PlotList at first control point }
3883
            begin
3884
              with TGraphPointObject(ControlPoints[0]) do
3885
              Add(TGraphPointObject.Create(x_phi, y_r));
3886
              with TGraphPointObject(Items[Count -1]) do
3887
              begin
3888
                if GraphData.Grid.xAxisStyle = asLog
3889
                then PlotPoint.X := CoordLogX(x_phi)
3890
                else
3891
                begin
3892
                  if Data.CoordsIdx = 1
3893
                  then PlotPoint.X := CoordX(y_r*Cos(x_phi))
3894
                  else PlotPoint.X := CoordX(x_phi);
3895
                end;
3896

3897
                if GraphData.Grid.yAxisStyle = asLog
3898
                then PlotPoint.Y := CoordLogY(y_r)
3899
                else
3900
                begin
3901
                  if Data.CoordsIdx = 1
3902
                  then PlotPoint.Y := CoordY(y_r*Sin(x_phi))
3903
                  else PlotPoint.Y := CoordY(y_r);
3904
                end;
3905
                DrawLine := Count > 1;
3906
              end;
3907

3908
              for k := FirstPoint to ControlPoints.Count do
3909
              if k < ControlPoints.Count -1 then
3910
              for j := 0 to StepPts -1 do
3911
              begin
3912
                with TGraphPointObject(ControlPoints[FirstPoint]) do
3913
                Add(TGraphPointObject.Create(xp(k, j, i), yp(k, j, i)));
3914
                with TGraphPointObject(Items[Count -1]) do
3915
                begin
3916
                  if GraphData.Grid.xAxisStyle = asLog
3917
                  then PlotPoint.X := CoordLogX(x_phi)
3918
                  else
3919
                  begin
3920
                    if Data.CoordsIdx = 1
3921
                    then PlotPoint.X := CoordX(y_r*Cos(x_phi))
3922
                    else PlotPoint.X := CoordX(x_phi);
3923
                  end;
3924

3925
                  if GraphData.Grid.yAxisStyle = asLog
3926
                  then PlotPoint.Y := CoordLogY(y_r)
3927
                  else
3928
                  begin
3929
                    if Data.CoordsIdx = 1
3930
                    then PlotPoint.Y := CoordY(y_r*Sin(x_phi))
3931
                    else PlotPoint.Y := CoordY(y_r);
3932
                  end;
3933
                  DrawLine := Count > 1;
3934
                end;
3935
              end;
3936
            end;
3937

3938
            with GraphData.PlotData do
3939
            begin
3940
              PlotWidth := PenWidth;
3941
              PlotColor := PenColor;
3942
            end;
3943

3944
            DrawCartesian(PlotList);     { draw the graph }
3945
            ClearPointList(ePoints);
3946
          end;
3947
        end;  { case Data.NumericStyle of }
3948

3949
        with NumericForm do
3950
        begin
3951
          if Visible and (InputRG.ItemIndex > 0) and
3952
                    (CheckListBox.ItemIndex = i) then
3953
          begin
3954
            j := CheckListBox.ItemIndex;
3955
            k := DataListBox.ItemIndex;
3956
            with TNumericObject(Items.Objects[j]) do
3957
            begin
3958
              c := Data.PlotColor;
3959
              with TGraphPointObject(ControlPoints[k]) do
3960
              begin
3961
                vx := x_phi;
3962
                vy := y_r;
3963
              end;
3964
            end;
3965

3966
            case CoordsRG.ItemIndex of
3967
            0:DrawTarget(vx, vy, c);  { Cartesian }
3968
            1:begin                   { Polar }
3969
                with TGraphPointObject(ControlPoints[k]) do
3970
                begin
3971
                  vx := y_r*Cos(x_phi);
3972
                  vy := y_r*Sin(x_phi);
3973
                  DrawTarget(vx, vy, c);
3974
                  Line(CoordX(0), CoordY(0), CoordX(vx), CoordY(vy));
3975
                end;
3976
              end;
3977
            2:begin                   { As Vector }
3978
                DrawTarget(vx, vy, c);
3979
                if k > 0 then
3980
                with TGraphPointObject(ControlPoints[k -1]) do
3981
                begin
3982
                  vx := x_phi;
3983
                  vy := y_r;
3984
                  DrawTarget(vx, vy, c);
3985
                end;
3986
              end;
3987
            end;
3988
          end;
3989
        end;
3990
      end;  { if Points.Count > 0 then... }
3991
    end;  { with TNumericObject(Items.Objects[i]) do if Checked[i] then... }
3992
  end;  { with NumericForm.CheckListBox do if Count > 0 then... }
3993
end;  { TfxCanvas.DrawNumericData }
3994

3995

3996
procedure TfxCanvas.DrawTextBlocks(var rci: TGLRenderContextInfo;
3997
                                   var wbf: TGLWindowsBitmapFont);
3998
var
3999
  i, j, k, x, y: integer;
4000

4001
begin
4002
  with TextBlocksForm.BlockListBox do if Count > 0 then
4003
  begin
4004
    StopPrimitive;
4005
    for i := 0 to Count -1 do
4006
    with TTextDataObject(Items.Objects[i]) do if Checked[i] then
4007
    begin
4008
      SetGLWinBitFont(rci, wbf, Data.FontName, Data.FontSize, Data.FontStyle);
4009
      for j := 0 to Items.Count -1 do if Checked[j] then
4010
      begin
4011
        if GraphData.Grid.xAxisStyle = asLog
4012
        then x := CoordLogX(Data.xLoc)
4013
        else x := CoordX(Data.xLoc);
4014

4015
        if GraphData.Grid.yAxisStyle = asLog
4016
        then y := CoordLogY(Data.yLoc)
4017
        else y := CoordY(Data.yLoc);
4018

4019
        for k := 0 to TextLines.Count -1 do
4020
        with TTextLineObject(TextLines[k])do
4021
        wbf.TextOut(rci, x, y + k*Data.yInc, Text, Color);
4022
      end;
4023
    end;
4024
  end;
4025
  with GraphData do SetGLWinBitFont(rci, wbf, FontName, FontSize, FontStyle);
4026
  SetupFont(rci, wbf);
4027
end;
4028

4029
procedure TfxCanvas.ClearTextList;
4030
var
4031
  i: integer;
4032

4033
begin
4034
  for i := 0 to TextList.Count -1 do TTextLocObject(TextList[i]).Free;
4035
  TextList.Free;
4036
end;
4037

4038
procedure TfxCanvas.ClearPointList(var L: TList);
4039
var
4040
  i: integer;
4041

4042
begin
4043
  if Assigned(L) then
4044
  begin
4045
    for i := 0 to L.Count -1 do TGraphPointObject(L[i]).Free;
4046
    L.Free;
4047
    L := nil;
4048
  end;
4049
end;
4050

4051
function TfxCanvas.SumSegments(var aNeg, aPos: extended): extended;
4052
var
4053
  a: extended;      { integral area }
4054
  h: extended;      { step }
4055
  isOK: Boolean;    { OK to draw line }
4056
  x, x1, x2: extended;
4057
  y, y1, y2: extended;
4058
  my: extended;
4059
  i: integer;
4060
  m: integer;
4061
  LastXCoord: integer;
4062

4063
begin  { SumSegments }
4064
  if IntegMax = IntegMin then
4065
  begin
4066
    Result := 0;
4067
    Exit;
4068
  end;
4069

4070
  if IntegMax < IntegMin then
4071
  begin
4072
    a := IntegMax;
4073
    IntegMax := IntegMin;
4074
    IntegMin := a;
4075
    with IntegrateXForm do
4076
    begin
4077
      EditIntegMin.Text := FloatToStrF(IntegMin, ffGeneral, 13, 4);
4078
      EditIntegMax.Text := FloatToStrF(IntegMax, ffGeneral, 13, 4);
4079
    end;
4080
  end;
4081

4082
  h := (IntegMax - IntegMin)/GraphData.IntegCount;  { calculate step }
4083
  a := 0;  { initial area = 0 }
4084

4085
{ calculate numerical value to be used to display area }
4086
  x := IntegMin;
4087
  for i := 0 to GraphData.IntegCount do
4088
  begin  { calculate area using Simpson's rule }
4089
  { h/3(y0 + 4y1 + 2y2 + 4y3 +...+ 2y(i-2) + 4y(i-1) + y(i)) }
4090
    y := EvaluateFunction(x);
4091
    if not isNaN(y) then
4092
    begin
4093
      if odd(i) then m := 4 else
4094
      if (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

4098
      my := m*y;     { m*f(x(i)) for i = 0 to Count }
4099
      a := a + my;   { add to sum }
4100
      if y < 0 then aNeg := aNeg + my else aPos := aPos + my;
4101
    end;
4102

4103
    x := x + h;    { next step }
4104
  end;  { for i := 0 to IntegCount do... }
4105

4106
  aNeg := aNeg*h/3;
4107
  aPos := aPos*h/3;
4108
  Result := aPos + aNeg;
4109
{-------------------------------------------------------------}
4110
  a := 0;  { initial area = 0 }
4111
  LastXCoord := MaxInt;
4112

4113
{ calculate value for each segment to be used to plot integral }
4114
  IntegYMin := 1.1e308;
4115
  IntegYMax := -IntegYMin;
4116

4117
  x := IntegMin;  { start }
4118
  x1 := x + h;    { one step }
4119
  x2 := x1 + h;   { two steps }
4120

4121
  for i := 0 to GraphData.IntegCount div 2 do
4122
  begin
4123
    isOK := true;
4124
    y := EvaluateFunction(x);
4125

4126
    if isNaN(y) then
4127
    begin
4128
      isOK := false;
4129
      y := 0;
4130
    end;
4131

4132
    y1 := EvaluateFunction(x1);
4133
    if isNaN(y1) then
4134
    begin
4135
      isOK := false;
4136
      y1 := 0;
4137
    end;
4138

4139
    y2 := EvaluateFunction(x2);
4140
    if isNaN(y2) then
4141
    begin
4142
      isOK := false;
4143
      y2 := 0;
4144
    end;
4145

4146
    a := a + h*(y + 4*y1 + y2)/3;
4147
  { Simpson's rule h/3(y + 4y1 + y2) }
4148
    y := a + IntegConst;
4149

4150
    if x1 <= IntegMax then
4151
    begin
4152
      if y < IntegYMin then IntegYMin := y;
4153
      if y > IntegYMax then IntegYMax := y;
4154
    { only add a GraphPoint for each pixel horizontally }
4155
      if LastXCoord <> CoordX(x1) then
4156
      begin
4157
        IntegList.Add(TGraphPointObject.Create(x1, y));
4158
        TGraphPointObject(
4159
        IntegList[IntegList.Count -1]).DrawLine := isOK;
4160
      end;
4161
      LastXCoord := CoordX(x1)
4162
    end;
4163
    x := x2;        { increase two steps }
4164
    x1 := x + h;    { increase one step }
4165
    x2 := x1 + h;   { increase one step }
4166
  end;
4167

4168
  i := 0;                    { get IntegXMin }
4169
  with TGraphPointObject(IntegList[i]) do
4170
  begin
4171
    isOK := DrawLine;
4172
    IntegXMin := x_phi;
4173
  end;
4174

4175
  while not isOK and (i < IntegList.Count) do
4176
  begin
4177
    with TGraphPointObject(IntegList[i]) do isOK := DrawLine;
4178
    Inc(i);
4179
  end;
4180
  if i > 0 then Dec(i);
4181
  with TGraphPointObject(IntegList[i]) do IntegXMin := x_phi;
4182

4183

4184
  i := IntegList.Count -1;   { get IntegXMax }
4185
  with TGraphPointObject(IntegList[i]) do
4186
  begin
4187
    isOK := DrawLine;
4188
    IntegXMax := x_phi;
4189
  end;
4190

4191
  while not isOK and (i > 0) do
4192
  begin
4193
    with TGraphPointObject(IntegList[i]) do isOK := DrawLine;
4194
    Dec(i);
4195
  end;
4196
  if i < IntegList.Count -1 then Inc(i);
4197
  with TGraphPointObject(IntegList[i]) do IntegXMax := x_phi;
4198
end;
4199

4200
function TfxCanvas.SumYSegments(var aNeg, aPos: Extended): extended;
4201
var
4202
  a: extended;   { integral area }
4203
  h: extended;   { step }
4204
  x1, x2, y1, y2: extended;
4205
  i: integer;
4206
  LastYCoord: integer;
4207

4208
begin  { SumYSegments }
4209
  if IntegMax = IntegMin then
4210
  begin
4211
    Result := 0;
4212
    Exit;
4213
  end;
4214

4215
  if IntegMax < IntegMin then
4216
  begin
4217
    a := IntegMax;
4218
    IntegMax := IntegMin;
4219
    IntegMin := a;
4220
    with IntegrateYForm do
4221
    begin
4222
      EditIntegMin.Text := FloatToStrF(IntegMin, ffGeneral, 13, 4);
4223
      EditIntegMax.Text := FloatToStrF(IntegMax, ffGeneral, 13, 4);
4224
    end;
4225
  end;
4226

4227
  h := (IntegMax - IntegMin)/GraphData.IntegCount;  { calculate step }
4228
  a := 0;  { initial area = 0 }
4229

4230
  LastYCoord := MaxInt;
4231
  aNeg := a;
4232
  aPos := a;
4233

4234
  x1 := IntegMin;
4235
  x2 := x1 + h;
4236
  y1 := EvaluateFunction(x1);
4237
  y2 := EvaluateFunction(x2);
4238

4239
  for i := 0 to GraphData.IntegCount do
4240
  begin
4241
    if not(isNAN(y1) or isNAN(y2)) then
4242
    begin
4243
      a := abs(y2 - y1)*(x1 + x2)/2;
4244
      if (x1 < 0) and (x2 <= 0) then aNeg := aNeg + a else aPos := aPos + a;
4245
    { only add a GraphPoint for each pixel vertically }
4246
      if LastYCoord <> CoordY(y1) then
4247
      IntegList.Add(TGraphPointObject.Create(x1, y1));
4248
      TGraphPointObject(IntegList[IntegList.Count -1]).DrawLine := True;
4249
    end
4250
    else
4251
    begin
4252
    { only add a GraphPoint for each pixel vertically }
4253
      if LastYCoord <> CoordY(y1) then
4254
      IntegList.Add(TGraphPointObject.Create(x1, y1));
4255
      TGraphPointObject(IntegList[IntegList.Count -1]).DrawLine := False;
4256
    end;
4257
    LastYCoord := CoordY(y1);
4258

4259
    x1 := x2;
4260
    x2 := x2 + h;
4261
    y1 := y2;
4262
    y2 := EvaluateFunction(x2);
4263
  end;
4264
  Result := aPos + aNeg;
4265
end;   { SumYSegments }
4266

4267
procedure TfxCanvas.QuadVertices(x, y, xRadius, yRadius: Single;
4268
                                 q1, q2, q3, q4: Boolean);
4269
var
4270
  i, n: Integer;
4271
  s, c: TSingleArray;
4272

4273
begin
4274
  n := Round(MaxFloat(xRadius, yRadius) * 0.1) + 5;
4275
  SetLength(s, n);
4276
  SetLength(c, n);
4277
  Dec(n);
4278
  PrepareSinCosCache(s, c, 0, 90);
4279
  ScaleFloatArray(s, yRadius);
4280
  ScaleFloatArray(c, xRadius);
4281
{ first quadrant; top right }
4282
  if q1 then for i := 0 to n do glVertex2f(x + c[i], y - s[i]);
4283

4284
{ second quadrant; top left }
4285
  if q2 then for i := n - 1 downto 0 do glVertex2f(x - c[i], y - s[i]);
4286

4287
{ third quadrant; bottom left }
4288
  if q3 then for i := 1 to n do glVertex2f(x - c[i], y + s[i]);
4289

4290
{ fourth quadrant; bottom right }
4291
  if q4 then for i := n - 1 downto 0 do glVertex2f(x + c[i], y + s[i]);
4292
end;
4293

4294
procedure TfxCanvas.FillEllipseBB(const x1, y1, x2, y2: Integer);
4295
begin
4296
  FillEllipse((x1 + x2)*0.5, (y1 + y2)*0.5, Abs(x2 - x1)*0.5, Abs(y2 - y1)*0.5);
4297
end;
4298

4299
procedure TfxCanvas.FillEllipseBB(const x1, y1, x2, y2: Single);
4300
begin
4301
  FillEllipse((x1 + x2)*0.5, (y1 + y2)*0.5, Abs(x2 - x1)*0.5, Abs(y2 - y1)*0.5);
4302
end;
4303

4304
procedure TfxCanvas.FillQuadrants(const x, y: Integer;
4305
                                  const xRadius, yRadius: Single;
4306
                                        q1, q2, q3, q4: Boolean);
4307
begin
4308
  StartPrimitive(GL_TRIANGLE_FAN);
4309
  glVertex2f(x, y); { not really necessary, but may help with memory stride }
4310
  QuadVertices(x, y, xRadius, yRadius, q1, q2, q3, q4);
4311
  StopPrimitive;
4312
end;
4313

4314
procedure TfxCanvas.FillQuadrantsBB(const x1, y1, x2, y2: Integer;
4315
                                q1, q2, q3, q4: Boolean);
4316
begin
4317
  FillQuadrants((x1 + x2) div 2, (y1 + y2) div 2,
4318
             Abs(x1 - x2) div 2, Abs(y1 - y2) div 2, q1, q2, q3, q4);
4319
end;
4320

4321
procedure TfxCanvas.StartRadialFill(const x, y: integer);
4322
begin
4323
  StartPrimitive(GL_TRIANGLE_FAN);
4324
  glVertex2f(x, y);
4325
end;
4326

4327
procedure TfxCanvas.FillSector(x, y: Integer);
4328
begin
4329
  glVertex2f(x, y);
4330
end;
4331

4332
procedure TfxCanvas.StopRadialFill;
4333
begin
4334
  StopPrimitive;
4335
end;
4336

4337
procedure TfxCanvas.SetupFont(var rci: TGLRenderContextInfo;
4338
                              var wbf: TGLWindowsBitmapFont);
4339
begin
4340
  wbf.TextOut(rci, -10, -30, 'y = f(x)', clRed);
4341
  CharW := wbf.GetCharWidth('M');
4342
  CharH := wbf.CharHeight;
4343
end;
4344

4345
procedure TfxCanvas.SetGLWinBitFont(var rci: TGLRenderContextInfo;
4346
                                    var wbf: TGLWindowsBitmapFont;
4347
                        Nm: string; Sz: Integer; St: TFontStyles);
4348
begin
4349
  with wbf.Font do
4350
  begin
4351
    Name := Nm;
4352
    Size := Sz;
4353
    Style := St;
4354
  end;
4355
end;
4356

4357
procedure TfxCanvas.xAxisGradsCalc(var wbf: TGLWindowsBitmapFont);
4358
var
4359
  xCoord: integer;
4360

4361
begin
4362
  CharW := wbf.GetCharWidth('M');
4363
  CharH := wbf.CharHeight;
4364

4365
  dxGrad := 0.1;
4366
  dx10Grad := 1;
4367

4368
  with GraphData do
4369
  begin
4370
    xCoord := CoordX(xMin + dxGrad);
4371

4372
                  { major X axis graduation lengths }
4373
    while (xCoord > xMajorGrad) or (xCoord < 0) do
4374
    begin
4375
      dxGrad := dxGrad/10;
4376
      xCoord := CoordX(xMin + dxGrad);
4377
    end;
4378
                 { minor X axis graduation lengths }
4379
    while xCoord < xMinorGrad do
4380
    begin
4381
      dxGrad := dxGrad*10;
4382
      xCoord := CoordX(xMin + dxGrad);
4383
    end;
4384
  end;
4385

4386
  dx10Grad := 10*dxGrad;  { major x graduation space }
4387
  if dxGrad < 1           { calculate number of digits }
4388
  then xDigits := round(-log10(dxGrad)) -1
4389
  else xDigits := round(log10(dxGrad)) +1;
4390
end;
4391

4392
procedure TfxCanvas.yAxisGradsCalc(var wbf: TGLWindowsBitmapFont);
4393
var
4394
  yCoord: integer;
4395

4396
begin
4397
  CharW := wbf.GetCharWidth('M');
4398
  CharH := wbf.CharHeight;
4399

4400
  dyGrad := 0.1;
4401
  dy10Grad := 1;
4402

4403
  with GraphData do
4404
  begin
4405
    yCoord := CoordY(yMin) - CoordY(yMin + dyGrad);
4406
                  { major Y axis graduation lengths }
4407
    while (yCoord > yMajorGrad) or (yCoord < 0) do
4408
    begin
4409
      dyGrad := dyGrad/10;
4410
      yCoord := CoordY(yMin) - CoordY(yMin + dyGrad);
4411
    end;
4412
                  { minor Y axis graduation lengths }
4413
    while yCoord < yMinorGrad do
4414
    begin
4415
      dyGrad := dyGrad*10;
4416
      yCoord := CoordY(yMin) - CoordY(yMin + dyGrad);
4417
    end;
4418
  end;
4419

4420
  dy10Grad := 10*dyGrad;  { major y graduation space }
4421
  if dyGrad < 1           { calculate number of digits }
4422
  then yDigits := round(-log10(dyGrad)) -1
4423
  else yDigits := round(log10(dyGrad)) +1;
4424
end;
4425

4426
procedure TfxCanvas.DrawTextList(var rci: TGLRenderContextInfo; L: TList;
4427
                                 var wbf: TGLWindowsBitmapFont);
4428
var
4429
  i: integer;
4430
  t: TTextLocObject;
4431

4432
begin
4433
  StopPrimitive;
4434
  for i := 0 to L.Count -1 do
4435
  begin
4436
    t := TTextLocObject(L.Items[i]);
4437
    wbf.TextOut(rci, t.xLoc, t.yLoc, t.TextString, t.TextColor);
4438
  end;
4439
end;
4440

4441
procedure TfxCanvas.DrawAxes;
4442
begin
4443
  with GraphData.Grid do
4444
  begin
4445
    case GridStyle of
4446
    gsCartesian:
4447
    begin
4448
      if xAxisStyle = asLog then DrawXGridLog else DrawXGridLinear;
4449
      if yAxisStyle = asLog then DrawYGridLog else DrawYGridLinear;
4450
    end;
4451
    gsPolar:
4452
      DrawPolarGrid;
4453
    end;
4454
    if xAxisStyle = asLog then DrawXAxisLog else DrawXAxisLinear;
4455
    if yAxisStyle = asLog then DrawYAxisLog else DrawYAxisLinear;
4456
  end;
4457
end;
4458

4459
procedure TfxCanvas.DrawFunctions;
4460
var
4461
  i: integer;
4462

4463
begin
4464
  with FunctionsForm.CheckListBox do
4465
  begin
4466
    for i := 0 to Items.Count -1 do if Checked[i] then
4467
    begin
4468
      GraphData.PlotData := TPlotDataObject(Items.Objects[i]).Data;
4469
      ClearPointList(PlotList);
4470
      PlotList := TList.Create;
4471

4472
      with FxParser do
4473
      begin
4474
        if i > 0 then Calculus.Free;
4475

4476
        ErrorByte := 0;
4477
        MainForm.StatusBar.Panels[2].Text := '';
4478
        with GraphData.PlotData do
4479
        Calculus := Compile(AnsiLowerCase(FunctStr), ErrorByte);
4480

4481
        if ErrorByte > 0 then
4482
        begin
4483
          with MainForm.StatusBar.Panels[2] do
4484
          case ErrorByte of
4485
            1:Text := 'Check Brackets for "'+
4486
                       GraphData.PlotData.FunctStr+'"';
4487
            2:Text := 'Unable to Parse "'+
4488
                       GraphData.PlotData.FunctStr+'"';
4489
          end;
4490
        end;
4491
      end;
4492
      PlotFunction(i = ItemIndex);  { Selected := i = ItemIndex }
4493
    end;
4494
  end;
4495
end;
4496

4497
end.
4498

Использование cookies

Мы используем файлы cookie в соответствии с Политикой конфиденциальности и Политикой использования cookies.

Нажимая кнопку «Принимаю», Вы даете АО «СберТех» согласие на обработку Ваших персональных данных в целях совершенствования нашего веб-сайта и Сервиса GitVerse, а также повышения удобства их использования.

Запретить использование cookies Вы можете самостоятельно в настройках Вашего браузера.