MathgeomGLS
399 строк · 10.3 Кб
1unit FMain;
2
3interface
4
5uses
6Winapi.Windows,
7Winapi.Messages,
8System.UITypes,
9System.Math,
10System.SysUtils,
11System.Variants,
12System.Classes,
13Vcl.Graphics,
14Vcl.Controls,
15Vcl.Forms,
16Vcl.Dialogs,
17Vcl.StdCtrls,
18Vcl.ExtCtrls,
19Vcl.Menus,
20Vcl.ComCtrls,
21
22GLS.VectorTypes,
23GLS.VectorTypesExt,
24GLS.PersistentClasses,
25GLS.Scene,
26GLS.SceneViewer,
27GLS.Objects,
28GLS.VectorFileObjects,
29GLS.VectorGeometry,
30GLS.State,
31GLS.Mesh,
32GLS.Color,
33GLS.Coordinates,
34
35GLS.BaseClasses,
36GLS.Spline,
37GLS.Material,
38GLS.Isosurface;
39
40type
41TFrmMain = class(TForm)
42GLSceneViewer: TGLSceneViewer;
43Scene: TGLScene;
44Camera: TGLCamera;
45dcBox: TGLDummyCube;
46PUSerInterface: TPanel;
47Label1: TLabel;
48Label2: TLabel;
49lblVertices: TLabel;
50lblTriangles: TLabel;
51rbgAlgorithm: TRadioGroup;
52ffObject: TGLFreeForm;
53MatLib: TGLMaterialLibrary;
54Light: TGLLightSource;
55rbgWireFrameFill: TRadioGroup;
56tbSize: TTrackBar;
57tbIsoValue: TTrackBar;
58Label3: TLabel;
59Label4: TLabel;
60rbgShading: TRadioGroup;
61TrackBar1: TTrackBar;
62Label5: TLabel;
63rbgInterpolation: TRadioGroup;
64MainMenu: TMainMenu;
65File1: TMenuItem;
66New1: TMenuItem;
67Open1: TMenuItem;
68Save1: TMenuItem;
69SaveAs1: TMenuItem;
70Exit1: TMenuItem;
71N1: TMenuItem;
72N2: TMenuItem;
73OpenDialog: TOpenDialog;
74Help1: TMenuItem;
75SearchforHelpOn1: TMenuItem;
76About1: TMenuItem;
77N3: TMenuItem;
78procedure FormCreate(Sender: TObject);
79procedure FormMouseWheel(Sender: TObject; Shift: TShiftState;
80WheelDelta: Integer; MousePos: TPoint; var Handled: Boolean);
81procedure GLSceneViewerMouseDown(Sender: TObject; Button: TMouseButton;
82Shift: TShiftState; X, Y: Integer);
83procedure GLSceneViewerMouseMove(Sender: TObject; Shift: TShiftState;
84X, Y: Integer);
85procedure rbgAlgorithmClick(Sender: TObject);
86function MakeSphere(Rad: Integer; var ADataout: TArray3DExt;
87var Dims: array of word; CPt: array of Integer): Integer;
88procedure rbgInvertClick(Sender: TObject);
89procedure tbSizeChange(Sender: TObject);
90procedure rbgShadingClick(Sender: TObject);
91procedure TrackBar1Change(Sender: TObject);
92procedure FormDestroy(Sender: TObject);
93procedure rbgWireFrameFillClick(Sender: TObject);
94procedure Exit1Click(Sender: TObject);
95procedure Open1Click(Sender: TObject);
96private
97ExtractedVertices: TVertexArray; // array of TVertex
98ExtractedTriangles: TIntegerArray; // array of Integer
99Dimensions: array ['x' .. 'z'] of Word;
100CenterPt: array ['x' .. 'z'] of Integer;
101CenterPts: array of array ['x' .. 'z'] of Integer;
102
103SingleData: TArray3DExt; // array of array of array of Single
104mdx, mdy: Integer;
105procedure GeneratePositions;
106procedure FillBlock;
107// Load Data from file
108function LoadCharData(AFileName: String; out ADataout: TArray3DExt;
109var Dims: array of word): Integer;
110
111end;
112
113var
114FrmMain: TFrmMain;
115
116implementation
117
118{$R *.dfm}
119
120procedure TFrmMain.FormCreate(Sender: TObject);
121begin
122SingleData := nil;
123GeneratePositions;
124FillBlock;
125end;
126
127procedure TFrmMain.FormDestroy(Sender: TObject);
128begin
129SetLength(SingleData, 0, 0, 0);
130end;
131
132procedure TFrmMain.rbgInvertClick(Sender: TObject);
133begin
134FillBlock;
135end;
136
137procedure TFrmMain.GeneratePositions;
138var
139DataAmount: Cardinal;
140i: Integer;
141X, Y, z: Integer;
142begin
143// don't redraw when the trackbar is exited, already drawn when it was moved
144if TrackBar1.Position = Length(CenterPts) then
145Exit;
146
147Dimensions['x'] := tbSize.Position;
148Dimensions['y'] := tbSize.Position;
149Dimensions['z'] := tbSize.Position;
150
151SetLength(CenterPts, TrackBar1.Position);
152if TrackBar1.Position = 1 then
153begin
154CenterPts[0, 'x'] := 50;
155CenterPts[0, 'y'] := 50;
156CenterPts[0, 'z'] := 50;
157end
158else
159for i := 0 to TrackBar1.Position - 1 do
160begin
161CenterPts[i, 'x'] := Random(100);
162CenterPts[i, 'y'] := Random(100);
163CenterPts[i, 'z'] := Random(100);
164end;
165end;
166
167procedure TFrmMain.Exit1Click(Sender: TObject);
168begin
169Close;
170end;
171
172procedure TFrmMain.FillBlock;
173var
174DataAmount: cardinal;
175i: Integer;
176X, Y, Z: Integer;
177begin
178Dimensions['x'] := tbSize.Position;
179Dimensions['y'] := tbSize.Position;
180Dimensions['z'] := tbSize.Position;
181SetLength(SingleData, 0, 0, 0);
182SetLength(SingleData, tbSize.Position, tbSize.Position, tbSize.Position);
183for i := 0 to TrackBar1.Position - 1 do
184begin
185CenterPt['x'] := round(CenterPts[i, 'x'] / 100 * tbSize.Position);
186CenterPt['y'] := round(CenterPts[i, 'y'] / 100 * tbSize.Position);
187CenterPt['z'] := round(CenterPts[i, 'z'] / 100 * tbSize.Position);
188MakeSphere(round(tbSize.Position / 2.5), SingleData, Dimensions, CenterPt);
189end;
190rbgAlgorithmClick(Self);
191end;
192
193// MakeSphere --------------------------------------------------------
194function TFrmMain.MakeSphere(Rad: Integer; var ADataout: TArray3DExt;
195var Dims: array of word; CPt: array of Integer): Integer;
196var
197X, Y, Z: Integer;
198DataPoint: Byte;
199Counter: Integer;
200v: single;
201begin
202// SetLength(ADataout, Dims[0], Dims[1], Dims[2]);
203Counter := 0;
204
205for X := -Rad to Rad do
206for Y := -Rad to Rad do
207for Z := -Rad to Rad do
208begin
209v := Sin(DegToRad(((X + Rad) / (2 * Rad)) * 180)) *
210Sin(DegToRad(((Y + Rad) / (2 * Rad)) * 180)) *
211Sin(DegToRad(((Z + Rad) / (2 * Rad)) * 180));
212if (v > 0) and ((X + CPt[0]) >= 0) and ((X + CPt[0]) <= high(ADataout))
213and ((Y + CPt[1]) >= 0) and ((Y + CPt[1]) <= high(ADataout[0])) and
214((z + CPt[2]) >= 0) and ((z + CPt[2]) <= high(ADataout[0, 0])) and
215(ADataout[X + CPt[0], Y + CPt[1], z + CPt[2]] < v * 255) then
216ADataout[X + CPt[0], Y + CPt[1], z + CPt[2]] := v * 255;
217inc(Counter);
218end;
219
220Result := Counter;
221end;
222
223procedure TFrmMain.Open1Click(Sender: TObject);
224var
225DataAmount: Cardinal;
226
227begin
228Dimensions['x'] := 27; // only for Cube.vol sample
229Dimensions['y'] := 27;
230Dimensions['z'] := 27;
231
232OpenDialog.InitialDir := ExtractFilePath(ParamStr(0));
233OpenDialog.Filter := 'Volumes|*.vol';
234if OpenDialog.Execute() then
235begin
236DataAmount := LoadCharData(OpenDialog.FileName, SingleData, Dimensions);
237MessageDlg(format('%d read. %dx%dx%d', [DataAmount, Dimensions['x'],
238Dimensions['y'], Dimensions['z']]), mtInformation, [mbOK], -1);
239end;
240rbgAlgorithmClick(Self);
241end;
242
243procedure TFrmMain.rbgAlgorithmClick(Sender: TObject);
244var
245IsoSurfaceEx: TGLIsoSurfaceExtractor;
246i: Integer;
247mo: TGLMeshObject;
248begin
249// Create IsoSurfaceExtractor
250IsoSurfaceEx := TGLIsoSurfaceExtractor.Create(Dimensions['x'], Dimensions['y'],
251Dimensions['z'], SingleData);
252// Launch Calculation
253case rbgAlgorithm.ItemIndex of
2540:
255IsoSurfaceEx.MarchingTetrahedra(tbIsoValue.Position, ExtractedVertices,
256ExtractedTriangles, rbgInterpolation.ItemIndex.ToBoolean);
2571:
258IsoSurfaceEx.MarchingCubes(tbIsoValue.Position, ExtractedVertices,
259ExtractedTriangles, rbgInterpolation.ItemIndex.ToBoolean);
260end;
261
262lblVertices.Caption := Format('%d', [length(ExtractedVertices)]);
263lblTriangles.Caption := Format('%d', [length(ExtractedTriangles) div 3]);
264IsoSurfaceEx.Free();
265
266ffObject.MaterialLibrary := MatLib;
267
268ffObject.MeshObjects.Clear();
269mo := TGLMeshObject.CreateOwned(ffObject.MeshObjects);
270for i := length(ExtractedTriangles) - 1 downto 0 do
271with ExtractedVertices[ExtractedTriangles[i]] do
272mo.Vertices.Add(AffineVectorMake(X - Dimensions['x'] / 2,
273Y - Dimensions['y'] / 2, z - Dimensions['z'] / 2));
274
275ffObject.StructureChanged;
276rbgWireFrameFillClick(nil);
277end;
278
279procedure TFrmMain.tbSizeChange(Sender: TObject);
280begin
281FillBlock;
282end;
283
284procedure TFrmMain.TrackBar1Change(Sender: TObject);
285begin
286GeneratePositions;
287FillBlock;
288end;
289
290
291procedure TFrmMain.rbgShadingClick(Sender: TObject);
292begin
293if rbgShading.ItemIndex = 0 then
294GLSceneViewer.Buffer.ShadeModel := smFlat
295else
296GLSceneViewer.Buffer.ShadeModel := smSmooth;
297end;
298
299procedure TFrmMain.rbgWireFrameFillClick(Sender: TObject);
300begin
301if rbgWireFrameFill.ItemIndex = 0 then
302ffObject.Material.PolygonMode := pmFill
303else
304ffObject.Material.PolygonMode := pmLines;
305GLSceneViewer.Invalidate();
306end;
307
308procedure TFrmMain.FormMouseWheel(Sender: TObject; Shift: TShiftState;
309WheelDelta: Integer; MousePos: TPoint; var Handled: Boolean);
310begin
311Camera.AdjustDistanceToTarget(Power(1.1, WheelDelta / 120));
312end;
313
314procedure TFrmMain.GLSceneViewerMouseDown(Sender: TObject; Button: TMouseButton;
315Shift: TShiftState; X, Y: Integer);
316begin
317mdx := X;
318mdy := Y;
319end;
320
321procedure TFrmMain.GLSceneViewerMouseMove(Sender: TObject; Shift: TShiftState;
322X, Y: Integer);
323var
324dx, dy: Integer;
325v: TGLVector;
326begin
327// calculate delta since last move or last mousedown
328dx := mdx - X;
329dy := mdy - Y;
330mdx := X;
331mdy := Y;
332if ssLeft in Shift then
333begin
334if ssShift in Shift then
335begin
336// right button with shift rotates the teapot
337// (rotation happens around camera's axis)
338Camera.RotateObject(dcBox, dy, dx);
339end
340else
341begin
342// right button without shift changes camera angle
343// (we're moving around the parent and target dummycube)
344Camera.MoveAroundTarget(dy, dx)
345end;
346end
347else if Shift = [ssRight] then
348begin
349// left button moves our target and parent dummycube
350v := Camera.ScreenDeltaToVectorXY(dx, -dy,
3510.12 * Camera.DistanceToTarget / Camera.FocalLength);
352dcBox.Position.Translate(v);
353// notify camera that its position/target has been changed
354Camera.TransformationChanged;
355end;
356end;
357
358// LoadCharData --------------------------------------------------------------
359function TFrmMain.LoadCharData(aFileName: String; out aDataout: TArray3DExt;
360var Dims: array of word): Integer;
361
362var
363DataFile: File of Byte;
364i, j, k: Integer;
365DataPoint: Byte;
366Counter: Integer;
367
368begin
369AssignFile(DataFile, aFileName);
370Reset(DataFile);
371SetLength(aDataout, Dims[0], Dims[1], Dims[2]);
372i := 0;
373j := 0;
374k := 0;
375Counter := 0;
376try
377repeat
378Read(DataFile, DataPoint);
379aDataout[i, j, k] := DataPoint;
380inc(i);
381if (i = Dims[0]) then
382begin
383i := 0;
384inc(j);
385end;
386if (j = Dims[1]) then
387begin
388j := 0;
389inc(k);
390end;
391inc(Counter);
392until Eof(DataFile);
393finally
394Closefile(DataFile);
395end;
396Result := Counter;
397end;
398
399end.
400