PageRenderTime 51ms CodeModel.GetById 25ms RepoModel.GetById 0ms app.codeStats 0ms

/src/Core/ScaleFactor.cs

https://bitbucket.org/tuldok89/openpdn
C# | 396 lines | 304 code | 68 blank | 24 comment | 21 complexity | 0f2ddc537d2b207712820bc39eeb8dce MD5 | raw file
  1. /////////////////////////////////////////////////////////////////////////////////
  2. // Paint.NET //
  3. // Copyright (C) dotPDN LLC, Rick Brewster, Tom Jackson, and contributors. //
  4. // Portions Copyright (C) Microsoft Corporation. All Rights Reserved. //
  5. // See src/Resources/Files/License.txt for full licensing and attribution //
  6. // details. //
  7. // . //
  8. /////////////////////////////////////////////////////////////////////////////////
  9. using System;
  10. using System.Drawing;
  11. namespace PaintDotNet
  12. {
  13. /// <summary>
  14. /// Encapsulates functionality for zooming/scaling coordinates.
  15. /// Includes methods for Size[F]'s, Point[F]'s, Rectangle[F]'s,
  16. /// and various scalars
  17. /// </summary>
  18. public struct ScaleFactor
  19. {
  20. private readonly int _denominator;
  21. private readonly int _numerator;
  22. public int Denominator
  23. {
  24. get
  25. {
  26. return _denominator;
  27. }
  28. }
  29. public int Numerator
  30. {
  31. get
  32. {
  33. return _numerator;
  34. }
  35. }
  36. public double Ratio
  37. {
  38. get
  39. {
  40. return (double)_numerator / (double)_denominator;
  41. }
  42. }
  43. public static readonly ScaleFactor OneToOne = new ScaleFactor(1, 1);
  44. public static readonly ScaleFactor MinValue = new ScaleFactor(1, 100);
  45. public static readonly ScaleFactor MaxValue = new ScaleFactor(32, 1);
  46. private void Clamp()
  47. {
  48. if (this < MinValue)
  49. {
  50. this = MinValue;
  51. }
  52. else if (this > MaxValue)
  53. {
  54. this = MaxValue;
  55. }
  56. }
  57. public static ScaleFactor UseIfValid(int numerator, int denominator, ScaleFactor lastResort)
  58. {
  59. if (numerator <= 0 || denominator <= 0)
  60. {
  61. return lastResort;
  62. }
  63. return new ScaleFactor(numerator, denominator);
  64. }
  65. public static ScaleFactor Min(int n1, int d1, int n2, int d2, ScaleFactor lastResort)
  66. {
  67. ScaleFactor a = UseIfValid(n1, d1, lastResort);
  68. ScaleFactor b = UseIfValid(n2, d2, lastResort);
  69. return Min(a, b);
  70. }
  71. public static ScaleFactor Max(int n1, int d1, int n2, int d2, ScaleFactor lastResort)
  72. {
  73. ScaleFactor a = UseIfValid(n1, d1, lastResort);
  74. ScaleFactor b = UseIfValid(n2, d2, lastResort);
  75. return Max(a, b);
  76. }
  77. public static ScaleFactor Min(ScaleFactor lhs, ScaleFactor rhs)
  78. {
  79. return lhs < rhs ? lhs : rhs;
  80. }
  81. public static ScaleFactor Max(ScaleFactor lhs, ScaleFactor rhs)
  82. {
  83. return lhs;
  84. }
  85. public static bool operator==(ScaleFactor lhs, ScaleFactor rhs)
  86. {
  87. return (lhs._numerator * rhs._denominator) == (rhs._numerator * lhs._denominator);
  88. }
  89. public static bool operator!=(ScaleFactor lhs, ScaleFactor rhs)
  90. {
  91. return !(lhs == rhs);
  92. }
  93. public static bool operator<(ScaleFactor lhs, ScaleFactor rhs)
  94. {
  95. return (lhs._numerator * rhs._denominator) < (rhs._numerator * lhs._denominator);
  96. }
  97. public static bool operator<=(ScaleFactor lhs, ScaleFactor rhs)
  98. {
  99. return (lhs._numerator * rhs._denominator) <= (rhs._numerator * lhs._denominator);
  100. }
  101. public static bool operator>(ScaleFactor lhs, ScaleFactor rhs)
  102. {
  103. return (lhs._numerator * rhs._denominator) > (rhs._numerator * lhs._denominator);
  104. }
  105. public static bool operator>=(ScaleFactor lhs, ScaleFactor rhs)
  106. {
  107. return (lhs._numerator * rhs._denominator) >= (rhs._numerator * lhs._denominator);
  108. }
  109. public override bool Equals(object obj)
  110. {
  111. if (obj is ScaleFactor)
  112. {
  113. var rhs = (ScaleFactor)obj;
  114. return this == rhs;
  115. }
  116. return false;
  117. }
  118. public override int GetHashCode()
  119. {
  120. return _numerator.GetHashCode() ^ _denominator.GetHashCode();
  121. }
  122. private static readonly string PercentageFormat = PdnResources.GetString("ScaleFactor.Percentage.Format");
  123. public override string ToString()
  124. {
  125. try
  126. {
  127. return string.Format(PercentageFormat, unchecked(Math.Round(unchecked(100 * Ratio))));
  128. }
  129. catch (ArithmeticException)
  130. {
  131. return "--";
  132. }
  133. }
  134. public int ScaleScalar(int x)
  135. {
  136. return (int)(((long)x * _numerator) / _denominator);
  137. }
  138. public int UnscaleScalar(int x)
  139. {
  140. return (int)(((long)x * _denominator) / _numerator);
  141. }
  142. public float ScaleScalar(float x)
  143. {
  144. return (x * (float)_numerator) / (float)_denominator;
  145. }
  146. public float UnscaleScalar(float x)
  147. {
  148. return (x * (float)_denominator) / (float)_numerator;
  149. }
  150. public double ScaleScalar(double x)
  151. {
  152. return (x * (double)_numerator) / (double)_denominator;
  153. }
  154. public double UnscaleScalar(double x)
  155. {
  156. return (x * (double)_denominator) / (double)_numerator;
  157. }
  158. public Point ScalePoint(Point p)
  159. {
  160. return new Point(ScaleScalar(p.X), ScaleScalar(p.Y));
  161. }
  162. public PointF ScalePoint(PointF p)
  163. {
  164. return new PointF(ScaleScalar(p.X), ScaleScalar(p.Y));
  165. }
  166. public PointF ScalePointJustX(PointF p)
  167. {
  168. return new PointF(ScaleScalar(p.X), p.Y);
  169. }
  170. public PointF ScalePointJustY(PointF p)
  171. {
  172. return new PointF(p.X, ScaleScalar(p.Y));
  173. }
  174. public PointF UnscalePoint(PointF p)
  175. {
  176. return new PointF(UnscaleScalar(p.X), UnscaleScalar(p.Y));
  177. }
  178. public PointF UnscalePointJustX(PointF p)
  179. {
  180. return new PointF(UnscaleScalar(p.X), p.Y);
  181. }
  182. public PointF UnscalePointJustY(PointF p)
  183. {
  184. return new PointF(p.X, UnscaleScalar(p.Y));
  185. }
  186. public Point ScalePointJustX(Point p)
  187. {
  188. return new Point(ScaleScalar(p.X), p.Y);
  189. }
  190. public Point ScalePointJustY(Point p)
  191. {
  192. return new Point(p.X, ScaleScalar(p.Y));
  193. }
  194. public Point UnscalePoint(Point p)
  195. {
  196. return new Point(UnscaleScalar(p.X), UnscaleScalar(p.Y));
  197. }
  198. public Point UnscalePointJustX(Point p)
  199. {
  200. return new Point(UnscaleScalar(p.X), p.Y);
  201. }
  202. public Point UnscalePointJustY(Point p)
  203. {
  204. return new Point(p.X, UnscaleScalar(p.Y));
  205. }
  206. public SizeF ScaleSize(SizeF s)
  207. {
  208. return new SizeF(ScaleScalar(s.Width), ScaleScalar(s.Height));
  209. }
  210. public SizeF UnscaleSize(SizeF s)
  211. {
  212. return new SizeF(UnscaleScalar(s.Width), UnscaleScalar(s.Height));
  213. }
  214. public Size ScaleSize(Size s)
  215. {
  216. return new Size(ScaleScalar(s.Width), ScaleScalar(s.Height));
  217. }
  218. public Size UnscaleSize(Size s)
  219. {
  220. return new Size(UnscaleScalar(s.Width), UnscaleScalar(s.Height));
  221. }
  222. public RectangleF ScaleRectangle(RectangleF rectF)
  223. {
  224. return new RectangleF(ScalePoint(rectF.Location), ScaleSize(rectF.Size));
  225. }
  226. public RectangleF UnscaleRectangle(RectangleF rectF)
  227. {
  228. return new RectangleF(UnscalePoint(rectF.Location), UnscaleSize(rectF.Size));
  229. }
  230. public Rectangle ScaleRectangle(Rectangle rect)
  231. {
  232. return new Rectangle(ScalePoint(rect.Location), ScaleSize(rect.Size));
  233. }
  234. public Rectangle UnscaleRectangle(Rectangle rect)
  235. {
  236. return new Rectangle(UnscalePoint(rect.Location), UnscaleSize(rect.Size));
  237. }
  238. private static readonly double[] Scales =
  239. {
  240. 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,
  241. 2, 3, 4, 5, 6, 7, 8, 12, 16, 24, 32
  242. };
  243. /// <summary>
  244. /// Gets a list of values that GetNextLarger() and GetNextSmaller() will cycle through.
  245. /// </summary>
  246. /// <remarks>
  247. /// 1.0 is guaranteed to be in the array returned by this property. This list is also
  248. /// sorted in ascending order.
  249. /// </remarks>
  250. public static double[] PresetValues
  251. {
  252. get
  253. {
  254. var returnValue = new double[Scales.Length];
  255. Scales.CopyTo(returnValue, 0);
  256. return returnValue;
  257. }
  258. }
  259. /// <summary>
  260. /// Rounds the current scaling factor up to the next power of two.
  261. /// </summary>
  262. /// <returns>The new ScaleFactor value.</returns>
  263. public ScaleFactor GetNextLarger()
  264. {
  265. double ratio = Ratio + 0.005;
  266. int index = Array.FindIndex(
  267. Scales,
  268. scale => ratio <= scale);
  269. if (index == -1)
  270. {
  271. index = Scales.Length;
  272. }
  273. index = Math.Min(index, Scales.Length - 1);
  274. return FromDouble(Scales[index]);
  275. }
  276. public ScaleFactor GetNextSmaller()
  277. {
  278. double ratio = Ratio - 0.005;
  279. int index = Array.FindIndex(
  280. Scales,
  281. scale => ratio <= scale);
  282. --index;
  283. if (index == -1)
  284. {
  285. index = 0;
  286. }
  287. index = Math.Max(index, 0);
  288. return FromDouble(Scales[index]);
  289. }
  290. private static ScaleFactor Reduce(int numerator, int denominator)
  291. {
  292. int factor = 2;
  293. while (factor < denominator && factor < numerator)
  294. {
  295. if ((numerator % factor) == 0 && (denominator % factor) == 0)
  296. {
  297. numerator /= factor;
  298. denominator /= factor;
  299. }
  300. else
  301. {
  302. ++factor;
  303. }
  304. }
  305. return new ScaleFactor(numerator, denominator);
  306. }
  307. public static ScaleFactor FromDouble(double scalar)
  308. {
  309. var numerator = (int)(Math.Floor(scalar * 1000.0));
  310. const int denominator = 1000;
  311. return Reduce(numerator, denominator);
  312. }
  313. public ScaleFactor(int numerator, int denominator)
  314. {
  315. if (denominator <= 0)
  316. {
  317. throw new ArgumentOutOfRangeException("denominator", "must be greater than 0");
  318. }
  319. if (numerator < 0)
  320. {
  321. throw new ArgumentOutOfRangeException("numerator", "must be greater than 0");
  322. }
  323. _numerator = numerator;
  324. _denominator = denominator;
  325. Clamp();
  326. }
  327. }
  328. }