Browse Source

Make skewed rectangles preserve angles when scaling transform overlay relative to center

Equbuxu 4 months ago
parent
commit
026a1c8bbc

+ 20 - 54
src/PixiEditor/Views/Overlays/TransformOverlay/TransformUpdateHelper.cs

@@ -33,7 +33,7 @@ internal static class TransformUpdateHelper
 
 
             snapX = snapY = "";
             snapX = snapY = "";
 
 
-            // constrain desired pos to a "propotional" diagonal line if needed
+            // constrain desired pos to a "proportional" diagonal line if needed
             if (freedom == TransformCornerFreedom.ScaleProportionally && corners.IsRect)
             if (freedom == TransformCornerFreedom.ScaleProportionally && corners.IsRect)
             {
             {
                 double correctAngle = targetCorner is Anchor.TopLeft or Anchor.BottomRight ? propAngle1 : propAngle2;
                 double correctAngle = targetCorner is Anchor.TopLeft or Anchor.BottomRight ? propAngle1 : propAngle2;
@@ -68,23 +68,15 @@ internal static class TransformUpdateHelper
             VecD leftNeighborPos = TransformHelper.GetAnchorPosition(corners, leftNeighbor);
             VecD leftNeighborPos = TransformHelper.GetAnchorPosition(corners, leftNeighbor);
             VecD rightNeighborPos = TransformHelper.GetAnchorPosition(corners, rightNeighbor);
             VecD rightNeighborPos = TransformHelper.GetAnchorPosition(corners, rightNeighbor);
 
 
-            double angle = corners.RectRotation;
-            if (double.IsNaN(angle))
-                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
-            VecD targetTrans = (targetPos - oppositePos).Rotate(-angle);
-            VecD leftNeighTrans = (leftNeighborPos - oppositePos).Rotate(-angle);
-            VecD rightNeighTrans = (rightNeighborPos - oppositePos).Rotate(-angle);
+            // find positions of neighboring corners relative to the opposite corner
+            VecD targetTrans = targetPos - oppositePos;
+            VecD leftNeighTrans = leftNeighborPos - oppositePos;
+            VecD rightNeighTrans = rightNeighborPos - oppositePos;
 
 
             // find by how much move each corner
             // find by how much move each corner
-            VecD delta = (desiredPos - targetPos).Rotate(-angle);
+            VecD delta = desiredPos - targetPos;
             VecD leftNeighDelta, rightNeighDelta;
             VecD leftNeighDelta, rightNeighDelta;
+            VecD oppositeDelta = scaleFromCenter ? -delta : VecD.Zero;
 
 
             if (corners.IsPartiallyDegenerate)
             if (corners.IsPartiallyDegenerate)
             {
             {
@@ -94,10 +86,12 @@ internal static class TransformUpdateHelper
             }
             }
             else
             else
             {
             {
-                VecD? newLeftPos = TransformHelper.TwoLineIntersection(VecD.Zero, leftNeighTrans, targetTrans + delta,
-                    leftNeighTrans + delta);
-                VecD? newRightPos = TransformHelper.TwoLineIntersection(VecD.Zero, rightNeighTrans, targetTrans + delta,
-                    rightNeighTrans + delta);
+                VecD? newLeftPos = TransformHelper.TwoLineIntersection(
+                    oppositeDelta, leftNeighTrans + oppositeDelta, 
+                    targetTrans + delta, leftNeighTrans + delta);
+                VecD? newRightPos = TransformHelper.TwoLineIntersection(
+                    oppositeDelta, rightNeighTrans + oppositeDelta,
+                    targetTrans + delta, rightNeighTrans + delta);
                 if (newLeftPos is null || newRightPos is null)
                 if (newLeftPos is null || newRightPos is null)
                     return null;
                     return null;
                 leftNeighDelta = newLeftPos.Value - leftNeighTrans;
                 leftNeighDelta = newLeftPos.Value - leftNeighTrans;
@@ -121,14 +115,16 @@ internal static class TransformUpdateHelper
                 rightNeighDelta = TransferZeros(SwapAxes(leftNeighTrans), delta);
                 rightNeighDelta = TransferZeros(SwapAxes(leftNeighTrans), delta);
             }
             }
 
 
-            // move the corners, while reapplying the transform rotation
+            // move the corners, finally
             corners = TransformHelper.UpdateCorner(corners, targetCorner,
             corners = TransformHelper.UpdateCorner(corners, targetCorner,
-                (targetTrans + delta).Rotate(angle) + oppositePos);
+                targetTrans + delta + oppositePos);
+            corners = TransformHelper.UpdateCorner(corners, opposite,
+                oppositePos + oppositeDelta);
             corners = TransformHelper.UpdateCorner(corners, leftNeighbor,
             corners = TransformHelper.UpdateCorner(corners, leftNeighbor,
-                (leftNeighTrans + leftNeighDelta).Rotate(angle) + oppositePos);
+                leftNeighTrans + leftNeighDelta + oppositePos);
             corners = TransformHelper.UpdateCorner(corners, rightNeighbor,
             corners = TransformHelper.UpdateCorner(corners, rightNeighbor,
-                (rightNeighTrans + rightNeighDelta).Rotate(angle) + oppositePos);
-
+                rightNeighTrans + rightNeighDelta + oppositePos);
+            
             if (!corners.IsLegal)
             if (!corners.IsLegal)
                 return null;
                 return null;
 
 
@@ -145,36 +141,6 @@ 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)