diff --git a/packages/vector_math/CHANGELOG.md b/packages/vector_math/CHANGELOG.md index a232ed01..af54597b 100644 --- a/packages/vector_math/CHANGELOG.md +++ b/packages/vector_math/CHANGELOG.md @@ -1,3 +1,10 @@ +## 2.4.3 + +* Optimizes `normalizeInto`, `min`, `max` and `mix` on `Vector2`, `Vector3` + and `Vector4` to compute their result first and write the `out`/`result` + parameter with a single `setValues` call, and aligns `copyInto` with the + same pattern. + ## 2.4.2 * Documents the public geometry filter APIs. diff --git a/packages/vector_math/lib/src/vector_math/vector2.dart b/packages/vector_math/lib/src/vector_math/vector2.dart index 5e4a3c19..b0de57b8 100644 --- a/packages/vector_math/lib/src/vector_math/vector2.dart +++ b/packages/vector_math/lib/src/vector_math/vector2.dart @@ -47,24 +47,20 @@ class Vector2 implements Vector { /// Set the values of [result] to the minimum of [a] and [b] for each line. static void min(Vector2 a, Vector2 b, Vector2 result) { - result - ..x = math.min(a.x, b.x) - ..y = math.min(a.y, b.y); + result.setValues(math.min(a.x, b.x), math.min(a.y, b.y)); } /// Set the values of [result] to the maximum of [a] and [b] for each line. static void max(Vector2 a, Vector2 b, Vector2 result) { - result - ..x = math.max(a.x, b.x) - ..y = math.max(a.y, b.y); + result.setValues(math.max(a.x, b.x), math.max(a.y, b.y)); } /// Interpolate between [min] and [max] with the amount of [a] using a linear /// interpolation and store the values in [result]. static void mix(Vector2 min, Vector2 max, double a, Vector2 result) { - result - ..x = min.x + a * (max.x - min.x) - ..y = min.y + a * (max.y - min.y); + final double x = min.x + a * (max.x - min.x); + final double y = min.y + a * (max.y - min.y); + result.setValues(x, y); } /// Set the values of the vector. @@ -174,9 +170,13 @@ class Vector2 implements Vector { /// Normalize vector into [out]. Vector2 normalizeInto(Vector2 out) { - out - ..setFrom(this) - ..normalize(); + final double l = length; + if (l == 0.0) { + out.setValues(_v2storage[0], _v2storage[1]); + } else { + final double d = 1.0 / l; + out.setValues(_v2storage[0] * d, _v2storage[1] * d); + } return out; } @@ -378,9 +378,7 @@ class Vector2 implements Vector { /// Copy this into [arg]. Returns [arg]. Vector2 copyInto(Vector2 arg) { - final Float32List argStorage = arg._v2storage; - argStorage[1] = _v2storage[1]; - argStorage[0] = _v2storage[0]; + arg.setValues(_v2storage[0], _v2storage[1]); return arg; } diff --git a/packages/vector_math/lib/src/vector_math/vector3.dart b/packages/vector_math/lib/src/vector_math/vector3.dart index 2fcad23c..950d28e3 100644 --- a/packages/vector_math/lib/src/vector_math/vector3.dart +++ b/packages/vector_math/lib/src/vector_math/vector3.dart @@ -47,27 +47,28 @@ class Vector3 implements Vector { /// Set the values of [result] to the minimum of [a] and [b] for each line. static void min(Vector3 a, Vector3 b, Vector3 result) { - result - ..x = math.min(a.x, b.x) - ..y = math.min(a.y, b.y) - ..z = math.min(a.z, b.z); + final double x = math.min(a.x, b.x); + final double y = math.min(a.y, b.y); + final double z = math.min(a.z, b.z); + result.setValues(x, y, z); } /// Set the values of [result] to the maximum of [a] and [b] for each line. static void max(Vector3 a, Vector3 b, Vector3 result) { - result - ..x = math.max(a.x, b.x) - ..y = math.max(a.y, b.y) - ..z = math.max(a.z, b.z); + final double x = math.max(a.x, b.x); + final double y = math.max(a.y, b.y); + final double z = math.max(a.z, b.z); + result.setValues(x, y, z); } /// Interpolate between [min] and [max] with the amount of [a] using a linear /// interpolation and store the values in [result]. static void mix(Vector3 min, Vector3 max, double a, Vector3 result) { - result - ..x = min.x + a * (max.x - min.x) - ..y = min.y + a * (max.y - min.y) - ..z = min.z + a * (max.z - min.z); + result.setValues( + min.x + a * (max.x - min.x), + min.y + a * (max.y - min.y), + min.z + a * (max.z - min.z), + ); } /// Set the values of the vector. @@ -190,9 +191,13 @@ class Vector3 implements Vector { /// Normalize vector into [out]. Vector3 normalizeInto(Vector3 out) { - out - ..setFrom(this) - ..normalize(); + final double l = length; + if (l == 0.0) { + out.setValues(_v3storage[0], _v3storage[1], _v3storage[2]); + } else { + final double d = 1.0 / l; + out.setValues(_v3storage[0] * d, _v3storage[1] * d, _v3storage[2] * d); + } return out; } @@ -496,10 +501,7 @@ class Vector3 implements Vector { /// Copy this into [arg]. Vector3 copyInto(Vector3 arg) { - final Float32List argStorage = arg._v3storage; - argStorage[2] = _v3storage[2]; - argStorage[1] = _v3storage[1]; - argStorage[0] = _v3storage[0]; + arg.setValues(_v3storage[0], _v3storage[1], _v3storage[2]); return arg; } diff --git a/packages/vector_math/lib/src/vector_math/vector4.dart b/packages/vector_math/lib/src/vector_math/vector4.dart index 599e0899..086d5612 100644 --- a/packages/vector_math/lib/src/vector_math/vector4.dart +++ b/packages/vector_math/lib/src/vector_math/vector4.dart @@ -46,30 +46,33 @@ class Vector4 implements Vector { /// Set the values of [result] to the minimum of [a] and [b] for each line. static void min(Vector4 a, Vector4 b, Vector4 result) { - result - ..x = math.min(a.x, b.x) - ..y = math.min(a.y, b.y) - ..z = math.min(a.z, b.z) - ..w = math.min(a.w, b.w); + result.setValues( + math.min(a.x, b.x), + math.min(a.y, b.y), + math.min(a.z, b.z), + math.min(a.w, b.w), + ); } /// Set the values of [result] to the maximum of [a] and [b] for each line. static void max(Vector4 a, Vector4 b, Vector4 result) { - result - ..x = math.max(a.x, b.x) - ..y = math.max(a.y, b.y) - ..z = math.max(a.z, b.z) - ..w = math.max(a.w, b.w); + result.setValues( + math.max(a.x, b.x), + math.max(a.y, b.y), + math.max(a.z, b.z), + math.max(a.w, b.w), + ); } /// Interpolate between [min] and [max] with the amount of [a] using a linear /// interpolation and store the values in [result]. static void mix(Vector4 min, Vector4 max, double a, Vector4 result) { - result - ..x = min.x + a * (max.x - min.x) - ..y = min.y + a * (max.y - min.y) - ..z = min.z + a * (max.z - min.z) - ..w = min.w + a * (max.w - min.w); + result.setValues( + min.x + a * (max.x - min.x), + min.y + a * (max.y - min.y), + min.z + a * (max.z - min.z), + min.w + a * (max.w - min.w), + ); } /// The components of the vector. @@ -211,9 +214,17 @@ class Vector4 implements Vector { /// Normalize vector into [out]. Vector4 normalizeInto(Vector4 out) { - out - ..setFrom(this) - ..normalize(); + final double l = length; + if (l == 0.0) { + out.setValues(_v4storage[0], _v4storage[1], _v4storage[2], _v4storage[3]); + } else { + final double d = 1.0 / l; + final double x = _v4storage[0] * d; + final double y = _v4storage[1] * d; + final double z = _v4storage[2] * d; + final double w = _v4storage[3] * d; + out.setValues(x, y, z, w); + } return out; } @@ -414,11 +425,7 @@ class Vector4 implements Vector { /// Copy this Vector4 copyInto(Vector4 arg) { - final Float32List argStorage = arg._v4storage; - argStorage[3] = _v4storage[3]; - argStorage[2] = _v4storage[2]; - argStorage[1] = _v4storage[1]; - argStorage[0] = _v4storage[0]; + arg.setValues(_v4storage[0], _v4storage[1], _v4storage[2], _v4storage[3]); return arg; } diff --git a/packages/vector_math/lib/src/vector_math_64/vector2.dart b/packages/vector_math/lib/src/vector_math_64/vector2.dart index 1ba3f853..556d74d0 100644 --- a/packages/vector_math/lib/src/vector_math_64/vector2.dart +++ b/packages/vector_math/lib/src/vector_math_64/vector2.dart @@ -47,24 +47,20 @@ class Vector2 implements Vector { /// Set the values of [result] to the minimum of [a] and [b] for each line. static void min(Vector2 a, Vector2 b, Vector2 result) { - result - ..x = math.min(a.x, b.x) - ..y = math.min(a.y, b.y); + result.setValues(math.min(a.x, b.x), math.min(a.y, b.y)); } /// Set the values of [result] to the maximum of [a] and [b] for each line. static void max(Vector2 a, Vector2 b, Vector2 result) { - result - ..x = math.max(a.x, b.x) - ..y = math.max(a.y, b.y); + result.setValues(math.max(a.x, b.x), math.max(a.y, b.y)); } /// Interpolate between [min] and [max] with the amount of [a] using a linear /// interpolation and store the values in [result]. static void mix(Vector2 min, Vector2 max, double a, Vector2 result) { - result - ..x = min.x + a * (max.x - min.x) - ..y = min.y + a * (max.y - min.y); + final double x = min.x + a * (max.x - min.x); + final double y = min.y + a * (max.y - min.y); + result.setValues(x, y); } /// Set the values of the vector. @@ -174,9 +170,13 @@ class Vector2 implements Vector { /// Normalize vector into [out]. Vector2 normalizeInto(Vector2 out) { - out - ..setFrom(this) - ..normalize(); + final double l = length; + if (l == 0.0) { + out.setValues(_v2storage[0], _v2storage[1]); + } else { + final double d = 1.0 / l; + out.setValues(_v2storage[0] * d, _v2storage[1] * d); + } return out; } @@ -378,9 +378,7 @@ class Vector2 implements Vector { /// Copy this into [arg]. Returns [arg]. Vector2 copyInto(Vector2 arg) { - final Float64List argStorage = arg._v2storage; - argStorage[1] = _v2storage[1]; - argStorage[0] = _v2storage[0]; + arg.setValues(_v2storage[0], _v2storage[1]); return arg; } diff --git a/packages/vector_math/lib/src/vector_math_64/vector3.dart b/packages/vector_math/lib/src/vector_math_64/vector3.dart index b1341d2b..210a5540 100644 --- a/packages/vector_math/lib/src/vector_math_64/vector3.dart +++ b/packages/vector_math/lib/src/vector_math_64/vector3.dart @@ -47,27 +47,28 @@ class Vector3 implements Vector { /// Set the values of [result] to the minimum of [a] and [b] for each line. static void min(Vector3 a, Vector3 b, Vector3 result) { - result - ..x = math.min(a.x, b.x) - ..y = math.min(a.y, b.y) - ..z = math.min(a.z, b.z); + final double x = math.min(a.x, b.x); + final double y = math.min(a.y, b.y); + final double z = math.min(a.z, b.z); + result.setValues(x, y, z); } /// Set the values of [result] to the maximum of [a] and [b] for each line. static void max(Vector3 a, Vector3 b, Vector3 result) { - result - ..x = math.max(a.x, b.x) - ..y = math.max(a.y, b.y) - ..z = math.max(a.z, b.z); + final double x = math.max(a.x, b.x); + final double y = math.max(a.y, b.y); + final double z = math.max(a.z, b.z); + result.setValues(x, y, z); } /// Interpolate between [min] and [max] with the amount of [a] using a linear /// interpolation and store the values in [result]. static void mix(Vector3 min, Vector3 max, double a, Vector3 result) { - result - ..x = min.x + a * (max.x - min.x) - ..y = min.y + a * (max.y - min.y) - ..z = min.z + a * (max.z - min.z); + result.setValues( + min.x + a * (max.x - min.x), + min.y + a * (max.y - min.y), + min.z + a * (max.z - min.z), + ); } /// Set the values of the vector. @@ -190,9 +191,13 @@ class Vector3 implements Vector { /// Normalize vector into [out]. Vector3 normalizeInto(Vector3 out) { - out - ..setFrom(this) - ..normalize(); + final double l = length; + if (l == 0.0) { + out.setValues(_v3storage[0], _v3storage[1], _v3storage[2]); + } else { + final double d = 1.0 / l; + out.setValues(_v3storage[0] * d, _v3storage[1] * d, _v3storage[2] * d); + } return out; } @@ -496,10 +501,7 @@ class Vector3 implements Vector { /// Copy this into [arg]. Vector3 copyInto(Vector3 arg) { - final Float64List argStorage = arg._v3storage; - argStorage[2] = _v3storage[2]; - argStorage[1] = _v3storage[1]; - argStorage[0] = _v3storage[0]; + arg.setValues(_v3storage[0], _v3storage[1], _v3storage[2]); return arg; } diff --git a/packages/vector_math/lib/src/vector_math_64/vector4.dart b/packages/vector_math/lib/src/vector_math_64/vector4.dart index dc0be723..ab22b849 100644 --- a/packages/vector_math/lib/src/vector_math_64/vector4.dart +++ b/packages/vector_math/lib/src/vector_math_64/vector4.dart @@ -46,30 +46,33 @@ class Vector4 implements Vector { /// Set the values of [result] to the minimum of [a] and [b] for each line. static void min(Vector4 a, Vector4 b, Vector4 result) { - result - ..x = math.min(a.x, b.x) - ..y = math.min(a.y, b.y) - ..z = math.min(a.z, b.z) - ..w = math.min(a.w, b.w); + result.setValues( + math.min(a.x, b.x), + math.min(a.y, b.y), + math.min(a.z, b.z), + math.min(a.w, b.w), + ); } /// Set the values of [result] to the maximum of [a] and [b] for each line. static void max(Vector4 a, Vector4 b, Vector4 result) { - result - ..x = math.max(a.x, b.x) - ..y = math.max(a.y, b.y) - ..z = math.max(a.z, b.z) - ..w = math.max(a.w, b.w); + result.setValues( + math.max(a.x, b.x), + math.max(a.y, b.y), + math.max(a.z, b.z), + math.max(a.w, b.w), + ); } /// Interpolate between [min] and [max] with the amount of [a] using a linear /// interpolation and store the values in [result]. static void mix(Vector4 min, Vector4 max, double a, Vector4 result) { - result - ..x = min.x + a * (max.x - min.x) - ..y = min.y + a * (max.y - min.y) - ..z = min.z + a * (max.z - min.z) - ..w = min.w + a * (max.w - min.w); + result.setValues( + min.x + a * (max.x - min.x), + min.y + a * (max.y - min.y), + min.z + a * (max.z - min.z), + min.w + a * (max.w - min.w), + ); } /// The components of the vector. @@ -211,9 +214,17 @@ class Vector4 implements Vector { /// Normalize vector into [out]. Vector4 normalizeInto(Vector4 out) { - out - ..setFrom(this) - ..normalize(); + final double l = length; + if (l == 0.0) { + out.setValues(_v4storage[0], _v4storage[1], _v4storage[2], _v4storage[3]); + } else { + final double d = 1.0 / l; + final double x = _v4storage[0] * d; + final double y = _v4storage[1] * d; + final double z = _v4storage[2] * d; + final double w = _v4storage[3] * d; + out.setValues(x, y, z, w); + } return out; } @@ -414,11 +425,7 @@ class Vector4 implements Vector { /// Copy this Vector4 copyInto(Vector4 arg) { - final Float64List argStorage = arg._v4storage; - argStorage[3] = _v4storage[3]; - argStorage[2] = _v4storage[2]; - argStorage[1] = _v4storage[1]; - argStorage[0] = _v4storage[0]; + arg.setValues(_v4storage[0], _v4storage[1], _v4storage[2], _v4storage[3]); return arg; } diff --git a/packages/vector_math/pubspec.yaml b/packages/vector_math/pubspec.yaml index 89b201e2..fa38b2ed 100644 --- a/packages/vector_math/pubspec.yaml +++ b/packages/vector_math/pubspec.yaml @@ -5,7 +5,7 @@ name: vector_math description: A vector math library for 2D and 3D applications, supporting 2D, 3D, and 4D matrices. repository: https://github.com/flutter/core-packages/tree/main/packages/vector_math issue_tracker: https://github.com/flutter/flutter/issues?q=is%3Aissue+is%3Aopen+label%3A%22p%3A+vector_math%22 -version: 2.4.2 +version: 2.4.3 environment: sdk: ^3.10.0 diff --git a/packages/vector_math/test/out_parameter_test.dart b/packages/vector_math/test/out_parameter_test.dart new file mode 100644 index 00000000..7688d4f6 --- /dev/null +++ b/packages/vector_math/test/out_parameter_test.dart @@ -0,0 +1,106 @@ +// Copyright 2013 The Flutter Authors +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. + +import 'package:test/test.dart'; +import 'package:vector_math/vector_math.dart'; + +import 'test_utils.dart'; + +void testVector2OutParameters() { + final a = Vector2(3.0, -4.0); + final b = Vector2(-1.0, 2.0); + final out = Vector2.zero(); + + expect(identical(a.normalizeInto(out), out), isTrue); + relativeTest(out, Vector2(0.6, -0.8)); + relativeTest(a, Vector2(3.0, -4.0)); + + Vector2.zero().normalizeInto(out); + relativeTest(out, Vector2.zero()); + + expect(identical(a.copyInto(out), out), isTrue); + relativeTest(out, a); + + Vector2.min(a, b, out); + relativeTest(out, Vector2(-1.0, -4.0)); + + Vector2.max(a, b, out); + relativeTest(out, Vector2(3.0, 2.0)); + + Vector2.mix(a, b, 0.25, out); + relativeTest(out, Vector2(2.0, -2.5)); +} + +void testVector3OutParameters() { + final a = Vector3(2.0, -3.0, 6.0); + final b = Vector3(-1.0, 4.0, 2.0); + final out = Vector3.zero(); + + expect(identical(a.normalizeInto(out), out), isTrue); + relativeTest(out, Vector3(2.0 / 7.0, -3.0 / 7.0, 6.0 / 7.0)); + relativeTest(a, Vector3(2.0, -3.0, 6.0)); + + Vector3.zero().normalizeInto(out); + relativeTest(out, Vector3.zero()); + + expect(identical(a.copyInto(out), out), isTrue); + relativeTest(out, a); + + Vector3.min(a, b, out); + relativeTest(out, Vector3(-1.0, -3.0, 2.0)); + + Vector3.max(a, b, out); + relativeTest(out, Vector3(2.0, 4.0, 6.0)); + + Vector3.mix(a, b, 0.5, out); + relativeTest(out, Vector3(0.5, 0.5, 4.0)); +} + +void testVector4OutParameters() { + final a = Vector4(1.0, -1.0, 1.0, -1.0); + final b = Vector4(-2.0, 2.0, 0.0, 3.0); + final out = Vector4.zero(); + + expect(identical(a.normalizeInto(out), out), isTrue); + relativeTest(out, Vector4(0.5, -0.5, 0.5, -0.5)); + relativeTest(a, Vector4(1.0, -1.0, 1.0, -1.0)); + + Vector4.zero().normalizeInto(out); + relativeTest(out, Vector4.zero()); + + expect(identical(a.copyInto(out), out), isTrue); + relativeTest(out, a); + + Vector4.min(a, b, out); + relativeTest(out, Vector4(-2.0, -1.0, 0.0, -1.0)); + + Vector4.max(a, b, out); + relativeTest(out, Vector4(1.0, 2.0, 1.0, 3.0)); + + Vector4.mix(a, b, 0.5, out); + relativeTest(out, Vector4(-0.5, 0.5, 0.5, 1.0)); +} + +void testNormalizeIntoSelf() { + final v2 = Vector2(3.0, -4.0); + v2.normalizeInto(v2); + relativeTest(v2, Vector2(0.6, -0.8)); + + final v3 = Vector3(2.0, -3.0, 6.0); + v3.normalizeInto(v3); + relativeTest(v3, Vector3(2.0 / 7.0, -3.0 / 7.0, 6.0 / 7.0)); + + final v4 = Vector4(1.0, -1.0, 1.0, -1.0); + v4.normalizeInto(v4); + relativeTest(v4, Vector4(0.5, -0.5, 0.5, -0.5)); +} + +void main() { + group('Out parameters', () { + test('Vector2', testVector2OutParameters); + test('Vector3', testVector3OutParameters); + test('Vector4', testVector4OutParameters); + test('normalizeInto self', testNormalizeIntoSelf); + }); +}