MathgeomGLS
1253 строки · 33.4 Кб
1unit fPlot3D;
2
3interface
4
5uses
6Winapi.Windows,
7Winapi.Messages,
8System.SysUtils,
9System.Variants,
10System.Classes,
11System.IniFiles,
12System.DateUtils,
13System.UITypes,
14System.Math,
15Vcl.Graphics,
16Vcl.Controls,
17Vcl.Forms,
18Vcl.Dialogs,
19Vcl.ComCtrls,
20Vcl.Menus,
21Vcl.ExtDlgs,
22
23GLS.OpenGLTokens,
24GLS.PersistentClasses,
25GLS.Scene,
26GLS.VectorTypes,
27GLS.GeomObjects,
28GLS.HUDObjects,
29GLS.Objects,
30GLS.Graph,
31GLS.Coordinates,
32
33GLS.SceneViewer,
34GLS.BitmapFont,
35GLS.WindowsFont,
36GLS.Particles,
37GLS.Color,
38GLS.BaseClasses,
39GLS.VectorGeometry,
40GLS.State,
41GLS.Material,
42
43uGlobal,
44uParser,
45fEvaluate,
46fGridColors,
47fAddPlotColors,
48fCoordOptions,
49fGridOptions,
50fDerivativeOptions,
51fPlotColors,
52fAbout;
53
54type
55TViewForm = class(TForm)
56GLSViewer: TGLSceneViewer;
57GLScene: TGLScene;
58GLLight: TGLLightSource;
59CameraCube: TGLDummyCube;
60Camera: TGLCamera;
61GLxyGrid: TGLXYZGrid;
62Fields: TGLDummyCube;
63GLWinBmpFont: TGLWindowsBitmapFont;
64StatusBar: TStatusBar;
65MainMenu: TMainMenu;
66File1: TMenuItem;
67New1: TMenuItem;
68Options1: TMenuItem;
69DefaultLayout1: TMenuItem;
70OpenFile: TMenuItem;
71Save1: TMenuItem;
72Saveas1: TMenuItem;
73Exit1: TMenuItem;
74Grid1: TMenuItem;
75GridColours1: TMenuItem;
76Evaluate1: TMenuItem;
77GLxzGrid: TGLXYZGrid;
78GLyzGrid: TGLXYZGrid;
79TargetCube: TGLDummyCube;
80xCoordLine: TGLLines;
81yCoordLine: TGLLines;
82zCoordLine: TGLLines;
83BoxLine1: TGLLines;
84BoxLine2: TGLLines;
85BoxLine3: TGLLines;
86BoxLine4: TGLLines;
87CoordText1: TMenuItem;
88YCoordsCube: TGLDummyCube;
89XCoordsCube: TGLDummyCube;
90ZCoordsCube: TGLDummyCube;
91xArrow: TGLArrowLine;
92yArrow: TGLArrowLine;
93Recent1: TMenuItem;
94DerivativeOps: TMenuItem;
95AddedField: TGLDummyCube;
96AddXLine: TGLLines;
97AddYLine: TGLLines;
98AddZLine: TGLLines;
99PlotColours1: TMenuItem;
100DerivativePlotColours1: TMenuItem;
101VolumeLines: TGLDummyCube;
102N2: TMenuItem;
103N3: TMenuItem;
104N4: TMenuItem;
105Help1: TMenuItem;
106About1: TMenuItem;
107procedure FormCreate(Sender: TObject);
108procedure FormShow(Sender: TObject);
109procedure FormCloseQuery(Sender: TObject; var CanClose: Boolean);
110procedure GLSViewerMouseDown(Sender: TObject; Button: TMouseButton;
111Shift: TShiftState; X, Y: Integer);
112procedure GLSViewerMouseMove(Sender: TObject; Shift: TShiftState;
113X, Y: Integer);
114procedure GLSViewerMouseUp(Sender: TObject; Button: TMouseButton;
115Shift: TShiftState; X, Y: Integer);
116procedure FormMouseWheel(Sender: TObject; Shift: TShiftState;
117WheelDelta: Integer; MousePos: TPoint; var Handled: Boolean);
118procedure FormKeyDown(Sender: TObject; var Key: Word; Shift: TShiftState);
119procedure FormKeyUp(Sender: TObject; var Key: Word; Shift: TShiftState);
120procedure DefaultLayout1Click(Sender: TObject);
121procedure Exit1Click(Sender: TObject);
122procedure Grid1Click(Sender: TObject);
123procedure GridColours1Click(Sender: TObject);
124procedure Evaluate1Click(Sender: TObject);
125procedure New1Click(Sender: TObject);
126procedure OpenFileClick(Sender: TObject);
127procedure Save1Click(Sender: TObject);
128procedure Saveas1Click(Sender: TObject);
129procedure FormDestroy(Sender: TObject);
130procedure FormActivate(Sender: TObject);
131procedure CoordText1Click(Sender: TObject);
132procedure RecentFilesClick(Sender: TObject);
133procedure FormClose(Sender: TObject; var Action: TCloseAction);
134procedure DerivativeOpsClick(Sender: TObject);
135procedure PlotColours1Click(Sender: TObject);
136procedure DerivativePlotColours1Click(Sender: TObject);
137procedure About1Click(Sender: TObject);
138private
139AtStart: Boolean;
140SelectedData: TPlotData; // data used to evaluate dz/dx or dz/dy
141procedure ShowCameraLocation;
142procedure ShowFocalLength;
143procedure ShowLightLocation;
144procedure DefaultView;
145procedure DefaultLayout;
146procedure Formulate(const X, Y: Single; var z: Single;
147var Color: TGLColorVector; var texPoint: TTexPoint);
148procedure CreateHeightFields(const n: Integer);
149procedure PlotFunctions;
150procedure CreateAddedField;
151procedure PlotDerivativeField;
152procedure PlotIntegralField;
153public
154MousePoint: TPoint;
155procedure ShowDisplacement;
156procedure UpdatePlot;
157procedure UpdateAdded;
158procedure ClearAddedField;
159procedure ClearAddedLines;
160end;
161
162const
163crLightxz = 1;
164crLightyz = 2;
165crLightxy = 3;
166crSlidexy = 4;
167crSlideyz = 5;
168crSlidexz = 6;
169crRotate = 7;
170crZoom = 8;
171crHandMove = 9;
172crSlidezy = 10;
173
174var
175ViewForm: TViewForm;
176
177// =====================================================================
178implementation
179// =====================================================================
180
181{$R *.dfm}
182{$R CURSORS.RES}
183
184uses
185fFunctions;
186
187procedure TViewForm.FormCreate(Sender: TObject);
188begin
189BinPath := ExtractFilePath(ParamStr(0));
190BinPath := IncludeTrailingPathDelimiter(BinPath);
191// PlotPath := BinPath;
192// Delete(PlotPath, Length(PlotPath) - 4, 4);
193DataPath := BinPath + 'Examples\'; // PlotPath
194SetCurrentDir(DataPath);
195ImagePath := BinPath + 'Images\';
196LayoutFName := BinPath + 'Layout.lay';
197RecentFName := BinPath + 'Recent.ini';
198
199Screen.Cursors[crLightxy] := LoadCursor(HInstance, 'LIGHTXY');
200Screen.Cursors[crLightyz] := LoadCursor(HInstance, 'LIGHTYZ');
201Screen.Cursors[crLightxz] := LoadCursor(HInstance, 'LIGHTXZ');
202Screen.Cursors[crSlidexy] := LoadCursor(HInstance, 'SLIDEXY');
203Screen.Cursors[crSlidexz] := LoadCursor(HInstance, 'SLIDEXZ');
204Screen.Cursors[crSlideyz] := LoadCursor(HInstance, 'SLIDEYZ');
205Screen.Cursors[crRotate] := LoadCursor(HInstance, 'ROTATE');
206Screen.Cursors[crZoom] := LoadCursor(HInstance, 'ZOOM');
207Screen.Cursors[crSlidezy] := LoadCursor(HInstance, 'SLIDEZY');
208AtStart := True;
209end;
210
211procedure TViewForm.FormShow(Sender: TObject);
212var
213LayFile: File of TLayout;
214ini: TIniFile;
215i, c: Integer;
216s: string;
217
218begin
219if FileExists(LayoutFName) then
220begin
221try
222AssignFile(LayFile, LayoutFName);
223try
224Reset(LayFile);
225Read(LayFile, Layout);
226finally
227CloseFile(LayFile);
228end;
229with Layout do
230begin
231if IsMaximize then
232WindowState := wsMaximized
233else
234begin
235WindowState := wsNormal;
236Left := MainLeft;
237Top := MainTop;
238Width := MainWidth;
239Height := MainHeight;
240end;
241GraphFName := CurrentGraphFName;
242DataPath := CurrentDataPath;
243ImagePath := CurrentImagePath;
244// FunctionsForm
245FunctionsForm.Left := FuncLeft;
246FunctionsForm.Top := FuncTop;
247FunctionsForm.Width := FuncWidth;
248FunctionsForm.Height := FuncHeight;
249// GridOptionsForm
250if GridsVisible then
251GridOptionsForm.Show;
252GridOptionsForm.Left := GridsLeft;
253GridOptionsForm.Top := GridsTop;
254// GridColorsForm
255GridColorsForm.Left := GridColorsLeft;
256GridColorsForm.Top := GridColorsTop;
257// PlotColorsForm
258PlotColorsForm.Left := PlotColorsLeft;
259PlotColorsForm.Top := PlotColorsTop;
260// EvaluateForm
261if EvaluateVisible then
262EvaluateForm.Show;
263EvaluateForm.Left := EvaluateLeft;
264EvaluateForm.Top := EvaluateTop;
265// CoordsForm
266if CoordVisible then
267CoordsForm.Show;
268CoordsForm.Left := CoordLeft;
269CoordsForm.Top := CoordTop;
270// DerivativesForm
271DerivativesForm.Left := DerivLeft;
272DerivativesForm.Top := DerivTop;
273// AddPlotColorsForm
274AddPlotColorsForm.Left := AddColorsLeft;
275AddPlotColorsForm.Top := AddColorsTop;
276end;
277FunctionsForm.EditMinX.SetFocus;
278except
279MessageDlg('File Error! An Error has occurred when attempting to read' +
280#13#10'"' + LayoutFName + '".' +
281#13#10'The default layout will be used.', mtError, [mbOK], 0);
282DefaultLayout;
283end;
284end
285else
286DefaultLayout;
287
288ShowCameraLocation;
289// focallength: right mouse drag up/down
290ShowFocalLength;
291(* displace origin: x axis: ctrl/left mouse drag left/right
292y axis: alt/left mouse drag up/down
293z axis: ctrl/left mouse drag up/down *)
294ShowDisplacement;
295(* move light: x axis: ctrl right mouse drag left/right
296y axis: alt right mouse drag up/down
297z axis: ctrl right mouse drag up/down *)
298ShowLightLocation;
299
300FunctionsForm.ReadAndShowInitialData;
301Caption := GraphFName;
302Altered := False;
303CreateHeightFields(FunctionsForm.CheckListBox.Count);
304
305ini := TIniFile.Create(RecentFName);
306with ini do
307try
308c := ReadInteger(Name, 'RecentCount', 0);
309for i := 0 to c - 1 do
310begin
311Recent1.Add(TMenuItem.Create(Self));
312Recent1.Items[i].Caption := ReadString(Name, IntToStr(i), '');
313Recent1.Items[i].OnClick := RecentFilesClick;
314end;
315finally
316Free;
317end;
318end;
319
320procedure TViewForm.FormActivate(Sender: TObject);
321begin
322if AtStart then
323begin
324PlotFunctions;
325if GridColorsForm.Visible then
326GridColorsForm.ShowGridColorData;
327if PlotColorsForm.Visible then
328PlotColorsForm.ShowPlotColorData;
329AtStart := False;
330end;
331end;
332
333procedure TViewForm.FormClose(Sender: TObject; var Action: TCloseAction);
334var
335ini: TIniFile;
336i: Integer;
337begin
338ini := TIniFile.Create(RecentFName);
339try
340ini.WriteInteger(Name, 'RecentCount', Recent1.Count);
341for i := 0 to Recent1.Count - 1 do
342ini.WriteString(Name, IntToStr(i), Recent1.Items[i].Caption);
343finally
344ini.Free;
345end;
346end;
347
348procedure TViewForm.FormDestroy(Sender: TObject);
349begin
350while Fields.Count > 0 do
351TGLHeightField(Fields.Children[0]).Free;
352ClearAddedField;
353ClearAddedLines;
354end;
355
356procedure TViewForm.FormCloseQuery(Sender: TObject; var CanClose: Boolean);
357var
358f: File of TLayout;
359
360begin
361with Layout do
362begin
363IsMaximize := (Width >= Screen.Width) and (Height >= Screen.Height);
364MainLeft := Left;
365MainTop := Top;
366MainWidth := Width;
367MainHeight := Height;
368if GraphFName = '' then
369GraphFName := NewFName;
370CurrentGraphFName := GraphFName;
371CurrentDataPath := DataPath;
372CurrentImagePath := ImagePath;
373
374// FunctionsForm
375FuncLeft := FunctionsForm.Left;
376FuncTop := FunctionsForm.Top;
377FuncWidth := FunctionsForm.Width;
378FuncHeight := FunctionsForm.Height;
379
380// GridOptionsForm
381GridsVisible := GridOptionsForm.Visible;
382GridsLeft := GridOptionsForm.Left;
383GridsTop := GridOptionsForm.Top;
384
385// GridColorsForm
386GridColorsLeft := GridColorsForm.Left;
387GridColorsTop := GridColorsForm.Top;
388
389// PlotColorsForm
390PlotColorsLeft := PlotColorsForm.Left;
391PlotColorsTop := PlotColorsForm.Top;
392
393// EvaluateForm
394EvaluateVisible := EvaluateForm.Visible;
395EvaluateLeft := EvaluateForm.Left;
396EvaluateTop := EvaluateForm.Top;
397
398// CoordsForm
399CoordVisible := CoordsForm.Visible;
400CoordLeft := CoordsForm.Left;
401CoordTop := CoordsForm.Top;
402
403// DerivativesForm
404DerivLeft := DerivativesForm.Left;
405DerivTop := DerivativesForm.Top;
406if DerivativesForm.Visible then
407DerivativesForm.Close;
408
409// AddPlotColorsForm
410AddColorsLeft := AddPlotColorsForm.Left;
411AddColorsTop := AddPlotColorsForm.Top;
412if AddPlotColorsForm.Visible then
413AddPlotColorsForm.Close;
414end;
415
416try
417AssignFile(f, LayoutFName);
418try
419Rewrite(f);
420write(f, Layout);
421finally
422CloseFile(f);
423end;
424except
425MessageDlg('File Error! An Error has occurred' +
426#13#10'when attempting to write to "' + LayoutFName + '".', mtError,
427[mbOK], 0);
428end;
429
430if Altered or GridColorsAltered or DerivativeAltered then
431begin
432case MessageDlg('The current graph''s data has been altered.' +
433#13#10'Do you wish to save the alterations ?', mtConfirmation,
434[mbYes, mbNo, mbCancel], 0) of
435mrYes:
436FunctionsForm.SaveClick(Sender);
437mrCancel:
438begin
439CanClose := False;
440Exit;
441end;
442end;
443end;
444end;
445
446procedure TViewForm.FormKeyDown(Sender: TObject; var Key: Word;
447Shift: TShiftState);
448var
449d: Integer;
450begin
451d := 0;
452case Key of
453VK_ADD:
454d := -1; // zoom in
455VK_SUBTRACT:
456d := 1; // zoom out
457end;
458if Key in [VK_ADD, VK_SUBTRACT] then
459begin
460Screen.Cursor := crZoom;
461GLSViewer.SetFocus;
462// each step adjusts target distance by 2.5% another method to zoom in or out
463Camera.AdjustDistanceToTarget(Power(1.025, d));
464ShowCameraLocation;
465end
466else
467case Key of
468VK_HOME, VK_NUMPAD7, 72:
469DefaultView; // 'H'/'h' key
470(* -> = 39
471<- = 37
472^ = 38
473| = 40
474-> and ^ = 33
475<- and | = 35 *)
476end;
477Key := 0;
478end;
479
480procedure TViewForm.FormKeyUp(Sender: TObject; var Key: Word;
481Shift: TShiftState);
482begin
483Screen.Cursor := crDefault;
484end;
485
486procedure TViewForm.FormMouseWheel(Sender: TObject; Shift: TShiftState;
487WheelDelta: Integer; MousePos: TPoint; var Handled: Boolean);
488begin
489if (MousePoint.X >= GLSViewer.Left) and
490(MousePoint.X <= GLSViewer.Left + GLSViewer.Width) and
491(MousePoint.Y >= GLSViewer.Top) and
492(MousePoint.Y <= GLSViewer.Top + GLSViewer.Height) then
493begin
494(*
495a wheel step = WheelDelta/300; each step adjusts target distance by 2.5%
496another method to zoom in or out
497*)
498GLSViewer.SetFocus;
499Camera.AdjustDistanceToTarget(Power(1.025, WheelDelta / 300));
500ShowCameraLocation;
501end;
502end;
503
504procedure TViewForm.GLSViewerMouseDown(Sender: TObject; Button: TMouseButton;
505Shift: TShiftState; X, Y: Integer);
506begin
507MousePoint.X := X;
508MousePoint.Y := Y;
509if ssShift in Shift then // Shift key down
510begin
511if ssLeft in Shift then
512Screen.Cursor := crZoom;
513end
514else if ssCtrl in Shift then // Ctrl key down
515begin
516if ssLeft in Shift then
517Screen.Cursor := crSlidexz
518else if ssRight in Shift then
519Screen.Cursor := crLightxz;
520end
521else if ssAlt in Shift then // Alt key down
522begin
523if ssLeft in Shift then
524Screen.Cursor := crSlidezy
525else if ssRight in Shift then
526Screen.Cursor := crLightxy;
527end
528else // no shift, ctrl or alt key
529begin
530if Shift = [ssLeft] then
531Screen.Cursor := crRotate
532else if Shift = [ssRight] then
533Screen.Cursor := crZoom;
534end;
535end;
536
537procedure TViewForm.GLSViewerMouseMove(Sender: TObject; Shift: TShiftState;
538X, Y: Integer);
539var
540dx, dy: Integer;
541
542begin // refer GLScene\Demos\interface\camera\Camera.dpr
543if MousePoint.X = MaxInt then // FileOpenDialog is visible
544begin
545MousePoint.X := X;
546Exit;
547end;
548
549dx := MousePoint.X - X;
550dy := MousePoint.Y - Y;
551
552if ssShift in Shift then // shift key down
553begin
554if ssLeft in Shift then // shift - left mouse button
555begin
556(* dy = a step which adjusts target distance by 1.25%; zoom in or out *)
557Camera.AdjustDistanceToTarget(Power(1.0125, dy));
558ShowCameraLocation;
559end;
560end
561else if ssCtrl in Shift then // Ctrl key down
562begin
563if ssLeft in Shift then // Ctrl - left mouse button
564begin
565TargetCube.Position.X := TargetCube.Position.X - dx *
566GLxzGrid.XSamplingScale.Step / 10;
567TargetCube.Position.z := TargetCube.Position.z - dy *
568GLxzGrid.ZSamplingScale.Step * ViewData.xyGrid.zScale / 10;
569ShowDisplacement;
570end;
571if ssRight in Shift then // Ctrl - right mouse button
572begin
573GLLight.Position.z := GLLight.Position.z + dy / 10;
574GLLight.Position.X := GLLight.Position.X + dx / 10;
575ShowLightLocation;
576end;
577end
578else if ssAlt in Shift then // Alt key down
579begin
580if ssRight in Shift then // Alt - right mouse button
581begin
582GLLight.Position.X := GLLight.Position.X + dx / 10;
583GLLight.Position.Y := GLLight.Position.Y + dy / 10;
584ShowLightLocation;
585end
586else if ssLeft in Shift then // Alt - left mouse button
587begin
588TargetCube.Position.Y := TargetCube.Position.Y + dx *
589GLyzGrid.YSamplingScale.Step / 10;
590TargetCube.Position.z := TargetCube.Position.z - dy *
591GLyzGrid.ZSamplingScale.Step * ViewData.xyGrid.zScale / 10;
592ShowDisplacement;
593end;
594end
595else // no shift key
596begin
597if Shift = [ssLeft] then
598(* Left mouse button changes camera angle by moving around target *)
599begin
600Camera.MoveAroundTarget(dy, dx);
601ShowCameraLocation;
602end;
603if Shift = [ssRight] then
604begin
605(*
606Right mouse button alters the camera's focal length;
607zoom out or in by moving cursor up or down
608*)
609Camera.FocalLength := Camera.FocalLength - dy;
610if Camera.FocalLength > 3000 then
611Camera.FocalLength := 3000; // max focal length
612if Camera.FocalLength < 10 then
613Camera.FocalLength := 10; // min focal length
614
615ShowFocalLength; // display in statusbar palel
616end;
617end;
618MousePoint.X := X; // update mouse position
619MousePoint.Y := Y;
620end;
621
622procedure TViewForm.GLSViewerMouseUp(Sender: TObject; Button: TMouseButton;
623Shift: TShiftState; X, Y: Integer);
624begin
625Screen.Cursor := crDefault;
626end;
627
628procedure TViewForm.New1Click(Sender: TObject);
629begin
630FunctionsForm.New1Click(Sender);
631end;
632
633procedure TViewForm.OpenFileClick(Sender: TObject);
634begin
635FunctionsForm.OpenFileClick(Sender);
636end;
637
638procedure TViewForm.Save1Click(Sender: TObject);
639begin
640FunctionsForm.SaveClick(Sender);
641end;
642
643procedure TViewForm.Saveas1Click(Sender: TObject);
644begin
645FunctionsForm.SaveAsClick(Sender);
646end;
647
648procedure TViewForm.ShowCameraLocation;
649begin
650StatusBar.Panels[0].Text := 'Camera: ' +
651FloatToStrF(Camera.Position.X, ffNumber, 5, 2) + ', ' +
652FloatToStrF(Camera.Position.Y, ffNumber, 5, 2) + ', ' +
653FloatToStrF(Camera.Position.Z, ffNumber, 5, 2);
654end;
655
656procedure TViewForm.GridColours1Click(Sender: TObject);
657begin
658GridColorsForm.Show;
659end;
660
661procedure TViewForm.CoordText1Click(Sender: TObject);
662begin
663CoordsForm.Show;
664end;
665
666procedure TViewForm.ShowFocalLength;
667begin
668StatusBar.Panels[1].Text := 'f = ' + FloatToStrF(Camera.FocalLength,
669ffNumber, 5, 2);
670end;
671
672procedure TViewForm.ShowDisplacement;
673begin
674StatusBar.Panels[2].Text := 'Displaced: ' +
675FloatToStrF(-TargetCube.Position.X, ffNumber, 5, 2) + ', ' +
676FloatToStrF(-TargetCube.Position.Y, ffNumber, 5, 2) + ', ' +
677FloatToStrF(-TargetCube.Position.Z, ffNumber, 5, 2);
678end;
679
680procedure TViewForm.Evaluate1Click(Sender: TObject);
681begin
682EvaluateForm.Show;
683end;
684
685procedure TViewForm.ShowLightLocation;
686begin
687StatusBar.Panels[3].Text := 'Light: ' +
688FloatToStrF(GLLight.Position.X, ffNumber, 5, 2) + ', ' +
689FloatToStrF(GLLight.Position.Y, ffNumber, 5, 2) + ', ' +
690FloatToStrF(GLLight.Position.Z, ffNumber, 5, 2);
691end;
692
693procedure TViewForm.Grid1Click(Sender: TObject);
694begin
695GridOptionsForm.Show;
696end;
697
698procedure TViewForm.DefaultLayout1Click(Sender: TObject);
699begin
700DefaultLayout;
701end;
702
703procedure TViewForm.DefaultView;
704begin
705CameraCube.Position.SetPoint(0, 0, 0);
706ShowDisplacement;
707Camera.FocalLength := 200;
708ShowFocalLength;
709Camera.Position.SetPoint(50, 50, 30);
710Camera.DepthOfView := 1000;
711ShowCameraLocation;
712GLLight.Position.SetPoint(50, 50, 50);
713ShowLightLocation;
714TargetCube.Position.SetPoint(0, 0, 0);
715end;
716
717procedure TViewForm.RecentFilesClick(Sender: TObject);
718begin
719FunctionsForm.OpenRecentFile(TMenuItem(Sender).Caption);
720end;
721
722procedure TViewForm.Exit1Click(Sender: TObject);
723begin
724Close;
725end;
726
727procedure TViewForm.DefaultLayout;
728begin
729WindowState := wsNormal;
730ViewForm.Left := 0;
731ViewForm.Top := 0;
732FunctionsForm.Width := 335;
733FunctionsForm.Height := 387;
734ViewForm.Width := Screen.Width - FunctionsForm.Width + 18;
735ViewForm.Height := Screen.Height - 40;
736FunctionsForm.Left := ViewForm.Left + ViewForm.Width - 14;
737FunctionsForm.Top := ViewForm.Top;
738GridOptionsForm.Left := FunctionsForm.Left + 5;
739GridOptionsForm.Top := FunctionsForm.Top + FunctionsForm.Height - 6;
740EvaluateForm.Left := GridOptionsForm.Left;
741EvaluateForm.Top := GridOptionsForm.Top + GridOptionsForm.Height - 3;
742EvaluateForm.Show;
743GridOptionsForm.Show;
744GridColorsForm.Left := 20;
745GridColorsForm.Top := 80;
746PlotColorsForm.Left := 30;
747PlotColorsForm.Top := 100;
748AddPlotColorsForm.Left := 40;
749AddPlotColorsForm.Top := 120;
750FunctionsForm.EditMinX.SetFocus;
751end;
752
753procedure TViewForm.DerivativeOpsClick(Sender: TObject);
754begin
755if PlotColorsForm.Visible then
756PlotColorsForm.Close;
757PlotColours1.Enabled := False;
758DerivativePlotColours1.Enabled := True;
759DerivativesForm.Show;
760end;
761
762procedure TViewForm.DerivativePlotColours1Click(Sender: TObject);
763begin
764if PlotColorsForm.Visible then
765PlotColorsForm.Close;
766PlotColours1.Enabled := False;
767AddPlotColorsForm.Show;
768end;
769
770procedure TViewForm.PlotFunctions;
771
772procedure PlotFunction(i: Integer);
773begin
774with PlotData do
775begin
776with TGLHeightField(Fields.Children[i]) do
777begin
778XSamplingScale.Step := xInc;
779XSamplingScale.Min := xMin;
780XSamplingScale.Max := xMax;
781
782YSamplingScale.Step := yInc;
783YSamplingScale.Min := yMin;
784YSamplingScale.Max := yMax;
785
786case ViewMode of
787vmAmbient:
788ColorMode := hfcmAmbient;
789vmAmbientandDiffuse:
790ColorMode := hfcmAmbientAndDiffuse;
791vmDiffuse:
792ColorMode := hfcmDiffuse;
793vmEmmision:
794ColorMode := hfcmEmission;
795vmNone:
796ColorMode := hfcmNone;
797end;
798
799case fxyMode of
800fxyFill:
801Material.PolygonMode := pmFill;
802fxyLines:
803Material.PolygonMode := pmLines;
804fxyPoints:
805Material.PolygonMode := pmPoints;
806end;
807OnGetHeight := Formulate;
808end;
809GLSViewer.Refresh; // needed to display each zField data in list
810end;
811end;
812
813var
814i: Integer;
815fxyParser: TfxyParser;
816PD: TPlotData; // save the current PlotData of selected function
817
818begin // PlotFunctions
819Screen.Cursor := crHourGlass;
820PD := PlotData;
821fxyParser := TfxyParser.Create(0, 0);
822try
823with FunctionsForm.CheckListBox do
824for i := 0 to Items.Count - 1 do
825if Checked[i] then
826begin
827// an item is checked; get the plot data
828PlotData := TPlotDataObject(Items.Objects[i]).Data;
829PlotFunction(i);
830end;
831finally
832Screen.Cursor := crDefault;
833fxyParser.Destroy;
834PlotData := PD; // restor the current PlotData
835end;
836end;
837
838procedure TViewForm.Formulate(const X, Y: Single; var z: Single;
839var Color: TGLColorVector; var texPoint: TTexPoint);
840var
841e: byte;
842MaxZ, MinZ: TGLFloat;
843x1, x2, y1, y2, z1, z2: extended;
844
845begin
846case AddedData.AddedAs of
847AddNone: // no AddedData to plot; just plot the PlotData
848begin
849z := ParseEvaluateFxy(X, Y, PlotData.fxyStr, e);
850z := z * ViewData.xyGrid.zScale;
851with PlotData do
852begin
853MaxZ := zMax * ViewData.xyGrid.zScale;
854MinZ := zMin * ViewData.xyGrid.zScale;
855if zCap then
856begin
857if zLim and (z > MaxZ) then
858z := MaxZ;
859if zLim and (z < MinZ) then
860z := MinZ;
861end
862else if zLim and ((z < MinZ) or (z > MaxZ)) then
863z := NaN;
864VectorLerp(LowerColor, UpperColor, z * ColorBlend - ColorMove, Color);
865end;
866end;
867
868AddDerivX: // this is for partial derivative wrt x
869begin
870x1 := X - AddedData.xInc;
871x2 := X + AddedData.xInc;
872z1 := ParseEvaluateFxy(x1, Y, SelectedData.fxyStr, e);
873// evaluate z1,x1,y
874z2 := ParseEvaluateFxy(x2, Y, SelectedData.fxyStr, e);
875// evaluate z2,x2,y
876z := (z2 - z1) / (x2 - x1); // z = slope wrt x axis
877z := z * ViewData.xyGrid.zScale;
878with AddedData do
879begin
880MaxZ := zMax * ViewData.xyGrid.zScale;
881MinZ := zMin * ViewData.xyGrid.zScale;
882if zCap then
883begin
884if zLim and (z > MaxZ) then
885z := MaxZ;
886if zLim and (z < MinZ) then
887z := MinZ;
888end
889else if zLim and ((z < MinZ) or (z > MaxZ)) then
890z := NaN;
891VectorLerp(LowerColor, UpperColor, z * ColorBlend - ColorMove, Color);
892end;
893end;
894
895AddDerivY: // this is for partial derivative wrt y
896begin
897y1 := Y - AddedData.yInc;
898y2 := Y + AddedData.yInc;
899z1 := ParseEvaluateFxy(X, y1, SelectedData.fxyStr, e);
900// evaluate z1,x,y1
901z2 := ParseEvaluateFxy(X, y2, SelectedData.fxyStr, e);
902// evaluate z2,x,y2
903z := (z2 - z1) / (y2 - y1); // z = slope wrt y axis
904z := z * ViewData.xyGrid.zScale;
905with AddedData do
906begin
907MaxZ := zMax * ViewData.xyGrid.zScale;
908MinZ := zMin * ViewData.xyGrid.zScale;
909if zCap then
910begin
911if zLim and (z > MaxZ) then
912z := MaxZ;
913if zLim and (z < MinZ) then
914z := MinZ;
915end
916else if zLim and ((z < MinZ) or (z > MaxZ)) then
917z := NaN;
918VectorLerp(LowerColor, UpperColor, z * ColorBlend - ColorMove, Color);
919end;
920end;
921
922AddVolume: // this is for double integral
923begin
924z := ParseEvaluateFxy(X, Y, PlotData.fxyStr, e);
925with AddedData do
926begin
927z := z * ViewData.xyGrid.zScale;
928MaxZ := zMax * ViewData.xyGrid.zScale;
929MinZ := zMin * ViewData.xyGrid.zScale;
930if zCap then
931begin
932if zLim and (z > MaxZ) then
933z := MaxZ;
934if zLim and (z < MinZ) then
935z := MinZ;
936end
937else if zLim and ((z < MinZ) or (z > MaxZ)) then
938z := NaN;
939VectorLerp(LowerColor, UpperColor, z * ColorBlend - ColorMove, Color);
940
941TGLLines.CreateAsChild(VolumeLines);
942with VolumeLines do
943begin
944with TGLLines(Children[Count - 1]) do
945begin
946LineColor.AsWinColor := AddLineColor;
947LineWidth := AddLineWidth;
948NodesAspect := LnaInvisible;
949
950Nodes.Add;
951Nodes[0].X := X; // start point
952Nodes[0].Y := Y;
953if zLim then
954Nodes[0].z := MinZ
955else
956Nodes[0].z := 0;
957
958Nodes.Add;
959Nodes[1].X := X; // end point
960Nodes[1].Y := Y;
961Nodes[1].z := z;
962end;
963end;
964end;
965end;
966end; // case AddedData.AddedAs of...
967end;
968
969procedure TViewForm.PlotDerivativeField;
970var
971i: Integer;
972FoundSelected: Boolean;
973
974begin
975Screen.Cursor := crHourGlass;
976try
977i := 0;
978if FunctionsForm.CheckListBox.Count > 1 then // find Selected item
979begin
980FoundSelected := False;
981while not FoundSelected and (i < FunctionsForm.CheckListBox.Count) do
982begin
983FoundSelected := FunctionsForm.CheckListBox.Selected[i];
984if not FoundSelected then
985Inc(i);
986end;
987end;
988
989with FunctionsForm.CheckListBox do
990SelectedData := TPlotDataObject(Items.Objects[i]).Data;
991
992with AddedData do
993begin
994with TGLHeightField(AddedField.Children[0]) do
995begin
996with XSamplingScale do
997begin
998Step := xInc;
999Min := xMin;
1000Max := xMax;
1001end;
1002
1003with YSamplingScale do
1004begin
1005Step := yInc;
1006Min := yMin;
1007Max := yMax;
1008end;
1009
1010case ViewMode of
1011vmAmbient:
1012ColorMode := hfcmAmbient;
1013vmAmbientandDiffuse:
1014ColorMode := hfcmAmbientAndDiffuse;
1015vmDiffuse:
1016ColorMode := hfcmDiffuse;
1017vmEmmision:
1018ColorMode := hfcmEmission;
1019vmNone:
1020ColorMode := hfcmNone;
1021end;
1022
1023case fxyMode of
1024fxyFill:
1025Material.PolygonMode := pmFill;
1026fxyLines:
1027Material.PolygonMode := pmLines;
1028fxyPoints:
1029Material.PolygonMode := pmPoints;
1030end;
1031OnGetHeight := Formulate;
1032end;
1033GLSViewer.Refresh; // needed to display each zField data in list
1034end;
1035finally
1036Screen.Cursor := crDefault;
1037end;
1038end;
1039
1040procedure TViewForm.PlotIntegralField;
1041procedure PlotVolume;
1042begin // PlotVolume
1043with AddedData do
1044begin
1045with TGLHeightField(AddedField.Children[0]) do
1046begin
1047with XSamplingScale do
1048begin
1049Step := xInc;
1050Min := xMin;
1051Max := xMax;
1052end;
1053
1054with YSamplingScale do
1055begin
1056Step := yInc;
1057Min := yMin;
1058Max := yMax;
1059end;
1060
1061case ViewMode of
1062vmAmbient:
1063ColorMode := hfcmAmbient;
1064vmAmbientandDiffuse:
1065ColorMode := hfcmAmbientAndDiffuse;
1066vmDiffuse:
1067ColorMode := hfcmDiffuse;
1068vmEmmision:
1069ColorMode := hfcmEmission;
1070vmNone:
1071ColorMode := hfcmNone;
1072end;
1073
1074case fxyMode of
1075fxyFill:
1076Material.PolygonMode := pmFill;
1077fxyLines:
1078Material.PolygonMode := pmLines;
1079fxyPoints:
1080Material.PolygonMode := pmPoints;
1081end;
1082OnGetHeight := Formulate;
1083end;
1084GLSViewer.Refresh; // needed to display each zField data in list
1085end;
1086end; // PlotVolume
1087
1088procedure CalculateVolume;
1089var
1090e: byte;
1091i, j, iCount, jCount: Integer;
1092X, Y, z, x0, y0, a, VolPos, VolNeg: TGLFloat;
1093
1094begin // CalculateVolume
1095with AddedData do
1096begin
1097a := xInc * yInc; // base area
1098iCount := round((xMax - xMin) / xInc) - 1; // number of x points
1099jCount := round((yMax - yMin) / yInc) - 1; // number of y points
1100VolPos := 0;
1101VolNeg := 0;
1102x0 := xMin + xInc / 2; // base centre x0
1103y0 := yMin + yInc / 2; // base centre y0
1104for j := 0 to jCount do
1105begin
1106Y := y0 + j * yInc; // next column wrt y
1107for i := 0 to iCount do
1108begin
1109X := x0 + i * xInc; // next column wrt x
1110z := ParseEvaluateFxy(X, Y, PlotData.fxyStr, e);
1111
1112if zLim then // zLimit applied
1113begin
1114if (zMax >= 0) and (zMin <= 0) then // above and below zero
1115begin
1116if z > 0 then
1117begin
1118if z > zMax then
1119VolPos := VolPos + a * zMax
1120else
1121VolPos := VolPos + a * z;
1122end
1123else
1124begin
1125if z < zMin then
1126VolNeg := VolNeg + a * zMin
1127else
1128VolNeg := VolNeg + a * z;
1129end;
1130end
1131else if zMin > 0 then // both above zero
1132begin
1133if z >= zMin then
1134begin
1135if z > zMax then
1136VolPos := VolPos + a * (zMax - zMin)
1137else
1138VolPos := VolPos + a * (z - zMin);
1139end;
1140end
1141else if zMax < 0 then // both below zero
1142begin
1143if z <= zMax then
1144begin
1145if z < zMin then
1146VolNeg := VolNeg + a * (zMax - zMin)
1147else
1148VolNeg := VolNeg + a * (z - zMax);
1149end;
1150end;
1151end
1152else // no zLimit applied
1153begin
1154if z > 0 then
1155VolPos := VolPos + a * z
1156else
1157VolNeg := VolNeg + a * z;
1158end;
1159end;
1160end;
1161end;
1162
1163with DerivativesForm do
1164begin
1165PosVolLabel.Caption := 'Positive Volume: ' + FloatToStr(VolPos);
1166NegVolLabel.Caption := 'Negative Volume: ' + FloatToStr(VolNeg);
1167TotalLabel.Caption := 'Absolute Volume: ' + FloatToStr(VolPos - VolNeg);
1168VolumeLabel.Caption := 'Total Volume: ' + FloatToStr(VolPos + VolNeg);
1169end;
1170end; // CalculateVolume
1171
1172begin // TViewForm.PlotIntegralField
1173Screen.Cursor := crHourGlass;
1174with AddedData do
1175begin
1176PlotVolume;
1177CalculateVolume;
1178end;
1179DerivativesForm.VolumeRB.Checked := False; //
1180Screen.Cursor := crDefault;
1181end; // TViewForm.PlotIntegralField
1182
1183procedure TViewForm.PlotColours1Click(Sender: TObject);
1184begin
1185PlotColorsForm.Show;
1186end;
1187
1188procedure TViewForm.CreateHeightFields(const n: Integer);
1189var
1190i: Integer;
1191
1192begin
1193while Fields.Count > 0 do
1194TGLHeightField(Fields.Children[0]).Free;
1195for i := 0 to n - 1 do
1196begin
1197TGLHeightField.CreateAsChild(Fields);
1198TGLHeightField(Fields.Children[Fields.Count - 1]).Material.BlendingMode :=
1199bmTransparency;
1200end;
1201end;
1202
1203procedure TViewForm.CreateAddedField;
1204begin
1205ClearAddedField;
1206TGLHeightField.CreateAsChild(AddedField);
1207TGLHeightField(AddedField.Children[0]).Material.BlendingMode :=
1208bmTransparency;
1209end;
1210
1211procedure TViewForm.UpdatePlot;
1212begin
1213CreateHeightFields(FunctionsForm.CheckListBox.Count);
1214PlotFunctions;
1215end;
1216
1217procedure TViewForm.UpdateAdded;
1218begin
1219CreateAddedField;
1220AddXLine.LineColor.AsWinColor := AddedData.AddLineColor;
1221AddYLine.LineColor.AsWinColor := AddedData.AddLineColor;
1222AddZLine.LineColor.AsWinColor := AddedData.AddLineColor;
1223AddXLine.LineWidth := AddedData.AddLineWidth;
1224AddYLine.LineWidth := AddedData.AddLineWidth;
1225AddZLine.LineWidth := AddedData.AddLineWidth;
1226if AddedData.AddedAs = AddVolume then
1227PlotIntegralField
1228else
1229PlotDerivativeField;
1230end;
1231
1232procedure TViewForm.About1Click(Sender: TObject);
1233begin
1234FormAbout.Show;
1235end;
1236
1237procedure TViewForm.ClearAddedField;
1238begin
1239with TGLHeightField(AddedField) do
1240if Count > 0 then
1241Children[0].Free;
1242end;
1243
1244procedure TViewForm.ClearAddedLines;
1245begin
1246Screen.Cursor := crHourGlass;
1247with TGLLines(VolumeLines) do
1248while Count > 0 do
1249Children[Count - 1].Free;
1250Screen.Cursor := crDefault;
1251end;
1252
1253end.
1254