diff --git a/src/Artemis.Core/Utilities/Numeric.cs b/src/Artemis.Core/Utilities/Numeric.cs
new file mode 100644
index 000000000..86bec89b8
--- /dev/null
+++ b/src/Artemis.Core/Utilities/Numeric.cs
@@ -0,0 +1,289 @@
+using System;
+using System.Collections.Generic;
+using System.Globalization;
+
+namespace Artemis.Core
+{
+ ///
+ /// Represents a number, either decimal or not, with arbitrary precision.
+ ///
+ /// Note: This struct is intended to be used by the node system when implementing your own .
+ /// Usage outside that context is not recommended due to conversion overhead.
+ ///
+ ///
+ public readonly struct Numeric : IComparable
+ {
+ private readonly float _value;
+
+ #region Constructors
+
+ ///
+ /// Creates a new instance of from a
+ ///
+ public Numeric(float value)
+ {
+ _value = value;
+ }
+
+ ///
+ /// Creates a new instance of from an
+ ///
+ public Numeric(int value)
+ {
+ _value = value;
+ }
+
+ ///
+ /// Creates a new instance of from a
+ ///
+ public Numeric(double value)
+ {
+ _value = (float) value;
+ }
+
+ ///
+ /// Creates a new instance of from a
+ ///
+ public Numeric(byte value)
+ {
+ _value = value;
+ }
+
+ ///
+ /// Creates a new instance of from an
+ ///
+ public Numeric(object? pathValue)
+ {
+ _value = pathValue switch
+ {
+ float value => value,
+ int value => value,
+ double value => (float) value,
+ byte value => value,
+ _ => ParseFloatOrDefault(pathValue?.ToString())
+ };
+ }
+
+ private static float ParseFloatOrDefault(string? pathValue)
+ {
+ float.TryParse(pathValue, NumberStyles.Any, NumberFormatInfo.InvariantInfo, out float parsedFloat);
+ return parsedFloat;
+ }
+
+ #endregion
+
+ #region Relational members
+
+ ///
+ public int CompareTo(Numeric other)
+ {
+ return _value.CompareTo(other._value);
+ }
+
+ #endregion
+
+ #region Equality members
+
+ ///
+ /// Indicates whether this instance and a specified numeric are equal
+ ///
+ /// The numeric to compare with the current instance
+ ///
+ /// if this numeric and the provided are equal; otherwise,
+ /// .
+ ///
+ public bool Equals(Numeric other)
+ {
+ return _value.Equals(other._value);
+ }
+
+ ///
+ public override bool Equals(object? obj)
+ {
+ return obj is Numeric other && Equals(other);
+ }
+
+ ///
+ public override int GetHashCode()
+ {
+ return _value.GetHashCode();
+ }
+
+ #endregion
+
+ #region Formatting members
+
+ ///
+ public override string ToString()
+ {
+ return _value.ToString(CultureInfo.InvariantCulture);
+ }
+
+ #endregion
+
+ #region Operators
+
+#pragma warning disable 1591
+
+ public static implicit operator float(Numeric p)
+ {
+ return p._value;
+ }
+
+ public static implicit operator int(Numeric p)
+ {
+ return (int) MathF.Round(p._value, MidpointRounding.AwayFromZero);
+ }
+
+ public static implicit operator double(Numeric p)
+ {
+ return p._value;
+ }
+
+ public static implicit operator byte(Numeric p)
+ {
+ return (byte) Math.Clamp(p._value, 0, 255);
+ }
+
+ public static bool operator >(Numeric a, Numeric b)
+ {
+ return a._value > b._value;
+ }
+
+ public static bool operator <(Numeric a, Numeric b)
+ {
+ return a._value < b._value;
+ }
+
+ public static bool operator ==(Numeric left, Numeric right)
+ {
+ return left.Equals(right);
+ }
+
+ public static bool operator !=(Numeric left, Numeric right)
+ {
+ return !(left == right);
+ }
+
+ public static bool operator <=(Numeric left, Numeric right)
+ {
+ return left.CompareTo(right) <= 0;
+ }
+
+ public static bool operator >=(Numeric left, Numeric right)
+ {
+ return left.CompareTo(right) >= 0;
+ }
+
+ public static Numeric operator +(Numeric a)
+ {
+ return new Numeric(+a._value);
+ }
+
+ public static Numeric operator -(Numeric a)
+ {
+ return new Numeric(-a._value);
+ }
+
+ public static Numeric operator ++(Numeric a)
+ {
+ return new Numeric(a._value + 1);
+ }
+
+ public static Numeric operator --(Numeric a)
+ {
+ return new Numeric(a._value - 1);
+ }
+
+ public static Numeric operator +(Numeric a, Numeric b)
+ {
+ return new Numeric(a._value + b._value);
+ }
+
+ public static Numeric operator -(Numeric a, Numeric b)
+ {
+ return new Numeric(a._value - b._value);
+ }
+
+ public static Numeric operator *(Numeric a, Numeric b)
+ {
+ return new Numeric(a._value * b._value);
+ }
+
+ public static Numeric operator %(Numeric a, Numeric b)
+ {
+ return new Numeric(a._value % b._value);
+ }
+
+ public static Numeric operator /(Numeric a, Numeric b)
+ {
+ if (b._value == 0)
+ throw new DivideByZeroException();
+ return new Numeric(a._value / b._value);
+ }
+
+#pragma warning restore 1591
+
+ #endregion
+
+ ///
+ /// Converts the string representation of a number into a numeric. A return value indicates whether the conversion
+ /// succeeded or failed.
+ ///
+ /// A string representing a number to convert.
+ ///
+ /// When this method returns, contains numeric equivalent to the numeric value or symbol contained in
+ /// , if the conversion succeeded, or zero if the conversion failed.
+ ///
+ /// if s was converted successfully; otherwise, .
+ public static bool TryParse(string? s, out Numeric result)
+ {
+ bool parsed = float.TryParse(s, NumberStyles.Any, NumberFormatInfo.InvariantInfo, out float parsedFloat);
+ if (!parsed)
+ {
+ result = new Numeric(0);
+ return false;
+ }
+
+ result = new Numeric(parsedFloat);
+ return true;
+ }
+
+ ///
+ /// Returns a boolean indicating whether the provided type can be used as a .
+ ///
+ public static bool IsTypeCompatible(Type type)
+ {
+ return type == typeof(Numeric) ||
+ type == typeof(float) ||
+ type == typeof(double) ||
+ type == typeof(int) ||
+ type == typeof(byte);
+ }
+ }
+
+ ///
+ /// Provides alternatives for common number-type extensions
+ ///
+ public static class NumericExtensions
+ {
+ #region Extensions
+
+ ///
+ /// Sums the numerics in the provided collection
+ ///
+ /// The sum of all numerics in the collection
+ ///
+ public static Numeric Sum(this IEnumerable source)
+ {
+ if (source == null) throw new ArgumentNullException(nameof(source));
+
+ float sum = 0;
+ foreach (float v in source) sum += v;
+
+ return new Numeric(sum);
+ }
+
+ #endregion
+ }
+}
\ No newline at end of file
diff --git a/src/Artemis.UI.Shared/Converters/StringToNumericConverter.cs b/src/Artemis.UI.Shared/Converters/StringToNumericConverter.cs
new file mode 100644
index 000000000..ced2709ae
--- /dev/null
+++ b/src/Artemis.UI.Shared/Converters/StringToNumericConverter.cs
@@ -0,0 +1,27 @@
+using System;
+using System.Globalization;
+using System.Windows.Data;
+using Artemis.Core;
+
+namespace Artemis.UI.Shared
+{
+ ///
+ /// Converts into .
+ ///
+ [ValueConversion(typeof(string), typeof(Numeric))]
+ public class StringToNumericConverter : IValueConverter
+ {
+ ///
+ public object? Convert(object? value, Type targetType, object parameter, CultureInfo culture)
+ {
+ return value?.ToString();
+ }
+
+ ///
+ public object ConvertBack(object? value, Type targetType, object parameter, CultureInfo culture)
+ {
+ Numeric.TryParse(value as string, out Numeric result);
+ return result;
+ }
+ }
+}
\ No newline at end of file
diff --git a/src/Artemis.UI/Services/RegistrationService.cs b/src/Artemis.UI/Services/RegistrationService.cs
index d6a9f6bd3..68d4f2fc5 100644
--- a/src/Artemis.UI/Services/RegistrationService.cs
+++ b/src/Artemis.UI/Services/RegistrationService.cs
@@ -132,7 +132,7 @@ namespace Artemis.UI.Services
_nodeService.RegisterTypeColor(Constants.CorePlugin, typeof(IList), new SKColor(0xFFED3E61));
_nodeService.RegisterTypeColor(Constants.CorePlugin, typeof(Enum), new SKColor(0xFF1E90FF));
- foreach (Type nodeType in typeof(SumIntegersNode).Assembly.GetTypes().Where(t => typeof(INode).IsAssignableFrom(t) && t.IsPublic && !t.IsAbstract && !t.IsInterface))
+ foreach (Type nodeType in typeof(SumNumericsNode).Assembly.GetTypes().Where(t => typeof(INode).IsAssignableFrom(t) && t.IsPublic && !t.IsAbstract && !t.IsInterface))
_nodeService.RegisterNodeType(Constants.CorePlugin, nodeType);
}
diff --git a/src/Artemis.VisualScripting/Artemis.VisualScripting.csproj b/src/Artemis.VisualScripting/Artemis.VisualScripting.csproj
index 6fe961c9a..47a179dcc 100644
--- a/src/Artemis.VisualScripting/Artemis.VisualScripting.csproj
+++ b/src/Artemis.VisualScripting/Artemis.VisualScripting.csproj
@@ -65,7 +65,7 @@
$(DefaultXamlRuntime)
-
+
$(DefaultXamlRuntime)
diff --git a/src/Artemis.VisualScripting/Nodes/BoolOperations.cs b/src/Artemis.VisualScripting/Nodes/BoolOperations.cs
index 5e44018ea..27b862989 100644
--- a/src/Artemis.VisualScripting/Nodes/BoolOperations.cs
+++ b/src/Artemis.VisualScripting/Nodes/BoolOperations.cs
@@ -2,6 +2,7 @@
using System.Collections;
using System.Linq;
using Artemis.Core;
+using Artemis.VisualScripting.Nodes.CustomViewModels;
namespace Artemis.VisualScripting.Nodes
{
@@ -33,6 +34,12 @@ namespace Artemis.VisualScripting.Nodes
public override void Evaluate()
{
+ if (Input1.Value is Numeric numeric1 && Input2.Value is Numeric numeric2)
+ {
+ Result.Value = numeric1 > numeric2;
+ return;
+ }
+
if (Input2.Value != null && Input1.Value != null && Input1.Value.IsNumber() && Input2.Value.IsNumber())
{
Result.Value = Convert.ToSingle(Input1.Value) > Convert.ToSingle(Input2.Value);
@@ -80,6 +87,12 @@ namespace Artemis.VisualScripting.Nodes
public override void Evaluate()
{
+ if (Input1.Value is Numeric numeric1 && Input2.Value is Numeric numeric2)
+ {
+ Result.Value = numeric1 < numeric2;
+ return;
+ }
+
if (Input2.Value != null && Input1.Value != null && Input1.Value.IsNumber() && Input2.Value.IsNumber())
{
Result.Value = Convert.ToSingle(Input1.Value) < Convert.ToSingle(Input2.Value);
@@ -263,4 +276,27 @@ namespace Artemis.VisualScripting.Nodes
#endregion
}
+
+ [Node("Enum Equals", "Determines the equality between an input and a selected enum value", "Operators", InputType = typeof(Enum), OutputType = typeof(bool))]
+ public class EnumEqualsNode : Node
+ {
+ public EnumEqualsNode() : base("Enum Equals", "Determines the equality between an input and a selected enum value")
+ {
+ InputPin = CreateInputPin();
+ OutputPin = CreateOutputPin();
+ }
+
+ public InputPin InputPin { get; }
+ public OutputPin OutputPin { get; }
+
+ #region Overrides of Node
+
+ ///
+ public override void Evaluate()
+ {
+ OutputPin.Value = InputPin.Value != null && InputPin.Value.Equals(Storage);
+ }
+
+ #endregion
+ }
}
\ No newline at end of file
diff --git a/src/Artemis.VisualScripting/Nodes/Color/HslSKColorNode.cs b/src/Artemis.VisualScripting/Nodes/Color/HslSKColorNode.cs
index 724053db7..a4478ad73 100644
--- a/src/Artemis.VisualScripting/Nodes/Color/HslSKColorNode.cs
+++ b/src/Artemis.VisualScripting/Nodes/Color/HslSKColorNode.cs
@@ -3,20 +3,20 @@ using SkiaSharp;
namespace Artemis.VisualScripting.Nodes.Color
{
- [Node("HSL Color", "Creates a color from hue, saturation and lightness values", "Color", InputType = typeof(float), OutputType = typeof(SKColor))]
+ [Node("HSL Color", "Creates a color from hue, saturation and lightness values", "Color", InputType = typeof(Numeric), OutputType = typeof(SKColor))]
public class HslSKColorNode : Node
{
public HslSKColorNode() : base("HSL Color", "Creates a color from hue, saturation and lightness values")
{
- H = CreateInputPin("H");
- S = CreateInputPin("S");
- L = CreateInputPin("L");
+ H = CreateInputPin("H");
+ S = CreateInputPin("S");
+ L = CreateInputPin("L");
Output = CreateOutputPin();
}
- public InputPin H { get; set; }
- public InputPin S { get; set; }
- public InputPin L { get; set; }
+ public InputPin H { get; set; }
+ public InputPin S { get; set; }
+ public InputPin L { get; set; }
public OutputPin Output { get; }
#region Overrides of Node
diff --git a/src/Artemis.VisualScripting/Nodes/ConvertNodes.cs b/src/Artemis.VisualScripting/Nodes/ConvertNodes.cs
index bf396f1db..eafe52cb9 100644
--- a/src/Artemis.VisualScripting/Nodes/ConvertNodes.cs
+++ b/src/Artemis.VisualScripting/Nodes/ConvertNodes.cs
@@ -34,24 +34,24 @@ namespace Artemis.VisualScripting.Nodes
#endregion
}
- [Node("To Integer", "Converts the input to an integer.", "Conversion", InputType = typeof(object), OutputType = typeof(int))]
- public class ConvertToIntegerNode : Node
+ [Node("To Numeric", "Converts the input to a numeric.", "Conversion", InputType = typeof(object), OutputType = typeof(Numeric))]
+ public class ConvertToNumericNode : Node
{
#region Properties & Fields
public InputPin