Fix Objects Growing near Infinity when Scaling w Aspect Ratio Maintained

This commit is contained in:
jklingen 2021-03-21 17:12:54 +01:00
parent d54a1a66b3
commit fb843fb414

View file

@ -29,7 +29,7 @@ namespace Greenshot.Helpers {
/// </summary> /// </summary>
public static class ScaleHelper { public static class ScaleHelper {
[Flags] [Flags]
public enum ScaleOptions { public enum ScaleOptions {
/// <summary> /// <summary>
/// Default scale behavior. /// Default scale behavior.
@ -218,24 +218,35 @@ namespace Greenshot.Helpers {
} }
/// <summary> /// <summary>
/// Adjusts resizeHandleCoords so that aspect ratio is kept after resizing a given rectangle with provided arguments /// Adjusts resizeHandleCoords so that aspect ratio is kept after resizing a given rectangle with provided arguments.
/// An adjustment can always be done in two ways, e.g. *in*crease width until fit or *de*crease height until fit.
/// To avoid objects growing near infinity unexpectedly in certain combinations, the adjustment will choose the
/// option resulting in the smaller rectangle.
/// </summary> /// </summary>
/// <param name="originalRectangle">bounds of the current rectangle</param> /// <param name="originalRectangle">bounds of the current rectangle</param>
/// <param name="resizeHandlePosition">position of the handle/gripper being used for resized, see Position</param> /// <param name="resizeHandlePosition">position of the handle/gripper being used for resized, see Position</param>
/// <param name="resizeHandleCoords">coordinates of the used handle/gripper, adjusted coordinates will be written to this reference</param> /// <param name="resizeHandleCoords">coordinates of the used handle/gripper, adjusted coordinates will be written to this reference</param>
private static void adjustCoordsForRationalScale(RectangleF originalRectangle, Positions resizeHandlePosition, ref PointF resizeHandleCoords) { private static void adjustCoordsForRationalScale(RectangleF originalRectangle, Positions resizeHandlePosition, ref PointF resizeHandleCoords) {
float originalRatio = originalRectangle.Width / originalRectangle.Height; float originalRatio = originalRectangle.Width / originalRectangle.Height;
float newWidth, newHeight, newRatio; float newWidth, newHeight, newRatio;
int flippedRatioSign;
switch(resizeHandlePosition) { switch(resizeHandlePosition) {
case Positions.TopLeft: case Positions.TopLeft:
newWidth = originalRectangle.Right - resizeHandleCoords.X; newWidth = originalRectangle.Right - resizeHandleCoords.X;
newHeight = originalRectangle.Bottom - resizeHandleCoords.Y; newHeight = originalRectangle.Bottom - resizeHandleCoords.Y;
newRatio = newWidth / newHeight; newRatio = newWidth / newHeight;
if(newRatio > originalRatio) { // FIXME flippedRatioSign = Math.Sign(newRatio) * Math.Sign(originalRatio);
resizeHandleCoords.X = originalRectangle.Right - newHeight * originalRatio; if (Math.Abs(newRatio) > Math.Abs(originalRatio)) {
} else if(newRatio < originalRatio) { // scaled rectangle (ratio) would be wider than original
resizeHandleCoords.Y = originalRectangle.Bottom - newWidth / originalRatio; // keep height and tweak width to maintain aspect ratio
float tweakedWidth = newHeight * originalRatio * flippedRatioSign;
resizeHandleCoords.X = originalRectangle.Right - tweakedWidth;
} else if(Math.Abs(newRatio) < Math.Abs(originalRatio)) {
// scaled rectangle (ratio) would be taller than original
// keep width and tweak height to maintain aspect ratio
float tweakedHeight = newWidth / originalRatio * flippedRatioSign;
resizeHandleCoords.Y = originalRectangle.Bottom - tweakedHeight;
} }
break; break;
@ -243,34 +254,62 @@ namespace Greenshot.Helpers {
newWidth = resizeHandleCoords.X - originalRectangle.Left; newWidth = resizeHandleCoords.X - originalRectangle.Left;
newHeight = originalRectangle.Bottom - resizeHandleCoords.Y; newHeight = originalRectangle.Bottom - resizeHandleCoords.Y;
newRatio = newWidth / newHeight; newRatio = newWidth / newHeight;
if(newRatio > originalRatio) { // FIXME flippedRatioSign = Math.Sign(newRatio) * Math.Sign(originalRatio);
resizeHandleCoords.X = newHeight * originalRatio + originalRectangle.Left;
} else if(newRatio < originalRatio) { if (Math.Abs(newRatio) > Math.Abs(originalRatio)) {
resizeHandleCoords.Y = originalRectangle.Bottom - newWidth / originalRatio; // scaled rectangle (ratio) would be wider than original
} // keep height and tweak width to maintain aspect ratio
break; float tweakedWidth = newHeight * originalRatio * flippedRatioSign;
resizeHandleCoords.X = originalRectangle.Left + tweakedWidth;
}
else if (Math.Abs(newRatio) < Math.Abs(originalRatio)) {
// scaled rectangle (ratio) would be taller than original
// keep width and tweak height to maintain aspect ratio
float tweakedHeight = newWidth / originalRatio * flippedRatioSign;
resizeHandleCoords.Y = originalRectangle.Bottom - tweakedHeight;
}
break;
case Positions.BottomLeft: case Positions.BottomLeft:
newWidth = originalRectangle.Right - resizeHandleCoords.X; newWidth = originalRectangle.Right - resizeHandleCoords.X;
newHeight = resizeHandleCoords.Y - originalRectangle.Top; newHeight = resizeHandleCoords.Y - originalRectangle.Top;
newRatio = newWidth / newHeight; newRatio = newWidth / newHeight;
if(newRatio > originalRatio) { flippedRatioSign = Math.Sign(newRatio) * Math.Sign(originalRatio);
resizeHandleCoords.X = originalRectangle.Right - newHeight * originalRatio;
} else if(newRatio < originalRatio) { if (Math.Abs(newRatio) > Math.Abs(originalRatio)) {
resizeHandleCoords.Y = newWidth / originalRatio + originalRectangle.Top; // scaled rectangle (ratio) would be wider than original
} // keep height and tweak width to maintain aspect ratio
break; float tweakedWidth = newHeight * originalRatio * flippedRatioSign;
resizeHandleCoords.X = originalRectangle.Right - tweakedWidth;
}
else if (Math.Abs(newRatio) < Math.Abs(originalRatio)) {
// scaled rectangle (ratio) would be taller than original
// keep width and tweak height to maintain aspect ratio
float tweakedHeight = newWidth / originalRatio * flippedRatioSign;
resizeHandleCoords.Y = originalRectangle.Top + tweakedHeight;
}
break;
case Positions.BottomRight: case Positions.BottomRight:
newWidth = resizeHandleCoords.X - originalRectangle.Left; newWidth = resizeHandleCoords.X - originalRectangle.Left;
newHeight = resizeHandleCoords.Y - originalRectangle.Top; newHeight = resizeHandleCoords.Y - originalRectangle.Top;
newRatio = newWidth / newHeight; newRatio = newWidth / newHeight;
if(newRatio > originalRatio) { flippedRatioSign = Math.Sign(newRatio) * Math.Sign(originalRatio);
resizeHandleCoords.X = newHeight * originalRatio + originalRectangle.Left;
} else if(newRatio < originalRatio) { if (Math.Abs(newRatio) > Math.Abs(originalRatio)) {
resizeHandleCoords.Y = newWidth / originalRatio + originalRectangle.Top; // scaled rectangle (ratio) would be wider than original
} // keep height and tweak width to maintain aspect ratio
break; float tweakedWidth = newHeight * originalRatio * flippedRatioSign;
resizeHandleCoords.X = originalRectangle.Left + tweakedWidth;
}
else if (Math.Abs(newRatio) < Math.Abs(originalRatio)) {
// TODO this is the same code as else if for topleft!
// scaled rectangle (ratio) would be taller than original
// keep width and tweak height to maintain aspect ratio
float tweakedHeight = newWidth / originalRatio * flippedRatioSign;
resizeHandleCoords.Y = originalRectangle.Top + tweakedHeight;
}
break;
} }
} }