namespace OpenTK.Tests open Xunit open FsCheck open FsCheck.Xunit open System open OpenTK module Vector3 = [ |])>] module Constructors = // [] let ``Triple value constructor sets all components to the correct values`` (a, b, c) = let v = Vector3(a, b, c) Assert.Equal(a, v.X) Assert.Equal(b, v.Y) Assert.Equal(c, v.Z) [] let ``Single value constructor sets all components to the correct values`` (a : float32) = let v = Vector3(a) Assert.Equal(a, v.X) Assert.Equal(a, v.Y) Assert.Equal(a, v.Z) [] let ``Vector2 value constructor sets all components to the correct values`` (a, b) = let v1 = Vector2(a, b) let v2 = Vector3(v1) Assert.Equal(v1.X, v2.X) Assert.Equal(v1.Y, v2.Y) Assert.Equal(a, v2.X) Assert.Equal(b, v2.Y) Assert.Equal((float32)0, v2.Z) [] let ``Vector3 value constructor sets all components to the correct values`` (a, b, c) = let v1 = Vector3(a, b, c) let v2 = Vector3(v1) Assert.Equal(v1.X, v2.X) Assert.Equal(v1.Y, v2.Y) Assert.Equal(v1.Z, v2.Z) Assert.Equal(a, v2.X) Assert.Equal(b, v2.Y) Assert.Equal(c, v2.Z) [] let ``Vector4 value constructor sets all components to the correct values`` (a, b, c, d) = let v1 = Vector4(a, b, c, d) let v2 = Vector3(v1) Assert.Equal(v1.X, v2.X) Assert.Equal(v1.Y, v2.Y) Assert.Equal(v1.Z, v2.Z) Assert.Equal(a, v2.X) Assert.Equal(b, v2.Y) Assert.Equal(c, v2.Z) [ |])>] module Indexing = // [] let ``Index operator accesses the correct components`` (a, b, c) = let v = Vector3(a, b, c) Assert.Equal(a, v.[0]) Assert.Equal(b, v.[1]) Assert.Equal(c, v.[2]) [] let ``Index operator throws exception for negative indices`` (a, b, c) = let mutable v = Vector3(a, b, c) let invalidIndexingAccess = fun() -> v.[-1] |> ignore let invalidIndexingAssignment = fun() -> v.[-1] <- a Assert.Throws(invalidIndexingAccess) |> ignore Assert.Throws(invalidIndexingAssignment) |> ignore [] let ``Index operator throws exception for large indices`` (a, b, c) = let mutable v = Vector3(a, b, c) let invalidIndexingAccess = fun() -> v.[3] |> ignore let invalidIndexingAssignment = fun() -> v.[3] <- a Assert.Throws(invalidIndexingAccess) |> ignore Assert.Throws(invalidIndexingAssignment) |> ignore [ |])>] module Length = // [] let ``Length method works`` (a, b, c) = let v = Vector3(a, b, c) let l = System.Math.Sqrt((float)(a * a + b * b + c * c)) Assert.Equal((float32)l, v.Length) [] let ``Fast length method works`` (a, b, c) = let v = Vector3(a, b, c) let l = 1.0f / MathHelper.InverseSqrtFast(a * a + b * b + c * c) Assert.Equal(l, v.LengthFast) [] let ``Length squared method works`` (a, b, c) = let v = Vector3(a, b, c) let lsq = a * a + b * b + c * c Assert.Equal(lsq, v.LengthSquared) [ |])>] module Normalization = // [] let ``Normalization of instance, creating a new vector, works`` (a, b, c) = let v = Vector3(a, b, c) let l = v.Length // Dividing by zero is not supported if not (approxEq l 0.0f) then let norm = v.Normalized() Assert.ApproximatelyEqual(v.X / l, norm.X) Assert.ApproximatelyEqual(v.Y / l, norm.Y) Assert.ApproximatelyEqual(v.Z / l, norm.Z) [] let ``Normalization of instance works`` (a, b, c) = let v = Vector3(a, b, c) let l = v.Length if not (approxEq l 0.0f) then let norm = Vector3(a, b, c) norm.Normalize() Assert.ApproximatelyEqual(v.X / l, norm.X) Assert.ApproximatelyEqual(v.Y / l, norm.Y) Assert.ApproximatelyEqual(v.Z / l, norm.Z) [] let ``Fast approximate normalization of instance works`` (a, b, c) = let v = Vector3(a, b, c) let norm = Vector3(a, b, c) norm.NormalizeFast() let scale = MathHelper.InverseSqrtFast(a * a + b * b + c * c) Assert.ApproximatelyEqual(v.X * scale, norm.X) Assert.ApproximatelyEqual(v.Y * scale, norm.Y) Assert.ApproximatelyEqual(v.Z * scale, norm.Z) [] let ``Normalization by reference works`` (a : Vector3) = if not (approxEq a.Length 0.0f) then let scale = 1.0f / a.Length let norm = Vector3(a.X * scale, a.Y * scale, a.Z * scale) let vRes = Vector3.Normalize(ref a) Assert.ApproximatelyEqual(norm, vRes) [] let ``Normalization works`` (a : Vector3) = if not (approxEq a.Length 0.0f) then let scale = 1.0f / a.Length let norm = Vector3(a.X * scale, a.Y * scale, a.Z * scale) Assert.ApproximatelyEqual(norm, Vector3.Normalize(a)); [] let ``Fast approximate normalization by reference works`` (a : Vector3) = let scale = MathHelper.InverseSqrtFast(a.X * a.X + a.Y * a.Y) let norm = Vector3(a.X * scale, a.Y * scale, a.Z * scale) let vRes = Vector3.NormalizeFast(ref a) Assert.ApproximatelyEqual(norm, vRes) [] let ``Fast approximate normalization works`` (a : Vector3) = let scale = MathHelper.InverseSqrtFast(a.X * a.X + a.Y * a.Y) let norm = Vector3(a.X * scale, a.Y * scale, a.Z * scale) Assert.ApproximatelyEqual(norm, Vector3.NormalizeFast(a)); [ |])>] module Addition = // [] let ``Vector3 addition is the same as component addition`` (a : Vector3, b : Vector3) = let c = a + b Assert.ApproximatelyEqual(a.X + b.X,c.X) Assert.ApproximatelyEqual(a.Y + b.Y,c.Y) [] let ``Vector3 addition is commutative`` (a : Vector3, b : Vector3) = let c = a + b let c2 = b + a Assert.ApproximatelyEqual(c, c2) [] let ``Vector3 addition is associative`` (a : Vector3, b : Vector3, c : Vector3) = let r1 = (a + b) + c let r2 = a + (b + c) Assert.ApproximatelyEqual(r1, r2) [] let ``Static Vector3 addition method works`` (a : Vector3, b : Vector3) = let v1 = Vector3(a.X + b.X, a.Y + b.Y, a.Z + b.Z) let sum = Vector3.Add(a, b) Assert.ApproximatelyEqual(v1, sum) [] let ``Static Vector3 addition method works by reference`` (a : Vector3, b : Vector3) = let v1 = Vector3(a.X + b.X, a.Y + b.Y, a.Z + b.Z) let sum = Vector3.Add(ref a, ref b) Assert.ApproximatelyEqual(v1, sum) [ |])>] module Subtraction = // [] let ``Vector3 subtraction is the same as component subtraction`` (a : Vector3, b : Vector3) = let c = a - b Assert.Equal(a.X - b.X,c.X) Assert.Equal(a.Y - b.Y,c.Y) Assert.Equal(a.Z - b.Z,c.Z) [] let ``Static Vector3 subtraction method works`` (a : Vector3, b : Vector3) = let v1 = Vector3(a.X - b.X, a.Y - b.Y, a.Z - b.Z) let sum = Vector3.Subtract(a, b) Assert.ApproximatelyEqual(v1, sum) [] let ``Static Vector3 subtraction method works by reference`` (a : Vector3, b : Vector3) = let v1 = Vector3(a.X - b.X, a.Y - b.Y, a.Z - b.Z) let sum = Vector3.Subtract(ref a, ref b) Assert.ApproximatelyEqual(v1, sum) [ |])>] module Multiplication = // [] let ``Vector3 multiplication is the same as component multiplication`` (a : Vector3, b : Vector3) = let c = a * b Assert.Equal(a.X * b.X,c.X) Assert.Equal(a.Y * b.Y,c.Y) Assert.Equal(a.Z * b.Z,c.Z) [] let ``Vector3 multiplication is commutative`` (a : Vector3, b : Vector3) = let r1 = a * b let r2 = b * a Assert.Equal(r1, r2) [] let ``Vector3-float multiplication is the same as component-float multiplication`` (a : Vector3, f : float32) = let r = a * f Assert.Equal(a.X * f,r.X) Assert.Equal(a.Y * f,r.Y) Assert.Equal(a.Z * f,r.Z) // Inverse direction let r = f * a Assert.Equal(a.X * f,r.X) Assert.Equal(a.Y * f,r.Y) Assert.Equal(a.Z * f,r.Z) [] let ``Vector3-Matrix3 multiplication works for right-handed notation`` (a : Matrix3, b : Vector3) = let res = a*b let c1 = b.X * a.M11 + b.Y * a.M12 + b.Z * a.M13 let c2 = b.X * a.M21 + b.Y * a.M22 + b.Z * a.M23 let c3 = b.X * a.M31 + b.Y * a.M32 + b.Z * a.M33 let exp = Vector3(c1, c2, c3) Assert.Equal(exp, res) [] let ``Vector3-Matrix3 multiplication works for left-handed notation`` (a : Matrix3, b : Vector3) = let res = b*a let c1 = b.X * a.M11 + b.Y * a.M21 + b.Z * a.M31 let c2 = b.X * a.M12 + b.Y * a.M22 + b.Z * a.M32 let c3 = b.X * a.M13 + b.Y * a.M23 + b.Z * a.M33 let exp = Vector3(c1, c2, c3) Assert.Equal(exp, res) [] let ``Static Vector3 multiplication method works`` (a : Vector3, b : Vector3) = let v1 = Vector3(a.X * b.X, a.Y * b.Y, a.Z * b.Z) let sum = Vector3.Multiply(a, b) Assert.ApproximatelyEqual(v1, sum) [] let ``Static Vector3 multiplication method works by reference`` (a : Vector3, b : Vector3) = let v1 = Vector3(a.X * b.X, a.Y * b.Y, a.Z * b.Z) let sum = Vector3.Multiply(ref a, ref b) Assert.ApproximatelyEqual(v1, sum) [ |])>] module Division = // [] let ``Vector3-float division is the same as component-float division`` (a : Vector3, f : float32) = if not (approxEq f 0.0f) then // we don't support diving by zero. let r = a / f Assert.ApproximatelyEqual(a.X / f,r.X) Assert.ApproximatelyEqual(a.Y / f,r.Y) Assert.ApproximatelyEqual(a.Z / f,r.Z) [] let ``Static Vector3-Vector3 division method works`` (a : Vector3, b : Vector3) = let v1 = Vector3(a.X / b.X, a.Y / b.Y, a.Z / b.Z) let sum = Vector3.Divide(a, b) Assert.ApproximatelyEqual(v1, sum) [] let ``Static Vector3-Vector3 divison method works by reference`` (a : Vector3, b : Vector3) = let v1 = Vector3(a.X / b.X, a.Y / b.Y, a.Z / b.Z) let sum = Vector3.Divide(ref a, ref b) Assert.ApproximatelyEqual(v1, sum) [] let ``Static Vector3-scalar division method works`` (a : Vector3, b : float32) = let v1 = Vector3(a.X / b, a.Y / b, a.Z / b) let sum = Vector3.Divide(a, b) Assert.ApproximatelyEqual(v1, sum) [] let ``Static Vector3-scalar divison method works by reference`` (a : Vector3, b : float32) = let v1 = Vector3(a.X / b, a.Y / b, a.Z / b) let sum = Vector3.Divide(ref a, b) Assert.ApproximatelyEqual(v1, sum) [ |])>] module Negation = // [] let ``Vector negation operator works`` (x, y, z) = let v = Vector3(x, y, z) let vNeg = -v Assert.Equal(-x, vNeg.X) Assert.Equal(-y, vNeg.Y) Assert.Equal(-z, vNeg.Z) [ |])>] module Equality = // [] let ``Vector equality operator works`` (x, y, z) = let v1 = Vector3(x, y, z) let v2 = Vector3(x, y, z) let equality = v1 = v2 Assert.True(equality) [] let ``Vector inequality operator works`` (x, y, z) = let v1 = Vector3(x, y, z) let v2 = Vector3(x + (float32)1 , y + (float32)1, z + (float32)1) let inequality = v1 <> v2 Assert.True(inequality) [] let ``Vector equality method works`` (x, y, z) = let v1 = Vector3(x, y, z) let v2 = Vector3(x, y, z) let notVector = Matrix2() let equality = v1.Equals(v2) let inequalityByOtherType = v1.Equals(notVector) Assert.True(equality) Assert.False(inequalityByOtherType) [ |])>] module Swizzling = // [] let ``Vector swizzling works`` (x, y, z) = let v = Vector3(x, y, z) let xyz = Vector3(x, y, z) let xzy = Vector3(x, z, y) let xy = Vector2(x, y) let xz = Vector2(x, z) let yxz = Vector3(y, x, z) let yzx = Vector3(y, z, x) let yx = Vector2(y, x) let yz = Vector2(y, z) let zxy = Vector3(z, x, y) let zyx = Vector3(z, y, x) let zx = Vector2(z, x) let zy = Vector2(z, y) Assert.Equal(xyz, v); Assert.Equal(xzy, v.Xzy); Assert.Equal(xy, v.Xy); Assert.Equal(xz, v.Xz); Assert.Equal(yxz, v.Yxz); Assert.Equal(yzx, v.Yzx); Assert.Equal(yx, v.Yx); Assert.Equal(yz, v.Yz); Assert.Equal(zxy, v.Zxy); Assert.Equal(zyx, v.Zyx); Assert.Equal(zx, v.Zx); Assert.Equal(zy, v.Zy); [ |])>] module Interpolation = // [] let ``Linear interpolation works`` (a : Vector3, b : Vector3, q) = let blend = q let rX = blend * (b.X - a.X) + a.X let rY = blend * (b.Y - a.Y) + a.Y let rZ = blend * (b.Z - a.Z) + a.Z let vExp = Vector3(rX, rY, rZ) Assert.Equal(vExp, Vector3.Lerp(a, b, q)) let vRes = Vector3.Lerp(ref a, ref b, q) Assert.Equal(vExp, vRes) [] let ``Barycentric interpolation works`` (a : Vector3, b : Vector3, c : Vector3, u, v) = let r = a + u * (b - a) + v * (c - a) Assert.Equal(r, Vector3.BaryCentric(a, b, c, u, v)) let vRes = Vector3.BaryCentric(ref a, ref b, ref c, u, v) Assert.Equal(r, vRes) [ |])>] module ``Vector products`` = // [] let ``Dot product works`` (a : Vector3, b : Vector3) = let dot = a.X * b.X + a.Y * b.Y + a.Z * b.Z Assert.Equal(dot, Vector3.Dot(a, b)); let vRes = Vector3.Dot(ref a, ref b) Assert.Equal(dot, vRes) [] let ``Cross product works`` (a : Vector3, b : Vector3) = let crossX = a.Y * b.Z - a.Z * b.Y let crossY = a.Z * b.X - a.X * b.Z let crossZ = a.X * b.Y - a.Y * b.X let cross = Vector3(crossX, crossY, crossZ) Assert.Equal(cross, Vector3.Cross(a, b)); let vRes = Vector3.Cross(ref a, ref b) Assert.Equal(cross, vRes) [ |])>] module ``Component min and max`` = // [] let ``Producing a new vector from the smallest components of given vectors works`` (x, y, z, u, w, q) = let v1 = Vector3(x, y, z) let v2 = Vector3(u, w, q) let vMin = Vector3.ComponentMin(v1, v2) Assert.True(vMin.X <= v1.X) Assert.True(vMin.X <= v2.X) Assert.True(vMin.Y <= v1.Y) Assert.True(vMin.Y <= v2.Y) Assert.True(vMin.Z <= v1.Z) Assert.True(vMin.Z <= v2.Z) [] let ``Producing a new vector from the largest components of given vectors works`` (x, y, z, u, w, q) = let v1 = Vector3(x, y, z) let v2 = Vector3(u, w, q) let vMax = Vector3.ComponentMax(v1, v2) Assert.True(vMax.X >= v1.X) Assert.True(vMax.X >= v2.X) Assert.True(vMax.Y >= v1.Y) Assert.True(vMax.Y >= v2.Y) Assert.True(vMax.Z >= v1.Z) Assert.True(vMax.Z >= v2.Z) [] let ``Producing a new vector from the smallest components of given vectors by reference works`` (x, y, z, u, w, q) = let v1 = Vector3(x, y, z) let v2 = Vector3(u, w, q) let vMin = Vector3.ComponentMin(ref v1, ref v2) Assert.True(vMin.X <= v1.X) Assert.True(vMin.X <= v2.X) Assert.True(vMin.Y <= v1.Y) Assert.True(vMin.Y <= v2.Y) Assert.True(vMin.Z <= v1.Z) Assert.True(vMin.Z <= v2.Z) [] let ``Producing a new vector from the largest components of given vectors by reference works`` (x, y, z, u, w, q) = let v1 = Vector3(x, y, z) let v2 = Vector3(u, w, q) let vMax = Vector3.ComponentMax(ref v1, ref v2) Assert.True(vMax.X >= v1.X) Assert.True(vMax.X >= v2.X) Assert.True(vMax.Y >= v1.Y) Assert.True(vMax.Y >= v2.Y) Assert.True(vMax.Z >= v1.Z) Assert.True(vMax.Z >= v2.Z) [] let ``Selecting the lesser of two vectors works`` (x, y, z, u, w, q) = let v1 = Vector3(x, y, z) let v2 = Vector3(u, w, q) let l1 = v1.LengthSquared let l2 = v2.LengthSquared let vMin = Vector3.Min(v1, v2) if l1 < l2 then let equalsFirst = vMin = v1 Assert.True(equalsFirst) else let equalsLast = vMin = v2 Assert.True(equalsLast) [] let ``Selecting the greater of two vectors works`` (x, y, z, u, w, q) = let v1 = Vector3(x, y, z) let v2 = Vector3(u, w, q) let l1 = v1.LengthSquared let l2 = v2.LengthSquared let vMin = Vector3.Max(v1, v2) if l1 >= l2 then let equalsFirst = vMin = v1 Assert.True(equalsFirst) else let equalsLast = vMin = v2 Assert.True(equalsLast) [ |])>] module Clamping = // [] let ``Clamping one vector between two other vectors works`` (a : Vector3, b : Vector3, w : Vector3) = let res = Vector3.Clamp(w, a, b) let expX = if w.X < a.X then a.X else if w.X > b.X then b.X else w.X let expY = if w.Y < a.Y then a.Y else if w.Y > b.Y then b.Y else w.Y let expZ = if w.Z < a.Z then a.Z else if w.Z > b.Z then b.Z else w.Z Assert.Equal(expX, res.X) Assert.Equal(expY, res.Y) Assert.Equal(expZ, res.Z) [] let ``Clamping one vector between two other vectors works by reference`` (a : Vector3, b : Vector3, w : Vector3) = let res = Vector3.Clamp(ref w, ref a, ref b) let expX = if w.X < a.X then a.X else if w.X > b.X then b.X else w.X let expY = if w.Y < a.Y then a.Y else if w.Y > b.Y then b.Y else w.Y let expZ = if w.Z < a.Z then a.Z else if w.Z > b.Z then b.Z else w.Z Assert.Equal(expX, res.X) Assert.Equal(expY, res.Y) Assert.Equal(expZ, res.Z) [ |])>] module ``Unit vectors``= // [] let ``Unit X is correct`` = let unitX = Vector3((float32)1, (float32)0, (float32)0) Assert.Equal(Vector3.UnitX, unitX) [] let ``Unit Y is correct`` = let unitY = Vector3((float32)0, (float32)1, (float32)0) Assert.Equal(Vector3.UnitY, unitY) [] let ``Unit Z is correct`` = let unitZ = Vector3((float32)0, (float32)0, (float32)1) Assert.Equal(Vector3.UnitZ, unitZ) [] let ``Unit zero is correct`` = let unitZero = Vector3((float32)0, (float32)0, (float32)0) Assert.Equal(Vector3.Zero, unitZero) [] let ``Unit one is correct`` = let unitOne = Vector3((float32)1, (float32)1, (float32)1) Assert.Equal(Vector3.One, unitOne)