diff --git a/Microsoft.Toolkit.Uwp.UI.Animations/Expressions/CompositionExtensions.cs b/Microsoft.Toolkit.Uwp.UI.Animations/Expressions/CompositionExtensions.cs
index 521d69ea2a9..3dea1f5c27c 100644
--- a/Microsoft.Toolkit.Uwp.UI.Animations/Expressions/CompositionExtensions.cs
+++ b/Microsoft.Toolkit.Uwp.UI.Animations/Expressions/CompositionExtensions.cs
@@ -263,5 +263,46 @@ private static ExpressionAnimation CreateExpressionAnimationFromNode(Compositor
return expressionNode.ExpressionAnimation;
}
+
+ internal static float EvaluateSubchannel(this ExpressionNode node, string subchannel) => (node, subchannel) switch
+ {
+ (Vector2Node n, "X") => n.Evaluate().X,
+ (Vector2Node n, "Y") => n.Evaluate().Y,
+
+ (Vector3Node n, "X") => n.Evaluate().X,
+ (Vector3Node n, "Y") => n.Evaluate().Y,
+ (Vector3Node n, "Z") => n.Evaluate().Z,
+
+ (Vector4Node n, "X") => n.Evaluate().X,
+ (Vector4Node n, "Y") => n.Evaluate().Y,
+ (Vector4Node n, "Z") => n.Evaluate().Z,
+ (Vector4Node n, "W") => n.Evaluate().W,
+
+ (Matrix3x2Node n, "Channel11") => n.Evaluate().M11,
+ (Matrix3x2Node n, "Channel12") => n.Evaluate().M12,
+ (Matrix3x2Node n, "Channel21") => n.Evaluate().M21,
+ (Matrix3x2Node n, "Channel22") => n.Evaluate().M22,
+ (Matrix3x2Node n, "Channel31") => n.Evaluate().M31,
+ (Matrix3x2Node n, "Channel32") => n.Evaluate().M32,
+
+ (Matrix4x4Node n, "Channel11") => n.Evaluate().M11,
+ (Matrix4x4Node n, "Channel12") => n.Evaluate().M12,
+ (Matrix4x4Node n, "Channel13") => n.Evaluate().M13,
+ (Matrix4x4Node n, "Channel14") => n.Evaluate().M14,
+ (Matrix4x4Node n, "Channel21") => n.Evaluate().M21,
+ (Matrix4x4Node n, "Channel22") => n.Evaluate().M22,
+ (Matrix4x4Node n, "Channel23") => n.Evaluate().M23,
+ (Matrix4x4Node n, "Channel24") => n.Evaluate().M24,
+ (Matrix4x4Node n, "Channel31") => n.Evaluate().M31,
+ (Matrix4x4Node n, "Channel32") => n.Evaluate().M32,
+ (Matrix4x4Node n, "Channel33") => n.Evaluate().M33,
+ (Matrix4x4Node n, "Channel34") => n.Evaluate().M34,
+ (Matrix4x4Node n, "Channel41") => n.Evaluate().M41,
+ (Matrix4x4Node n, "Channel42") => n.Evaluate().M42,
+ (Matrix4x4Node n, "Channel43") => n.Evaluate().M43,
+ (Matrix4x4Node n, "Channel44") => n.Evaluate().M44,
+
+ _ => 0
+ };
}
}
\ No newline at end of file
diff --git a/Microsoft.Toolkit.Uwp.UI.Animations/Expressions/ExpressionNodes/BooleanNode.cs b/Microsoft.Toolkit.Uwp.UI.Animations/Expressions/ExpressionNodes/BooleanNode.cs
index 6e49f5e9417..625cf7dbbae 100644
--- a/Microsoft.Toolkit.Uwp.UI.Animations/Expressions/ExpressionNodes/BooleanNode.cs
+++ b/Microsoft.Toolkit.Uwp.UI.Animations/Expressions/ExpressionNodes/BooleanNode.cs
@@ -2,6 +2,8 @@
// The .NET Foundation licenses this file to you under the MIT license.
// See the LICENSE file in the project root for more information.
+using System;
+
namespace Microsoft.Toolkit.Uwp.UI.Animations.Expressions
{
// Ignore warning: 'BooleanNode' defines operator == or operator != but does not override Object.Equals(object o) && Object.GetHashCode()
@@ -127,6 +129,67 @@ protected internal override string GetValue()
}
private bool _value;
+
+ ///
+ /// Evaluates the current value of the expression
+ ///
+ /// The current value of the expression
+ public bool Evaluate()
+ {
+ switch (NodeType)
+ {
+ case ExpressionNodeType.ConstantValue:
+ return _value;
+ case ExpressionNodeType.Equals:
+ return Equals(Children[0], Children[1]);
+ case ExpressionNodeType.NotEquals:
+ return !Equals(Children[0], Children[1]);
+ case ExpressionNodeType.And:
+ return (Children[0] as BooleanNode).Evaluate() && (Children[1] as BooleanNode).Evaluate();
+ case ExpressionNodeType.Or:
+ return (Children[0] as BooleanNode).Evaluate() || (Children[1] as BooleanNode).Evaluate();
+ case ExpressionNodeType.LessThan:
+ return (Children[0] as ScalarNode).Evaluate() < (Children[1] as ScalarNode).Evaluate();
+ case ExpressionNodeType.LessThanEquals:
+ return (Children[0] as ScalarNode).Evaluate() <= (Children[1] as ScalarNode).Evaluate();
+ case ExpressionNodeType.GreaterThan:
+ return (Children[0] as ScalarNode).Evaluate() > (Children[1] as ScalarNode).Evaluate();
+ case ExpressionNodeType.GreaterThanEquals:
+ return (Children[0] as ScalarNode).Evaluate() >= (Children[1] as ScalarNode).Evaluate();
+ case ExpressionNodeType.Not:
+ return !(Children[0] as BooleanNode).Evaluate();
+ case ExpressionNodeType.ReferenceProperty:
+ var reference = (Children[0] as ReferenceNode).Reference;
+ switch (PropertyName)
+ {
+ default:
+ reference.Properties.TryGetBoolean(PropertyName, out var referencedProperty);
+ return referencedProperty;
+ }
+
+ case ExpressionNodeType.Conditional:
+ return
+ (Children[0] as BooleanNode).Evaluate() ?
+ (Children[1] as BooleanNode).Evaluate() :
+ (Children[2] as BooleanNode).Evaluate();
+ default:
+ throw new NotImplementedException();
+ }
+
+ bool Equals(ExpressionNode e1, ExpressionNode e2) => (e1, e2) switch
+ {
+ (BooleanNode n1, BooleanNode n2) => n1.Evaluate() == n2.Evaluate(),
+ (ScalarNode n1, ScalarNode n2) => n1.Evaluate() == n2.Evaluate(),
+ (Vector2Node n1, Vector2Node n2) => n1.Evaluate() == n2.Evaluate(),
+ (Vector3Node n1, Vector3Node n2) => n1.Evaluate() == n2.Evaluate(),
+ (Vector4Node n1, Vector4Node n2) => n1.Evaluate() == n2.Evaluate(),
+ (ColorNode n1, ColorNode n2) => n1.Evaluate() == n2.Evaluate(),
+ (QuaternionNode n1, QuaternionNode n2) => n1.Evaluate() == n2.Evaluate(),
+ (Matrix3x2Node n1, Matrix3x2Node n2) => n1.Evaluate() == n2.Evaluate(),
+ (Matrix4x4Node n1, Matrix4x4Node n2) => n1.Evaluate() == n2.Evaluate(),
+ _ => false
+ };
+ }
}
#pragma warning restore CS0660, CS0661
}
\ No newline at end of file
diff --git a/Microsoft.Toolkit.Uwp.UI.Animations/Expressions/ExpressionNodes/ColorNode.cs b/Microsoft.Toolkit.Uwp.UI.Animations/Expressions/ExpressionNodes/ColorNode.cs
index 553beee5005..c442df610fd 100644
--- a/Microsoft.Toolkit.Uwp.UI.Animations/Expressions/ExpressionNodes/ColorNode.cs
+++ b/Microsoft.Toolkit.Uwp.UI.Animations/Expressions/ExpressionNodes/ColorNode.cs
@@ -2,7 +2,9 @@
// The .NET Foundation licenses this file to you under the MIT license.
// See the LICENSE file in the project root for more information.
+using System;
using Windows.UI;
+using Windows.UI.Composition;
namespace Microsoft.Toolkit.Uwp.UI.Animations.Expressions
{
@@ -97,6 +99,40 @@ protected internal override string GetValue()
}
private Color _value;
+
+ ///
+ /// Evaluates the current value of the expression
+ ///
+ /// The current value of the expression
+ public Color Evaluate()
+ {
+ switch (NodeType)
+ {
+ case ExpressionNodeType.ConstantValue:
+ return _value;
+ case ExpressionNodeType.ReferenceProperty:
+ var reference = (Children[0] as ReferenceNode).Reference;
+ return PropertyName switch
+ {
+ nameof(CompositionColorBrush.Color) => (reference as CompositionColorBrush).Color,
+ _ => GetProperty()
+ };
+
+ Color GetProperty()
+ {
+ reference.Properties.TryGetColor(PropertyName, out var value);
+ return value;
+ }
+
+ case ExpressionNodeType.Conditional:
+ return
+ (Children[0] as BooleanNode).Evaluate() ?
+ (Children[1] as ColorNode).Evaluate() :
+ (Children[2] as ColorNode).Evaluate();
+ default:
+ throw new NotImplementedException();
+ }
+ }
}
#pragma warning restore CS0660, CS0661
}
\ No newline at end of file
diff --git a/Microsoft.Toolkit.Uwp.UI.Animations/Expressions/ExpressionNodes/Matrix3x2Node.cs b/Microsoft.Toolkit.Uwp.UI.Animations/Expressions/ExpressionNodes/Matrix3x2Node.cs
index 4fe297e34f8..87155ba3073 100644
--- a/Microsoft.Toolkit.Uwp.UI.Animations/Expressions/ExpressionNodes/Matrix3x2Node.cs
+++ b/Microsoft.Toolkit.Uwp.UI.Animations/Expressions/ExpressionNodes/Matrix3x2Node.cs
@@ -2,6 +2,7 @@
// The .NET Foundation licenses this file to you under the MIT license.
// See the LICENSE file in the project root for more information.
+using System;
using System.Numerics;
namespace Microsoft.Toolkit.Uwp.UI.Animations.Expressions
@@ -336,6 +337,57 @@ protected internal override string GetValue()
}
private Matrix3x2 _value;
+
+ ///
+ /// Evaluates the current value of the expression
+ ///
+ /// The current value of the expression
+ public Matrix3x2 Evaluate()
+ {
+ switch (NodeType)
+ {
+ case ExpressionNodeType.ConstantValue:
+ return _value;
+ case ExpressionNodeType.ReferenceProperty:
+ var reference = (Children[0] as ReferenceNode).Reference;
+ reference.Properties.TryGetMatrix3x2(PropertyName, out var referencedProperty);
+ return referencedProperty;
+ case ExpressionNodeType.Add:
+ return
+ (Children[0] as Matrix3x2Node).Evaluate() +
+ (Children[1] as Matrix3x2Node).Evaluate();
+ case ExpressionNodeType.Subtract:
+ return
+ (Children[0] as Matrix3x2Node).Evaluate() -
+ (Children[1] as Matrix3x2Node).Evaluate();
+ case ExpressionNodeType.Negate:
+ return
+ -(Children[0] as Matrix3x2Node).Evaluate();
+ case ExpressionNodeType.Multiply:
+ return (Children[0], Children[1]) switch
+ {
+ (Matrix3x2Node v1, Matrix3x2Node v2) => v1.Evaluate() * v2.Evaluate(),
+ (Matrix3x2Node v1, ScalarNode s2) => v1.Evaluate() * s2.Evaluate(),
+ (ScalarNode s1, Matrix3x2Node v2) => v2.Evaluate() * s1.Evaluate(),
+ _ => throw new NotImplementedException()
+ };
+ case ExpressionNodeType.Conditional:
+ return
+ (Children[0] as BooleanNode).Evaluate() ?
+ (Children[1] as Matrix3x2Node).Evaluate() :
+ (Children[2] as Matrix3x2Node).Evaluate();
+ case ExpressionNodeType.Swizzle:
+ return new Matrix3x2(
+ Children[0].EvaluateSubchannel(Subchannels[0]),
+ Children[0].EvaluateSubchannel(Subchannels[1]),
+ Children[0].EvaluateSubchannel(Subchannels[2]),
+ Children[0].EvaluateSubchannel(Subchannels[3]),
+ Children[0].EvaluateSubchannel(Subchannels[4]),
+ Children[0].EvaluateSubchannel(Subchannels[5]));
+ default:
+ throw new NotImplementedException();
+ }
+ }
}
#pragma warning restore CS0660, CS0661
}
\ No newline at end of file
diff --git a/Microsoft.Toolkit.Uwp.UI.Animations/Expressions/ExpressionNodes/Matrix4x4Node.cs b/Microsoft.Toolkit.Uwp.UI.Animations/Expressions/ExpressionNodes/Matrix4x4Node.cs
index b75ec095e87..33bd6650465 100644
--- a/Microsoft.Toolkit.Uwp.UI.Animations/Expressions/ExpressionNodes/Matrix4x4Node.cs
+++ b/Microsoft.Toolkit.Uwp.UI.Animations/Expressions/ExpressionNodes/Matrix4x4Node.cs
@@ -2,7 +2,9 @@
// The .NET Foundation licenses this file to you under the MIT license.
// See the LICENSE file in the project root for more information.
+using System;
using System.Numerics;
+using Windows.UI.Composition;
namespace Microsoft.Toolkit.Uwp.UI.Animations.Expressions
{
@@ -410,6 +412,77 @@ protected internal override string GetValue()
}
private Matrix4x4 _value;
+
+ ///
+ /// Evaluates the current value of the expression
+ ///
+ /// The current value of the expression
+ public Matrix4x4 Evaluate()
+ {
+ switch (NodeType)
+ {
+ case ExpressionNodeType.ConstantValue:
+ return _value;
+ case ExpressionNodeType.ReferenceProperty:
+ var reference = (Children[0] as ReferenceNode).Reference;
+ return PropertyName switch
+ {
+ nameof(Visual.TransformMatrix) => (reference as Visual).TransformMatrix,
+ _ => GetProperty()
+ };
+
+ Matrix4x4 GetProperty()
+ {
+ reference.Properties.TryGetMatrix4x4(PropertyName, out var value);
+ return value;
+ }
+
+ case ExpressionNodeType.Add:
+ return
+ (Children[0] as Matrix4x4Node).Evaluate() +
+ (Children[1] as Matrix4x4Node).Evaluate();
+ case ExpressionNodeType.Subtract:
+ return
+ (Children[0] as Matrix4x4Node).Evaluate() -
+ (Children[1] as Matrix4x4Node).Evaluate();
+ case ExpressionNodeType.Negate:
+ return
+ -(Children[0] as Matrix4x4Node).Evaluate();
+ case ExpressionNodeType.Multiply:
+ return (Children[0], Children[1]) switch
+ {
+ (Matrix4x4Node v1, Matrix4x4Node v2) => v1.Evaluate() * v2.Evaluate(),
+ (Matrix4x4Node v1, ScalarNode s2) => v1.Evaluate() * s2.Evaluate(),
+ (ScalarNode s1, Matrix4x4Node v2) => v2.Evaluate() * s1.Evaluate(),
+ _ => throw new NotImplementedException()
+ };
+ case ExpressionNodeType.Conditional:
+ return
+ (Children[0] as BooleanNode).Evaluate() ?
+ (Children[1] as Matrix4x4Node).Evaluate() :
+ (Children[2] as Matrix4x4Node).Evaluate();
+ case ExpressionNodeType.Swizzle:
+ return new Matrix4x4(
+ Children[0].EvaluateSubchannel(Subchannels[0]),
+ Children[0].EvaluateSubchannel(Subchannels[1]),
+ Children[0].EvaluateSubchannel(Subchannels[2]),
+ Children[0].EvaluateSubchannel(Subchannels[3]),
+ Children[0].EvaluateSubchannel(Subchannels[4]),
+ Children[0].EvaluateSubchannel(Subchannels[5]),
+ Children[0].EvaluateSubchannel(Subchannels[6]),
+ Children[0].EvaluateSubchannel(Subchannels[7]),
+ Children[0].EvaluateSubchannel(Subchannels[8]),
+ Children[0].EvaluateSubchannel(Subchannels[9]),
+ Children[0].EvaluateSubchannel(Subchannels[10]),
+ Children[0].EvaluateSubchannel(Subchannels[11]),
+ Children[0].EvaluateSubchannel(Subchannels[12]),
+ Children[0].EvaluateSubchannel(Subchannels[13]),
+ Children[0].EvaluateSubchannel(Subchannels[14]),
+ Children[0].EvaluateSubchannel(Subchannels[15]));
+ default:
+ throw new NotImplementedException();
+ }
+ }
}
#pragma warning restore CS0660, CS0661
}
\ No newline at end of file
diff --git a/Microsoft.Toolkit.Uwp.UI.Animations/Expressions/ExpressionNodes/QuaternionNode.cs b/Microsoft.Toolkit.Uwp.UI.Animations/Expressions/ExpressionNodes/QuaternionNode.cs
index 54b09e738ca..26b29041cc0 100644
--- a/Microsoft.Toolkit.Uwp.UI.Animations/Expressions/ExpressionNodes/QuaternionNode.cs
+++ b/Microsoft.Toolkit.Uwp.UI.Animations/Expressions/ExpressionNodes/QuaternionNode.cs
@@ -2,7 +2,9 @@
// The .NET Foundation licenses this file to you under the MIT license.
// See the LICENSE file in the project root for more information.
+using System;
using System.Numerics;
+using Windows.UI.Composition;
namespace Microsoft.Toolkit.Uwp.UI.Animations.Expressions
{
@@ -130,6 +132,67 @@ protected internal override string GetValue()
}
private Quaternion _value;
+
+ ///
+ /// Evaluates the current value of the expression
+ ///
+ /// The current value of the expression
+ public Quaternion Evaluate()
+ {
+ switch (NodeType)
+ {
+ case ExpressionNodeType.ConstantValue:
+ return _value;
+ case ExpressionNodeType.ReferenceProperty:
+ var reference = (Children[0] as ReferenceNode).Reference;
+ return PropertyName switch
+ {
+ nameof(Visual.Orientation) => (reference as Visual).Orientation,
+ _ => GetProperty()
+ };
+
+ Quaternion GetProperty()
+ {
+ reference.Properties.TryGetQuaternion(PropertyName, out var value);
+ return value;
+ }
+
+ case ExpressionNodeType.Add:
+ return
+ (Children[0] as QuaternionNode).Evaluate() +
+ (Children[1] as QuaternionNode).Evaluate();
+ case ExpressionNodeType.Subtract:
+ return
+ (Children[0] as QuaternionNode).Evaluate() -
+ (Children[1] as QuaternionNode).Evaluate();
+ case ExpressionNodeType.Negate:
+ return
+ -(Children[0] as QuaternionNode).Evaluate();
+ case ExpressionNodeType.Multiply:
+ return (Children[0], Children[1]) switch
+ {
+ (QuaternionNode v1, QuaternionNode v2) => v1.Evaluate() * v2.Evaluate(),
+ (QuaternionNode v1, ScalarNode s2) => v1.Evaluate() * s2.Evaluate(),
+ (ScalarNode s1, QuaternionNode v2) => v2.Evaluate() * s1.Evaluate(),
+ _ => throw new NotImplementedException()
+ };
+ case ExpressionNodeType.Divide:
+ return
+ (Children[0] as QuaternionNode).Evaluate() /
+ (Children[1] as QuaternionNode).Evaluate();
+ case ExpressionNodeType.QuaternionFromAxisAngle:
+ return Quaternion.CreateFromAxisAngle((Children[0] as Vector3Node).Evaluate(), (Children[1] as ScalarNode).Evaluate());
+ case ExpressionNodeType.Conditional:
+ return
+ (Children[0] as BooleanNode).Evaluate() ?
+ (Children[1] as QuaternionNode).Evaluate() :
+ (Children[2] as QuaternionNode).Evaluate();
+ case ExpressionNodeType.Swizzle:
+ return new Quaternion(this.EvaluateSubchannel(Subchannels[0]), this.EvaluateSubchannel(Subchannels[1]), this.EvaluateSubchannel(Subchannels[2]), this.EvaluateSubchannel(Subchannels[4]));
+ default:
+ throw new NotImplementedException();
+ }
+ }
}
#pragma warning restore CS0660, CS0661
}
\ No newline at end of file
diff --git a/Microsoft.Toolkit.Uwp.UI.Animations/Expressions/ExpressionNodes/ScalarNode.cs b/Microsoft.Toolkit.Uwp.UI.Animations/Expressions/ExpressionNodes/ScalarNode.cs
index fe3b7408b91..34f07643a56 100644
--- a/Microsoft.Toolkit.Uwp.UI.Animations/Expressions/ExpressionNodes/ScalarNode.cs
+++ b/Microsoft.Toolkit.Uwp.UI.Animations/Expressions/ExpressionNodes/ScalarNode.cs
@@ -2,6 +2,10 @@
// The .NET Foundation licenses this file to you under the MIT license.
// See the LICENSE file in the project root for more information.
+using System;
+using System.Numerics;
+using Windows.UI.Composition;
+
namespace Microsoft.Toolkit.Uwp.UI.Animations.Expressions
{
// Ignore warning: 'ScalarNode' defines operator == or operator != but does not override Object.Equals(object o) && Object.GetHashCode()
@@ -258,6 +262,124 @@ protected internal override string GetValue()
}
private float _value;
+
+ ///
+ /// Evaluates the current value of the expression
+ ///
+ /// The current value of the expression
+ public float Evaluate()
+ {
+ switch (NodeType)
+ {
+ case ExpressionNodeType.ConstantValue:
+ return _value;
+ case ExpressionNodeType.ReferenceProperty:
+ var reference = (Children[0] as ReferenceNode).Reference;
+ return PropertyName switch
+ {
+ nameof(Visual.Opacity) => (reference as Visual).Opacity,
+ nameof(Visual.RotationAngle) => (reference as Visual).RotationAngle,
+ nameof(InsetClip.BottomInset) => (reference as InsetClip).BottomInset,
+ nameof(InsetClip.LeftInset) => (reference as InsetClip).LeftInset,
+ nameof(InsetClip.RightInset) => (reference as InsetClip).RightInset,
+ nameof(InsetClip.TopInset) => (reference as InsetClip).TopInset,
+ _ => GetProperty()
+ };
+
+ float GetProperty()
+ {
+ reference.Properties.TryGetScalar(PropertyName, out var value);
+ return value;
+ }
+
+ case ExpressionNodeType.Negate:
+ return -(Children[0] as ScalarNode).Evaluate();
+ case ExpressionNodeType.Add:
+ return (Children[0] as ScalarNode).Evaluate() + (Children[1] as ScalarNode).Evaluate();
+ case ExpressionNodeType.Subtract:
+ return (Children[0] as ScalarNode).Evaluate() - (Children[1] as ScalarNode).Evaluate();
+ case ExpressionNodeType.Multiply:
+ return (Children[0] as ScalarNode).Evaluate() * (Children[1] as ScalarNode).Evaluate();
+ case ExpressionNodeType.Divide:
+ return (Children[0] as ScalarNode).Evaluate() / (Children[1] as ScalarNode).Evaluate();
+ case ExpressionNodeType.Min:
+ return MathF.Min((Children[0] as ScalarNode).Evaluate(), (Children[1] as ScalarNode).Evaluate());
+ case ExpressionNodeType.Max:
+ return MathF.Max((Children[0] as ScalarNode).Evaluate(), (Children[1] as ScalarNode).Evaluate());
+ case ExpressionNodeType.Absolute:
+ return MathF.Abs((Children[0] as ScalarNode).Evaluate());
+ case ExpressionNodeType.Sin:
+ return MathF.Sin((Children[0] as ScalarNode).Evaluate());
+ case ExpressionNodeType.Cos:
+ return MathF.Cos((Children[0] as ScalarNode).Evaluate());
+ case ExpressionNodeType.Asin:
+ return MathF.Asin((Children[0] as ScalarNode).Evaluate());
+ case ExpressionNodeType.Acos:
+ return MathF.Acos((Children[0] as ScalarNode).Evaluate());
+ case ExpressionNodeType.Atan:
+ return MathF.Atan((Children[0] as ScalarNode).Evaluate());
+ case ExpressionNodeType.Ceil:
+ return MathF.Ceiling((Children[0] as ScalarNode).Evaluate());
+ case ExpressionNodeType.Floor:
+ return MathF.Floor((Children[0] as ScalarNode).Evaluate());
+ case ExpressionNodeType.Ln:
+ return MathF.Log((Children[0] as ScalarNode).Evaluate());
+ case ExpressionNodeType.Log10:
+ return MathF.Log10((Children[0] as ScalarNode).Evaluate());
+ case ExpressionNodeType.Pow:
+ return MathF.Pow((Children[0] as ScalarNode).Evaluate(), (Children[1] as ScalarNode).Evaluate());
+ case ExpressionNodeType.Round:
+ return MathF.Round((Children[0] as ScalarNode).Evaluate());
+ case ExpressionNodeType.Square:
+ return MathF.Pow((Children[0] as ScalarNode).Evaluate(), 2);
+ case ExpressionNodeType.Sqrt:
+ return MathF.Sqrt((Children[0] as ScalarNode).Evaluate());
+ case ExpressionNodeType.ToDegrees:
+ return 180 * (Children[0] as ScalarNode).Evaluate() / MathF.PI;
+ case ExpressionNodeType.ToRadians:
+ return MathF.PI * (Children[0] as ScalarNode).Evaluate() / 180;
+ case ExpressionNodeType.Modulus:
+ return (Children[0] as ScalarNode).Evaluate() % (Children[1] as ScalarNode).Evaluate();
+ case ExpressionNodeType.Conditional:
+ return (Children[0] as BooleanNode).Evaluate() ? (Children[1] as ScalarNode).Evaluate() : (Children[2] as ScalarNode).Evaluate();
+ case ExpressionNodeType.Distance:
+ return Vector2.Distance((Children[0] as Vector2Node).Evaluate(), (Children[1] as Vector2Node).Evaluate());
+ case ExpressionNodeType.Lerp:
+ {
+ var start = (Children[0] as ScalarNode).Evaluate();
+ var end = (Children[1] as ScalarNode).Evaluate();
+ var progress = (Children[2] as ScalarNode).Evaluate();
+ return start + (progress * (end - start));
+ }
+
+ case ExpressionNodeType.Swizzle:
+ return Children[0] switch
+ {
+ ScalarNode n => n.Evaluate(),
+ Vector2Node n => Subchannels[0] switch
+ {
+ "X" => n.Evaluate().X,
+ _ => n.Evaluate().Y,
+ },
+ Vector3Node n => Subchannels[0] switch
+ {
+ "X" => n.Evaluate().X,
+ "Y" => n.Evaluate().Y,
+ _ => n.Evaluate().Z,
+ },
+ Vector4Node n => Subchannels[0] switch
+ {
+ "X" => n.Evaluate().X,
+ "Y" => n.Evaluate().Y,
+ "Z" => n.Evaluate().Z,
+ _ => n.Evaluate().W,
+ },
+ _ => throw new NotImplementedException()
+ };
+ default:
+ throw new NotImplementedException();
+ }
+ }
}
#pragma warning restore CS0660, CS0661
}
\ No newline at end of file
diff --git a/Microsoft.Toolkit.Uwp.UI.Animations/Expressions/ExpressionNodes/Vector2Node.cs b/Microsoft.Toolkit.Uwp.UI.Animations/Expressions/ExpressionNodes/Vector2Node.cs
index 31c9885e70e..91c7513c980 100644
--- a/Microsoft.Toolkit.Uwp.UI.Animations/Expressions/ExpressionNodes/Vector2Node.cs
+++ b/Microsoft.Toolkit.Uwp.UI.Animations/Expressions/ExpressionNodes/Vector2Node.cs
@@ -2,7 +2,9 @@
// The .NET Foundation licenses this file to you under the MIT license.
// See the LICENSE file in the project root for more information.
+using System;
using System.Numerics;
+using Windows.UI.Composition;
namespace Microsoft.Toolkit.Uwp.UI.Animations.Expressions
{
@@ -301,6 +303,68 @@ protected internal override string GetValue()
}
private Vector2 _value;
+
+ ///
+ /// Evaluates the current value of the expression
+ ///
+ /// The current value of the expression
+ public Vector2 Evaluate()
+ {
+ switch (NodeType)
+ {
+ case ExpressionNodeType.ConstantValue:
+ return _value;
+ case ExpressionNodeType.ReferenceProperty:
+ var reference = (Children[0] as ReferenceNode).Reference;
+ return PropertyName switch
+ {
+ nameof(Visual.Size) => (reference as Visual).Size,
+ nameof(Visual.AnchorPoint) => (reference as Visual).AnchorPoint,
+ _ => GetProperty()
+ };
+
+ Vector2 GetProperty()
+ {
+ reference.Properties.TryGetVector2(PropertyName, out var value);
+ return value;
+ }
+
+ case ExpressionNodeType.Conditional:
+ return
+ (Children[0] as BooleanNode).Evaluate() ?
+ (Children[1] as Vector2Node).Evaluate() :
+ (Children[2] as Vector2Node).Evaluate();
+ case ExpressionNodeType.Add:
+ return
+ (Children[0] as Vector2Node).Evaluate() +
+ (Children[1] as Vector2Node).Evaluate();
+ case ExpressionNodeType.Subtract:
+ return
+ (Children[0] as Vector2Node).Evaluate() -
+ (Children[1] as Vector2Node).Evaluate();
+ case ExpressionNodeType.Negate:
+ return
+ -(Children[0] as Vector2Node).Evaluate();
+ case ExpressionNodeType.Multiply:
+ return (Children[0], Children[1]) switch
+ {
+ (Vector2Node v1, Vector2Node v2) => v1.Evaluate() * v2.Evaluate(),
+ (Vector2Node v1, ScalarNode s2) => v1.Evaluate() * s2.Evaluate(),
+ (ScalarNode s1, Vector2Node v2) => s1.Evaluate() * v2.Evaluate(),
+ _ => throw new NotImplementedException()
+ };
+ case ExpressionNodeType.Divide:
+ return
+ (Children[0] as Vector2Node).Evaluate() /
+ (Children[1] as Vector2Node).Evaluate();
+ case ExpressionNodeType.Vector2:
+ return new Vector2((Children[0] as ScalarNode).Evaluate(), (Children[1] as ScalarNode).Evaluate());
+ case ExpressionNodeType.Swizzle:
+ return new Vector2(Children[0].EvaluateSubchannel(Subchannels[0]), Children[0].EvaluateSubchannel(Subchannels[1]));
+ default:
+ throw new NotImplementedException();
+ }
+ }
}
#pragma warning restore CS0660, CS0661
}
\ No newline at end of file
diff --git a/Microsoft.Toolkit.Uwp.UI.Animations/Expressions/ExpressionNodes/Vector3Node.cs b/Microsoft.Toolkit.Uwp.UI.Animations/Expressions/ExpressionNodes/Vector3Node.cs
index 7493428608a..4a89f50991d 100644
--- a/Microsoft.Toolkit.Uwp.UI.Animations/Expressions/ExpressionNodes/Vector3Node.cs
+++ b/Microsoft.Toolkit.Uwp.UI.Animations/Expressions/ExpressionNodes/Vector3Node.cs
@@ -2,7 +2,9 @@
// The .NET Foundation licenses this file to you under the MIT license.
// See the LICENSE file in the project root for more information.
+using System;
using System.Numerics;
+using Windows.UI.Composition;
namespace Microsoft.Toolkit.Uwp.UI.Animations.Expressions
{
@@ -324,6 +326,79 @@ protected internal override string GetValue()
}
private Vector3 _value;
+
+ ///
+ /// Evaluates the current value of the expression
+ ///
+ /// The current value of the expression
+ public Vector3 Evaluate()
+ {
+ switch (NodeType)
+ {
+ case ExpressionNodeType.ConstantValue:
+ return _value;
+ case ExpressionNodeType.ReferenceProperty:
+ var reference = (Children[0] as ReferenceNode).Reference;
+ return PropertyName switch
+ {
+ nameof(Visual.Offset) => (reference as Visual).Offset,
+ nameof(Visual.RotationAxis) => (reference as Visual).RotationAxis,
+ nameof(Visual.CenterPoint) => (reference as Visual).CenterPoint,
+ _ => GetProperty()
+ };
+
+ Vector3 GetProperty()
+ {
+ reference.Properties.TryGetVector3(PropertyName, out var value);
+ return value;
+ }
+
+ case ExpressionNodeType.Conditional:
+ return
+ (Children[0] as BooleanNode).Evaluate() ?
+ (Children[1] as Vector3Node).Evaluate() :
+ (Children[2] as Vector3Node).Evaluate();
+ case ExpressionNodeType.Add:
+ return
+ (Children[0] as Vector3Node).Evaluate() +
+ (Children[1] as Vector3Node).Evaluate();
+ case ExpressionNodeType.Subtract:
+ return
+ (Children[0] as Vector3Node).Evaluate() -
+ (Children[1] as Vector3Node).Evaluate();
+ case ExpressionNodeType.Lerp:
+ {
+ var t = (Children[2] as ScalarNode).Evaluate();
+ return
+ (Children[0] as Vector3Node).Evaluate() * t -
+ (Children[1] as Vector3Node).Evaluate() * (1 - t);
+ }
+ case ExpressionNodeType.Negate:
+ return
+ -(Children[0] as Vector3Node).Evaluate();
+ case ExpressionNodeType.Multiply:
+ return (Children[0], Children[1]) switch
+ {
+ (Vector3Node v1, Vector3Node v2) => v1.Evaluate() * v2.Evaluate(),
+ (Vector3Node v1, ScalarNode s2) => v1.Evaluate() * s2.Evaluate(),
+ (ScalarNode s1, Vector3Node v2) => s1.Evaluate() * v2.Evaluate(),
+ _ => throw new NotImplementedException()
+ };
+ case ExpressionNodeType.Divide:
+ return
+ (Children[0] as Vector3Node).Evaluate() /
+ (Children[1] as Vector3Node).Evaluate();
+ case ExpressionNodeType.Vector3:
+ return new Vector3(
+ (Children[0] as ScalarNode).Evaluate(),
+ (Children[1] as ScalarNode).Evaluate(),
+ (Children[2] as ScalarNode).Evaluate());
+ case ExpressionNodeType.Swizzle:
+ return new Vector3(Children[0].EvaluateSubchannel(Subchannels[0]), Children[0].EvaluateSubchannel(Subchannels[1]), Children[0].EvaluateSubchannel(Subchannels[2]));
+ default:
+ throw new NotImplementedException();
+ }
+ }
}
#pragma warning restore CS0660, CS0661
}
\ No newline at end of file
diff --git a/Microsoft.Toolkit.Uwp.UI.Animations/Expressions/ExpressionNodes/Vector4Node.cs b/Microsoft.Toolkit.Uwp.UI.Animations/Expressions/ExpressionNodes/Vector4Node.cs
index 83b85093088..dadc67f5489 100644
--- a/Microsoft.Toolkit.Uwp.UI.Animations/Expressions/ExpressionNodes/Vector4Node.cs
+++ b/Microsoft.Toolkit.Uwp.UI.Animations/Expressions/ExpressionNodes/Vector4Node.cs
@@ -2,7 +2,9 @@
// The .NET Foundation licenses this file to you under the MIT license.
// See the LICENSE file in the project root for more information.
+using System;
using System.Numerics;
+using Windows.UI.Composition;
namespace Microsoft.Toolkit.Uwp.UI.Animations.Expressions
{
@@ -347,6 +349,70 @@ protected internal override string GetValue()
}
private Vector4 _value;
+
+ ///
+ /// Evaluates the current value of the expression
+ ///
+ /// The current value of the expression
+ public Vector4 Evaluate()
+ {
+ switch (NodeType)
+ {
+ case ExpressionNodeType.ConstantParameter:
+ throw new NotImplementedException();
+ case ExpressionNodeType.ReferenceProperty:
+ var reference = (Children[0] as ReferenceNode).Reference;
+ return PropertyName switch
+ {
+ _ => GetProperty()
+ };
+
+ Vector4 GetProperty()
+ {
+ reference.Properties.TryGetVector4(PropertyName, out var value);
+ return value;
+ }
+
+ case ExpressionNodeType.Conditional:
+ return
+ (Children[0] as BooleanNode).Evaluate() ?
+ (Children[1] as Vector4Node).Evaluate() :
+ (Children[2] as Vector4Node).Evaluate();
+ case ExpressionNodeType.Add:
+ return
+ (Children[0] as Vector4Node).Evaluate() +
+ (Children[1] as Vector4Node).Evaluate();
+ case ExpressionNodeType.Subtract:
+ return
+ (Children[0] as Vector4Node).Evaluate() -
+ (Children[1] as Vector4Node).Evaluate();
+ case ExpressionNodeType.Negate:
+ return
+ -(Children[0] as Vector4Node).Evaluate();
+ case ExpressionNodeType.Multiply:
+ return (Children[0], Children[1]) switch
+ {
+ (Vector4Node v1, Vector4Node v2) => v1.Evaluate() * v2.Evaluate(),
+ (Vector4Node v1, ScalarNode s2) => v1.Evaluate() * s2.Evaluate(),
+ (ScalarNode s1, Vector4Node v2) => s1.Evaluate() * v2.Evaluate(),
+ _ => throw new NotImplementedException()
+ };
+ case ExpressionNodeType.Divide:
+ return
+ (Children[0] as Vector4Node).Evaluate() /
+ (Children[1] as Vector4Node).Evaluate();
+ case ExpressionNodeType.Vector3:
+ return new Vector4(
+ (Children[0] as ScalarNode).Evaluate(),
+ (Children[1] as ScalarNode).Evaluate(),
+ (Children[2] as ScalarNode).Evaluate(),
+ (Children[2] as ScalarNode).Evaluate());
+ case ExpressionNodeType.Swizzle:
+ return new Vector4(Children[0].EvaluateSubchannel(Subchannels[0]), Children[0].EvaluateSubchannel(Subchannels[1]), Children[0].EvaluateSubchannel(Subchannels[2]), Children[0].EvaluateSubchannel(Subchannels[3]));
+ default:
+ throw new NotImplementedException();
+ }
+ }
}
#pragma warning restore CS0660, CS0661
}
\ No newline at end of file
diff --git a/UnitTests/UnitTests.UWP/UI/Animations/Test_ExpressionNode.cs b/UnitTests/UnitTests.UWP/UI/Animations/Test_ExpressionNode.cs
new file mode 100644
index 00000000000..c61d8bafc99
--- /dev/null
+++ b/UnitTests/UnitTests.UWP/UI/Animations/Test_ExpressionNode.cs
@@ -0,0 +1,63 @@
+// Licensed to the .NET Foundation under one or more agreements.
+// The .NET Foundation licenses this file to you under the MIT license.
+// See the LICENSE file in the project root for more information.
+
+using System.Threading.Tasks;
+using Microsoft.VisualStudio.TestTools.UnitTesting;
+using Microsoft.Toolkit.Uwp;
+using Windows.UI.Xaml.Controls;
+using Microsoft.Toolkit.Uwp.UI.Animations;
+using System.Numerics;
+using Microsoft.Toolkit.Uwp.UI;
+using System;
+using Windows.UI.Xaml.Media;
+using Windows.UI.Xaml.Hosting;
+using Microsoft.Toolkit.Uwp.UI.Animations.Expressions;
+
+namespace UnitTests.UWP.UI.Animations
+{
+ [TestClass]
+ [TestCategory("Test_ExpressionNode")]
+ public class Test_ExpressionNode : VisualUITestBase
+ {
+ [TestMethod]
+ public async Task EvaluateExpressionNode()
+ {
+ await App.DispatcherQueue.EnqueueAsync(async () =>
+ {
+ Grid grid = new();
+ await SetTestContentAsync(grid);
+
+ var visual = ElementCompositionPreview.GetElementVisual(grid);
+
+ // Test basic vector algebra
+ visual.Offset = Vector3.UnitX;
+ var vector3AlgebraNode = (-visual.GetReference().Offset
+ + Vector3.UnitY
+ - Vector3.UnitZ) * 5;
+
+ Assert.AreEqual(new Vector3(-5, 5, -5), vector3AlgebraNode.Evaluate());
+
+ // Test swizzle operation
+ visual.CenterPoint = Vector3.UnitY;
+ var swizzleNode = visual.GetReference().CenterPoint.GetSubchannels(
+ Vector3Node.Subchannel.Y,
+ Vector3Node.Subchannel.X,
+ Vector3Node.Subchannel.Y);
+
+ Assert.AreEqual(new Vector3(1, 0, 1), swizzleNode.Evaluate());
+
+ // Test retrieving properties from set
+ var propertySet = visual.Compositor.CreatePropertySet();
+ var propertyName = "test";
+ var propertyNode = propertySet.GetReference().GetVector4Property(propertyName);
+
+ propertySet.InsertVector4(propertyName, Vector4.UnitW);
+ Assert.AreEqual(Vector4.UnitW, propertyNode.Evaluate());
+
+ propertySet.InsertVector4(propertyName, Vector4.UnitX);
+ Assert.AreEqual(Vector4.UnitX, propertyNode.Evaluate());
+ });
+ }
+ }
+}
\ No newline at end of file
diff --git a/UnitTests/UnitTests.UWP/UnitTests.UWP.csproj b/UnitTests/UnitTests.UWP/UnitTests.UWP.csproj
index d50b438032e..29f55845ee9 100644
--- a/UnitTests/UnitTests.UWP/UnitTests.UWP.csproj
+++ b/UnitTests/UnitTests.UWP/UnitTests.UWP.csproj
@@ -231,6 +231,7 @@
+