Prerequisites!
This article builds on my previous article "Visualizing mathematical functions by generating custom meshes using FireMonkey".
The wave function
The wave function we‘ll use in this article is:
f(x,y) = A*sin(1/L*r-v*t)
where:
- (x,y) = observation point
- A = amplitude
- L = wave length
- r = distance between wave center and observation point
- v = velocity of wave propagation
- t = time
In Delphi it simply becomes:
function
f(x,y : Double) : Double;begin
f := Amplitude*Sin(1/Length*Sqrt(Sqr(x-PosX)+Sqr(y-PosY))-Speed*t);end
;
Note: It should be noted that this function simply gives us the state of equilibrium. We‘re completely ignoring starting scenarios and the fact that waves die out over time and distance.
The screen shot below shows one wave:
Hide image
Generating the mesh
In order to generate the mesh, we borrow the code from my previous article, and modify it slightly to give it a time parameter:
procedure
TForm1.GenerateWave(t : Double);function
f(x,y : Double) : Double;var
i : Integer;begin
Result := 0;for
i:=0to
3do
with
Wave[i]do
if
Enabledthen
Result := Result+Amplitude*Sin(1/Length*Sqrt(Sqr(x-PosX)+Sqr(y-PosY))-Speed*t);end
;const
MaxX = 30; MaxZ = 30;var
u, v : Double; px, py, pz :array
[0..3]of
Double; d : Double; NP, NI : Integer; BMP : TBitmap; k : Integer;begin
d := 0.5; NP := 0; NI := 0; Mesh1.Data.VertexBuffer.Length := Round(2*MaxX*2*MaxZ/d/d)*4; Mesh1.Data.IndexBuffer.Length := Round(2*MaxX*2*MaxZ/d/d)*6; BMP := TBitmap.Create(1,360);for
k := 0to
359do
BMP.Pixels[0,k] := CorrectColor(HSLtoRGB(k/360,0.75,0.5)); u := -MaxX;while
u < MaxXdo
begin
v := -MaxZ;while
v < MaxZdo
begin
px[0] := u; pz[0] := v; py[0] := f(px[0],pz[0]); px[1] := u+d; pz[1] := v; py[1] := f(px[1],pz[1]); px[2] := u+d; pz[2] := v+d; py[2] := f(px[2],pz[2]); px[3] := u; pz[3] := v+d; py[3] := f(px[3],pz[3]);with
Mesh1.Datado
begin
// Set the points
with
VertexBufferdo
begin
Vertices[NP+0] := Point3D(px[0],py[0],pz[0]); Vertices[NP+1] := Point3D(px[1],py[1],pz[1]); Vertices[NP+2] := Point3D(px[2],py[2],pz[2]); Vertices[NP+3] := Point3D(px[3],py[3],pz[3]);end
;// Map the colors
with
VertexBufferdo
begin
TexCoord0[NP+0] := PointF(0,(py[0]+35)/45); TexCoord0[NP+1] := PointF(0,(py[1]+35)/45); TexCoord0[NP+2] := PointF(0,(py[2]+35)/45); TexCoord0[NP+3] := PointF(0,(py[3]+35)/45);end
;// Map the triangles
IndexBuffer[NI+0] := NP+1; IndexBuffer[NI+1] := NP+2; IndexBuffer[NI+2] := NP+3; IndexBuffer[NI+3] := NP+3; IndexBuffer[NI+4] := NP+0; IndexBuffer[NI+5] := NP+1;end
; NP := NP+4; NI := NI+6; v := v+d;end
; u := u+d;end
; Mesh1.Material.Texture := BMP;end
;
Animating the mesh
The above code generates a "snap shot" of the wave interaction between 4 waves at any time t.
Animating the wave is simply a matter of using a timer to increment time and re-generating the mesh over and over again:
procedure
TForm1.Timer1Timer(Sender: TObject);begin
GenerateWave(t); t := t+0.1;end
;
The waves are represented by this record:
type
TWave =record
Enabled : Boolean; Amplitude : Double; Length : Double; PosX : Double; PosY : Double; Speed : Double;end
;
In the demo project that accompanies this article, I have declared 4 starting waves like so:
var
Wave :array
[0..3]of
TWave = ((Enabled: False; Amplitude: 1; Length: 1; PosX: -20; PosY: -20; Speed: 1), (Enabled: False; Amplitude: 1; Length: 1; PosX: +20; PosY: -20; Speed: 1), (Enabled: False; Amplitude: 1; Length: 1; PosX: +20; PosY: +20; Speed: 1), (Enabled: False; Amplitude: 1; Length: 1; PosX: -20; PosY: +20; Speed: 1));
Note that all 4 waves have the same properties, except that their origins are spread across the coordinate system. Specifically they‘re located in (-20,-20), (+20,-20), (+20,+20) and (-20,+20).