flabbet 1 anno fa
parent
commit
85205f812b

+ 2 - 1
src/PixiEditor.ChangeableDocument/Changeables/Graph/Nodes/EllipseNode.cs

@@ -27,7 +27,8 @@ public class EllipseNode : Node
 
     public EllipseNode()
     {
-        Radius = CreateInput<VecI>("Radius", "RADIUS", new VecI(32, 32));
+        Radius = CreateInput<VecI>("Radius", "RADIUS", new VecI(32, 32)).WithRules(
+            v => v.Min(VecI.One));
         StrokeColor = CreateInput<Color>("StrokeColor", "STROKE_COLOR", new Color(0, 0, 0, 255));
         FillColor = CreateInput<Color>("FillColor", "FILL_COLOR", new Color(0, 0, 0, 255));
         StrokeWidth = CreateInput<int>("StrokeWidth", "STROKE_WIDTH", 1);

+ 1 - 1
src/PixiEditor.ChangeableDocument/Changeables/Graph/Nodes/EmptyImageNode.cs

@@ -21,7 +21,7 @@ public class CreateImageNode : Node
     public CreateImageNode()
     {
         Output = CreateOutput<Texture>(nameof(Output), "EMPTY_IMAGE", null);
-        Size = CreateInput(nameof(Size), "SIZE", new VecI(32, 32));
+        Size = CreateInput(nameof(Size), "SIZE", new VecI(32, 32)).WithRules(v => v.Min(VecI.One));
         Fill = CreateInput(nameof(Fill), "FILL", new Color(0, 0, 0, 255));
     }
 

+ 1 - 5
src/PixiEditor.ChangeableDocument/Changeables/Graph/Nodes/NoiseNode.cs

@@ -41,11 +41,7 @@ public class NoiseNode : Node
         Noise = CreateOutput<Texture>(nameof(Noise), "NOISE", null);
         NoiseType = CreateInput(nameof(NoiseType), "NOISE_TYPE", Nodes.NoiseType.FractalPerlin);
         Size = CreateInput(nameof(Size), "SIZE", new VecI(64, 64))
-            .WithRules(v =>
-                v.Min(
-                    VecI.One,
-                    vector => new VecI(Math.Max(1, vector.X), Math.Max(1, vector.Y))
-                )
+            .WithRules(v => v.Min(VecI.One)
             );
 
         Offset = CreateInput(nameof(Offset), "OFFSET", new VecD(0d, 0d));

+ 2 - 1
src/PixiEditor.ChangeableDocument/Changeables/Graph/Nodes/Points/DistributePointsNode.cs

@@ -18,7 +18,8 @@ public class DistributePointsNode : Node
     {
         Points = CreateOutput(nameof(Points), "POINTS", PointList.Empty);
 
-        MaxPointCount = CreateInput("MaxPointCount", "MAX_POINTS", 10);
+        MaxPointCount = CreateInput("MaxPointCount", "MAX_POINTS", 10).
+            WithRules(v => v.Min(1));
         Seed = CreateInput("Seed", "SEED", 0);
     }
 

+ 10 - 0
src/PixiEditor.ChangeableDocument/Changeables/Graph/PropertyValidator.cs

@@ -8,6 +8,16 @@ public class PropertyValidator
 {
     public List<ValidateProperty> Rules { get; } = new();
 
+    public PropertyValidator Min(VecI min)
+    {
+       return Min(min, v => new VecI(Math.Max(v.X, min.X), Math.Max(v.Y, min.Y))); 
+    }
+    
+    public PropertyValidator Min(VecD min)
+    {
+        return Min(min, v => new VecD(Math.Max(v.X, min.X), Math.Max(v.Y, min.Y))); 
+    }
+
     public PropertyValidator Min<T>(T min, Func<T, T>? adjust = null) where T : IComparable<T>
     {
         Rules.Add((value) =>

+ 46 - 3
src/PixiEditor.Numerics/VecD.cs

@@ -1,6 +1,6 @@
 namespace PixiEditor.Numerics;
 
-public struct VecD : IEquatable<VecD>
+public struct VecD : IEquatable<VecD>, IComparable<VecD>
 {
     public double X { set; get; }
     public double Y { set; get; }
@@ -19,27 +19,33 @@ public struct VecD : IEquatable<VecD>
         X = x;
         Y = y;
     }
+
     public VecD(double bothAxesValue)
     {
         X = bothAxesValue;
         Y = bothAxesValue;
     }
+
     public static VecD FromAngleAndLength(double angle, double length)
     {
         return new VecD(Math.Cos(angle) * length, Math.Sin(angle) * length);
     }
+
     public VecD Round()
     {
         return new(Math.Round(X), Math.Round(Y));
     }
+
     public VecD Ceiling()
     {
         return new(Math.Ceiling(X), Math.Ceiling(Y));
     }
+
     public VecD Floor()
     {
         return new(Math.Floor(X), Math.Floor(Y));
     }
+
     /// <summary>
     ///     Rotates the vector by the specified angle in radians
     /// </summary>
@@ -52,10 +58,12 @@ public struct VecD : IEquatable<VecD>
         result.Y = X * Math.Sin(angleRad) + Y * Math.Cos(angleRad);
         return result;
     }
+
     public VecD Rotate(double angleRad, VecD around)
     {
         return (this - around).Rotate(angleRad) + around;
     }
+
     public double DistanceToLineSegment(VecD pos1, VecD pos2)
     {
         VecD segment = pos2 - pos1;
@@ -65,6 +73,7 @@ public struct VecD : IEquatable<VecD>
             return (this - pos2).Length;
         return DistanceToLine(pos1, pos2);
     }
+
     public double DistanceToLine(VecD pos1, VecD pos2)
     {
         double a = (pos1 - pos2).Length;
@@ -76,12 +85,14 @@ public struct VecD : IEquatable<VecD>
 
         return triangleArea / a * 2;
     }
+
     public VecD ProjectOntoLine(VecD pos1, VecD pos2)
     {
         VecD line = (pos2 - pos1).Normalize();
         VecD point = this - pos1;
         return (line * point) * line + pos1;
     }
+
     /// <summary>
     /// Reflects the vector across a vertical line with the specified position
     /// </summary>
@@ -89,6 +100,7 @@ public struct VecD : IEquatable<VecD>
     {
         return new(2 * lineX - X, Y);
     }
+
     /// <summary>
     /// Reflects the vector along a horizontal line with the specified position
     /// </summary>
@@ -96,11 +108,13 @@ public struct VecD : IEquatable<VecD>
     {
         return new(X, 2 * lineY - Y);
     }
+
     public VecD ReflectAcrossLine(VecD pos1, VecD pos2)
     {
         var onLine = ProjectOntoLine(pos1, pos2);
         return onLine - (this - onLine);
     }
+
     public double AngleTo(VecD other)
     {
         return Math.Acos((this * other) / Length / other.Length);
@@ -114,22 +128,27 @@ public struct VecD : IEquatable<VecD>
         var rot = other.Rotate(-Angle);
         return rot.Angle;
     }
+
     public VecD Lerp(VecD other, double factor)
     {
         return (other - this) * factor + this;
     }
+
     public VecD Normalize()
     {
         return new VecD(X / Length, Y / Length);
     }
+
     public VecD Abs()
     {
         return new VecD(Math.Abs(X), Math.Abs(Y));
     }
+
     public VecD Signs()
     {
         return new VecD(X >= 0 ? 1 : -1, Y >= 0 ? 1 : -1);
     }
+
     /// <summary>
     /// Returns the signed magnitude (Z coordinate) of the vector resulting from the cross product
     /// </summary>
@@ -139,51 +158,62 @@ public struct VecD : IEquatable<VecD>
     }
 
     public double Dot(VecD other) => (X * other.X) + (Y * other.Y);
-    
+
     public VecD Multiply(VecD other)
     {
         return new VecD(X * other.X, Y * other.Y);
     }
+
     public VecD Divide(VecD other)
     {
         return new VecD(X / other.X, Y / other.Y);
     }
+
     public static VecD operator +(VecD a, VecD b)
     {
         return new VecD(a.X + b.X, a.Y + b.Y);
     }
+
     public static VecD operator -(VecD a, VecD b)
     {
         return new VecD(a.X - b.X, a.Y - b.Y);
     }
+
     public static VecD operator -(VecD a)
     {
         return new VecD(-a.X, -a.Y);
     }
+
     public static VecD operator *(double b, VecD a)
     {
         return new VecD(a.X * b, a.Y * b);
     }
+
     public static double operator *(VecD a, VecD b)
     {
         return a.X * b.X + a.Y * b.Y;
     }
+
     public static VecD operator *(VecD a, double b)
     {
         return new VecD(a.X * b, a.Y * b);
     }
+
     public static VecD operator /(VecD a, double b)
     {
         return new VecD(a.X / b, a.Y / b);
     }
+
     public static VecD operator %(VecD a, double b)
     {
         return new(a.X % b, a.Y % b);
     }
+
     public static bool operator ==(VecD a, VecD b)
     {
         return a.X == b.X && a.Y == b.Y;
     }
+
     public static bool operator !=(VecD a, VecD b)
     {
         return !(a.X == b.X && a.Y == b.Y);
@@ -193,16 +223,18 @@ public struct VecD : IEquatable<VecD>
     {
         return new VecI((int)vec.X, (int)vec.Y);
     }
-    
+
     public static implicit operator VecD((double, double) tuple)
     {
         return new VecD(tuple.Item1, tuple.Item2);
     }
+
     public void Deconstruct(out double x, out double y)
     {
         x = X;
         y = Y;
     }
+
     public bool IsNaNOrInfinity()
     {
         return double.IsNaN(X) || double.IsNaN(Y) || double.IsInfinity(X) || double.IsInfinity(Y);
@@ -213,6 +245,17 @@ public struct VecD : IEquatable<VecD>
         return $"({X}; {Y})";
     }
 
+    public int CompareTo(VecD other)
+    {
+        int xComparison = X.CompareTo(other.X);
+        int yComparison = Y.CompareTo(other.Y);
+        if (xComparison == 0 && yComparison == 0)
+            return 0;
+
+        bool anyNegative = xComparison < 0 || yComparison < 0;
+        return anyNegative ? -1 : 1;
+    }
+
     public override bool Equals(object? obj)
     {
         var item = obj as VecD?;

+ 6 - 1
src/PixiEditor.Numerics/VecI.cs

@@ -194,7 +194,12 @@ public struct VecI : IEquatable<VecI>, IComparable<VecI>
     public int CompareTo(VecI other)
     {
         int xComparison = X.CompareTo(other.X);
-        return xComparison * Y.CompareTo(other.Y); 
+        int yComparison = Y.CompareTo(other.Y);
+        if (xComparison == 0 && yComparison == 0)
+            return 0;
+        
+        bool anyNegative = xComparison < 0 || yComparison < 0;
+        return anyNegative ? -1 : 1;
     }
 
     public override bool Equals(object? obj)