using System; using System.Drawing; namespace PaintDotNet { /// /// 封装了缩放坐标的功能 /// public struct ScaleFactor { /// /// 分母 /// private int denominator; /// /// 分子 /// private int numerator; public int Denominator { get { return denominator; } } public int Numerator { get { return numerator; } } /// /// 缩放比例 /// public double Ratio { get { return (double)numerator / (double)denominator; } } public static readonly ScaleFactor OneToOne = new ScaleFactor(1, 1); public static readonly ScaleFactor MinValue = new ScaleFactor(1, 100); public static readonly ScaleFactor MaxValue = new ScaleFactor(32, 1); private void Clamp() { if (this < MinValue) { this = MinValue; } else if (this > MaxValue) { this = MaxValue; } } public static ScaleFactor UseIfValid(int numerator, int denominator, ScaleFactor lastResort) { if (numerator <= 0 || denominator <= 0) { return lastResort; } else { return new ScaleFactor(numerator, denominator); } } public static ScaleFactor Min(int n1, int d1, int n2, int d2, ScaleFactor lastResort) { ScaleFactor a = UseIfValid(n1, d1, lastResort); ScaleFactor b = UseIfValid(n2, d2, lastResort); return ScaleFactor.Min(a, b); } public static ScaleFactor Max(int n1, int d1, int n2, int d2, ScaleFactor lastResort) { ScaleFactor a = UseIfValid(n1, d1, lastResort); ScaleFactor b = UseIfValid(n2, d2, lastResort); return ScaleFactor.Max(a, b); } public static ScaleFactor Min(ScaleFactor lhs, ScaleFactor rhs) { if (lhs < rhs) { return lhs; } else { return rhs; } } public static ScaleFactor Max(ScaleFactor lhs, ScaleFactor rhs) { if (lhs > rhs) { return lhs; } else { return lhs; } } public static bool operator ==(ScaleFactor lhs, ScaleFactor rhs) { return (lhs.numerator * rhs.denominator) == (rhs.numerator * lhs.denominator); } public static bool operator !=(ScaleFactor lhs, ScaleFactor rhs) { return !(lhs == rhs); } public static bool operator <(ScaleFactor lhs, ScaleFactor rhs) { return (lhs.numerator * rhs.denominator) < (rhs.numerator * lhs.denominator); } public static bool operator <=(ScaleFactor lhs, ScaleFactor rhs) { return (lhs.numerator * rhs.denominator) <= (rhs.numerator * lhs.denominator); } public static bool operator >(ScaleFactor lhs, ScaleFactor rhs) { return (lhs.numerator * rhs.denominator) > (rhs.numerator * lhs.denominator); } public static bool operator >=(ScaleFactor lhs, ScaleFactor rhs) { return (lhs.numerator * rhs.denominator) >= (rhs.numerator * lhs.denominator); } public override bool Equals(object obj) { if (obj is ScaleFactor) { ScaleFactor rhs = (ScaleFactor)obj; return this == rhs; } else { return false; } } public override int GetHashCode() { return numerator.GetHashCode() ^ denominator.GetHashCode(); } public override string ToString() { try { var percentageFormat = PdnResources.GetString("ScaleFactor.Percentage.Format"); return string.Format(percentageFormat, unchecked(Math.Round(unchecked(100 * Ratio)))); } catch (ArithmeticException) { return "--"; } } public int ScaleScalar(int x) { return (int)(((long)x * numerator) / denominator); } public int UnscaleScalar(int x) { return (int)(((long)x * denominator) / numerator); } public float ScaleScalar(float x) { return (x * (float)numerator) / (float)denominator; } public float UnscaleScalar(float x) { return (x * (float)denominator) / (float)numerator; } public double ScaleScalar(double x) { return (x * (double)numerator) / (double)denominator; } public double UnscaleScalar(double x) { return (x * (double)denominator) / (double)numerator; } public Point ScalePoint(Point p) { return new Point(ScaleScalar(p.X), ScaleScalar(p.Y)); } public PointF ScalePoint(PointF p) { return new PointF(ScaleScalar(p.X), ScaleScalar(p.Y)); } public PointF ScalePointJustX(PointF p) { return new PointF(ScaleScalar(p.X), p.Y); } public PointF ScalePointJustY(PointF p) { return new PointF(p.X, ScaleScalar(p.Y)); } public PointF UnscalePoint(PointF p) { return new PointF(UnscaleScalar(p.X), UnscaleScalar(p.Y)); } public PointF UnscalePointJustX(PointF p) { return new PointF(UnscaleScalar(p.X), p.Y); } public PointF UnscalePointJustY(PointF p) { return new PointF(p.X, UnscaleScalar(p.Y)); } public Point ScalePointJustX(Point p) { return new Point(ScaleScalar(p.X), p.Y); } public Point ScalePointJustY(Point p) { return new Point(p.X, ScaleScalar(p.Y)); } public Point UnscalePoint(Point p) { return new Point(UnscaleScalar(p.X), UnscaleScalar(p.Y)); } public Point UnscalePointJustX(Point p) { return new Point(UnscaleScalar(p.X), p.Y); } public Point UnscalePointJustY(Point p) { return new Point(p.X, UnscaleScalar(p.Y)); } public SizeF ScaleSize(SizeF s) { return new SizeF(ScaleScalar(s.Width), ScaleScalar(s.Height)); } public SizeF UnscaleSize(SizeF s) { return new SizeF(UnscaleScalar(s.Width), UnscaleScalar(s.Height)); } public Size ScaleSize(Size s) { return new Size(ScaleScalar(s.Width), ScaleScalar(s.Height)); } public Size UnscaleSize(Size s) { return new Size(UnscaleScalar(s.Width), UnscaleScalar(s.Height)); } public RectangleF ScaleRectangle(RectangleF rectF) { return new RectangleF(ScalePoint(rectF.Location), ScaleSize(rectF.Size)); } public RectangleF UnscaleRectangle(RectangleF rectF) { return new RectangleF(UnscalePoint(rectF.Location), UnscaleSize(rectF.Size)); } public Rectangle ScaleRectangle(Rectangle rect) { return new Rectangle(ScalePoint(rect.Location), ScaleSize(rect.Size)); } public Rectangle UnscaleRectangle(Rectangle rect) { return new Rectangle(UnscalePoint(rect.Location), UnscaleSize(rect.Size)); } private static readonly double[] scales = { 0.01, 0.02, 0.03, 0.04, 0.05, 0.06, 0.08, 0.12, 0.16, 0.25, 0.33, 0.50, 0.66, 1, 2, 3, 4, 5, 6, 7, 8, 12, 16, 24, 32 }; /// /// Gets a list of values that GetNextLarger() and GetNextSmaller() will cycle through. /// /// /// 1.0 is guaranteed to be in the array returned by this property. This list is also /// sorted in ascending order. /// public static double[] PresetValues { get { double[] returnValue = new double[scales.Length]; scales.CopyTo(returnValue, 0); return returnValue; } } /// /// Rounds the current scaling factor up to the next power of two. /// /// The new ScaleFactor value. public ScaleFactor GetNextLarger() { double ratio = Ratio + 0.005; int index = Array.FindIndex( scales, delegate (double scale) { return ratio <= scale; }); if (index == -1) { index = scales.Length; } index = Math.Min(index, scales.Length - 1); return ScaleFactor.FromDouble(scales[index]); } public ScaleFactor GetNextSmaller() { double ratio = Ratio - 0.005; int index = Array.FindIndex( scales, delegate (double scale) { return ratio <= scale; }); --index; if (index == -1) { index = 0; } index = Math.Max(index, 0); return ScaleFactor.FromDouble(scales[index]); } private static ScaleFactor Reduce(int numerator, int denominator) { int factor = 2; while (factor < denominator && factor < numerator) { if ((numerator % factor) == 0 && (denominator % factor) == 0) { numerator /= factor; denominator /= factor; } else { ++factor; } } return new ScaleFactor(numerator, denominator); } public static ScaleFactor FromDouble(double scalar) { int numerator = (int)(Math.Floor(scalar * 1000.0)); int denominator = 1000; return Reduce(numerator, denominator); } public ScaleFactor(int numerator, int denominator) { if (denominator <= 0) { throw new ArgumentOutOfRangeException("denominator", "must be greater than 0"); } if (numerator < 0) { throw new ArgumentOutOfRangeException("numerator", "must be greater than 0"); } this.numerator = numerator; this.denominator = denominator; this.Clamp(); } } }