Browse Source

Scale from center improvements

flabbet 8 months ago
parent
commit
9b23b528ad

+ 22 - 0
src/ChunkyImageLib/DataHolders/ShapeCorners.cs

@@ -196,6 +196,28 @@ public struct ShapeCorners
         };
         };
     }
     }
 
 
+    public ShapeCorners AsScaled(float scaleX, float scaleY)
+    {
+        VecD center = RectCenter;
+        VecD topLeftDelta = TopLeft - center;
+        VecD topRightDelta = TopRight - center;
+        VecD bottomLeftDelta = BottomLeft - center;
+        VecD bottomRightDelta = BottomRight - center;
+
+        topLeftDelta = new VecD(topLeftDelta.X * scaleX, topLeftDelta.Y * scaleY);
+        topRightDelta = new VecD(topRightDelta.X * scaleX, topRightDelta.Y * scaleY);
+        bottomLeftDelta = new VecD(bottomLeftDelta.X * scaleX, bottomLeftDelta.Y * scaleY);
+        bottomRightDelta = new VecD(bottomRightDelta.X * scaleX, bottomRightDelta.Y * scaleY);
+
+        return new ShapeCorners()
+        {
+            TopLeft = center + topLeftDelta,
+            TopRight = center + topRightDelta,
+            BottomLeft = center + bottomLeftDelta,
+            BottomRight = center + bottomRightDelta
+        };
+    }
+
     public static bool operator !=(ShapeCorners left, ShapeCorners right) => !(left == right);
     public static bool operator !=(ShapeCorners left, ShapeCorners right) => !(left == right);
 
 
     public static bool operator ==(ShapeCorners left, ShapeCorners right)
     public static bool operator ==(ShapeCorners left, ShapeCorners right)

+ 37 - 22
src/PixiEditor/Views/Overlays/TransformOverlay/TransformUpdateHelper.cs

@@ -72,6 +72,11 @@ internal static class TransformUpdateHelper
             if (double.IsNaN(angle))
             if (double.IsNaN(angle))
                 angle = 0;
                 angle = 0;
 
 
+            if (scaleFromCenter)
+            {
+                return ScaleCornersFromCenter(corners, targetCorner, desiredPos, angle);
+            }
+
             // find positions of neighboring corners relative to the opposite corner, while also undoing the transform rotation
             // find positions of neighboring corners relative to the opposite corner, while also undoing the transform rotation
             VecD targetTrans = (targetPos - oppositePos).Rotate(-angle);
             VecD targetTrans = (targetPos - oppositePos).Rotate(-angle);
             VecD leftNeighTrans = (leftNeighborPos - oppositePos).Rotate(-angle);
             VecD leftNeighTrans = (leftNeighborPos - oppositePos).Rotate(-angle);
@@ -99,24 +104,6 @@ internal static class TransformUpdateHelper
                 rightNeighDelta = newRightPos.Value - rightNeighTrans;
                 rightNeighDelta = newRightPos.Value - rightNeighTrans;
             }
             }
 
 
-            VecD oppositeDelta = VecD.Zero;
-            if (scaleFromCenter)
-            {
-                oppositeDelta = -delta;
-                bool swapped = leftNeighbor is Anchor.TopLeft or Anchor.BottomRight;
-
-                if (swapped)
-                {
-                    leftNeighDelta += new VecD(0, oppositeDelta.Y);
-                    rightNeighDelta += new VecD(oppositeDelta.X, 0);
-                }
-                else
-                {
-                    leftNeighDelta += new VecD(oppositeDelta.X, 0);
-                    rightNeighDelta += new VecD(0, oppositeDelta.Y);
-                }
-            }
-
             // handle cases where the transform overlay is squished into a line or a single point
             // handle cases where the transform overlay is squished into a line or a single point
             bool squishedWithLeft = leftNeighTrans.TaxicabLength < epsilon;
             bool squishedWithLeft = leftNeighTrans.TaxicabLength < epsilon;
             bool squishedWithRight = rightNeighTrans.TaxicabLength < epsilon;
             bool squishedWithRight = rightNeighTrans.TaxicabLength < epsilon;
@@ -141,8 +128,6 @@ internal static class TransformUpdateHelper
                 (leftNeighTrans + leftNeighDelta).Rotate(angle) + oppositePos);
                 (leftNeighTrans + leftNeighDelta).Rotate(angle) + oppositePos);
             corners = TransformHelper.UpdateCorner(corners, rightNeighbor,
             corners = TransformHelper.UpdateCorner(corners, rightNeighbor,
                 (rightNeighTrans + rightNeighDelta).Rotate(angle) + oppositePos);
                 (rightNeighTrans + rightNeighDelta).Rotate(angle) + oppositePos);
-            corners = TransformHelper.UpdateCorner(corners, opposite,
-                (oppositeDelta).Rotate(angle) + oppositePos);
 
 
             if (!corners.IsLegal)
             if (!corners.IsLegal)
                 return null;
                 return null;
@@ -160,6 +145,36 @@ internal static class TransformUpdateHelper
         throw new ArgumentException($"Freedom degree {freedom} is not supported");
         throw new ArgumentException($"Freedom degree {freedom} is not supported");
     }
     }
 
 
+    private static ShapeCorners? ScaleCornersFromCenter(ShapeCorners corners, Anchor targetCorner, VecD desiredPos, 
+        double angle)
+    {
+        // un rotate to properly calculate the scaling
+        // here is a skewing issue, since angle for skewed rects is already non 0
+        // (this is an issue in itself, since when user skews a non-rotated rect, the angle should be 0,
+        // so maybe if we find a way to get "un skewed" angle
+        // we can use it here and there. Idk if it's possible, It's hard to say what should be a "proper" angle for skewed rect,
+        // when you didn't see it getting skewed, so perhaps some tracking for overlay session would be the only solution)
+        desiredPos = desiredPos.Rotate(-angle, corners.RectCenter);
+        corners = corners.AsRotated(-angle, corners.RectCenter);
+
+        VecD targetPos = TransformHelper.GetAnchorPosition(corners, targetCorner);
+
+        VecD currentCenter = corners.RectCenter;
+        VecD targetPosToCenter = (targetPos - currentCenter);
+
+        if (targetPosToCenter.Length < epsilon)
+            return corners;
+
+        VecD desiredPosToCenter = (desiredPos - currentCenter);
+
+        VecD scaling = new(desiredPosToCenter.X / targetPosToCenter.X, desiredPosToCenter.Y / targetPosToCenter.Y);
+        
+        // when rect is skewed and falsely un rotated, this applies scaling in wrong directions
+        corners = corners.AsScaled((float)scaling.X, (float)scaling.Y);
+
+        return corners.AsRotated(angle, corners.RectCenter);
+    }
+
     private static VecD SwapAxes(VecD vec) => new VecD(vec.Y, vec.X);
     private static VecD SwapAxes(VecD vec) => new VecD(vec.Y, vec.X);
 
 
     private static VecD TransferZeros(VecD from, VecD to)
     private static VecD TransferZeros(VecD from, VecD to)
@@ -335,8 +350,8 @@ internal static class TransformUpdateHelper
     {
     {
         VecD currentCenter = corners.RectCenter;
         VecD currentCenter = corners.RectCenter;
         float targetPosToCenter = (float)(targetPos - currentCenter).Length;
         float targetPosToCenter = (float)(targetPos - currentCenter).Length;
-        
-        if(targetPosToCenter < epsilon)
+
+        if (targetPosToCenter < epsilon)
             return corners;
             return corners;
 
 
         VecD reflectedDesiredPos = desiredPos.ReflectAcrossLine(currentCenter, targetPos);
         VecD reflectedDesiredPos = desiredPos.ReflectAcrossLine(currentCenter, targetPos);