| 123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421 | using System;using System.Drawing;namespace PaintDotNet{    /// <summary>    /// 封装了缩放坐标的功能    /// </summary>    public struct ScaleFactor    {        /// <summary>        /// 分母        /// </summary>        private int denominator;        /// <summary>        /// 分子        /// </summary>        private int numerator;        public int Denominator        {            get            {                return denominator;            }        }        public int Numerator        {            get            {                return numerator;            }        }        /// <summary>        /// 缩放比例        /// </summary>        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            };        /// <summary>        /// Gets a list of values that GetNextLarger() and GetNextSmaller() will cycle through.        /// </summary>        /// <remarks>        /// 1.0 is guaranteed to be in the array returned by this property. This list is also        /// sorted in ascending order.        /// </remarks>        public static double[] PresetValues        {            get            {                double[] returnValue = new double[scales.Length];                scales.CopyTo(returnValue, 0);                return returnValue;            }        }        /// <summary>        /// Rounds the current scaling factor up to the next power of two.        /// </summary>        /// <returns>The new ScaleFactor value.</returns>        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();        }    }}
 |