The root of all your problems is that you are using a class that is a reference type. Instead, you need to make your vector a value type. This means use record .
In your code, even when you fix the problem identified by @NGLN, you still destroy all instances of your class by the time the WriteLn call starts.
If you do not understand this problem in the near future, I am afraid that you will have problems. Switching to using a value type will make your coding trivially simple compared to your current approach.
Here you can start:
type TVector3 = record public class operator Negative(const V: TVector3): TVector3; class operator Equal(const V1, V2: TVector3): Boolean; class operator NotEqual(const V1, V2: TVector3): Boolean; class operator Add(const V1, V2: TVector3): TVector3; class operator Subtract(const V1, V2: TVector3): TVector3; class operator Multiply(const V: TVector3; const D: Double): TVector3; class operator Multiply(const D: Double; const V: TVector3): TVector3; class operator Divide(const V: TVector3; const D: Double): TVector3; class function New(const X, Y, Z: Double): TVector3; static; function IsZero: Boolean; function IsNonZero: Boolean; function IsUnit: Boolean; function Mag: Double; function SqrMag: Double; function Normalised: TVector3; function ToString: string; public X, Y, Z: Double; end; const ZeroVector3: TVector3=(); class operator TVector3.Negative(const V: TVector3): TVector3; begin Result.X := -VX; Result.Y := -VY; Result.Z := -VZ; end; class operator TVector3.Equal(const V1, V2: TVector3): Boolean; begin Result := (V1.X=V2.X) and (V1.Y=V2.Y) and (V1.Z=V2.Z); end; class operator TVector3.NotEqual(const V1, V2: TVector3): Boolean; begin Result := not (V1=V2); end; class operator TVector3.Add(const V1, V2: TVector3): TVector3; begin Result.X := V1.X + V2.X; Result.Y := V1.Y + V2.Y; Result.Z := V1.Z + V2.Z; end; class operator TVector3.Subtract(const V1, V2: TVector3): TVector3; begin Result.X := V1.X - V2.X; Result.Y := V1.Y - V2.Y; Result.Z := V1.Z - V2.Z; end; class operator TVector3.Multiply(const V: TVector3; const D: Double): TVector3; begin Result.X := D*VX; Result.Y := D*VY; Result.Z := D*VZ; end; class operator TVector3.Multiply(const D: Double; const V: TVector3): TVector3; begin Result.X := D*VX; Result.Y := D*VY; Result.Z := D*VZ; end; class operator TVector3.Divide(const V: TVector3; const D: Double): TVector3; begin Result := (1.0/D)*V; end; class function TVector3.New(const X, Y, Z: Double): TVector3; begin Result.X := X; Result.Y := Y; Result.Z := Z; end; function TVector3.IsZero: Boolean; begin Result := Self=ZeroVector3; end; function TVector3.IsNonZero: Boolean; begin Result := Self<>ZeroVector3; end; function TVector3.IsUnit: Boolean; begin Result := abs(1.0-Mag)<1.0e-5; end; function TVector3.Mag: Double; begin Result := Sqrt(X*X + Y*Y + Z*Z); end; function TVector3.SqrMag: Double; begin Result := X*X + Y*Y + Z*Z; end; function TVector3.Normalised; begin Result := Self/Mag; end; function TVector3.ToString: string; begin Result := Format('(%g, %g, %g)', [X, Y, Z]); end;
This is extracted from my own code base. I use Double , but if you really prefer to use Single , you can easily change it.
Using operator overloading makes the code you write much more readable. Now you can write V3 := V1 + V2 , etc.
Here is what your test code looks like with this entry:
var nonUnitVector: TVector3; unitVector: TVector3; nUVNormed: TVector3; uVNormed: TVector3; begin //Setup Vectors for Test nonUnitVector := TVector3.New(1, 1, 1); unitVector := TVector3.New(1, 0, 0); //Normalise Vectors nUVNormed := nonUnitVector.Normalised; uVNormed := unitVector.Normalised; //Print Output WriteLn('nUVNormed = ' + nUVNormed.ToString); WriteLn('uVNormed = ' + uVNormed.ToString); Readln; end.
Or if you want to compress it a bit:
WriteLn('nUVNormed = ' + TVector3.New(1, 1, 1).Normalised.ToString); WriteLn('uVNormed = ' + TVector3.New(1, 0, 0).Normalised.ToString);