PageRenderTime 259ms CodeModel.GetById 32ms RepoModel.GetById 6ms app.codeStats 2ms

/src/Core/Utility.cs

https://bitbucket.org/tcz001/openpdn
C# | 3273 lines | 2568 code | 519 blank | 186 comment | 377 complexity | 4946d19edb99d6fa1f3119903511463b MD5 | raw file
Possible License(s): Unlicense
  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 Microsoft.Win32;
  10. using PaintDotNet.Threading;
  11. using PaintDotNet.SystemLayer;
  12. using System;
  13. using System.Collections;
  14. using System.Collections.Generic;
  15. using System.ComponentModel;
  16. using System.Diagnostics;
  17. using System.Drawing;
  18. using System.Drawing.Drawing2D;
  19. using System.Drawing.Imaging;
  20. using System.Globalization;
  21. using System.IO;
  22. using System.Net;
  23. using System.Reflection;
  24. using System.Runtime.InteropServices;
  25. using System.Runtime.Serialization;
  26. using System.Runtime.Serialization.Formatters.Binary;
  27. using System.Text;
  28. using System.Threading;
  29. using System.Windows.Forms;
  30. namespace PaintDotNet
  31. {
  32. /// <summary>
  33. /// Defines miscellaneous constants and static functions.
  34. /// </summary>
  35. /// // TODO: refactor into mini static classes
  36. public sealed class Utility
  37. {
  38. private Utility()
  39. {
  40. }
  41. internal static bool IsNumber(float x)
  42. {
  43. return x >= float.MinValue && x <= float.MaxValue;
  44. }
  45. internal static bool IsNumber(double x)
  46. {
  47. return x >= double.MinValue && x <= double.MaxValue;
  48. }
  49. internal static int Min(int val0, params int[] vals)
  50. {
  51. int min = val0;
  52. for (int i = 0; i < vals.Length; ++i)
  53. {
  54. if (vals[i] < min)
  55. {
  56. min = vals[i];
  57. }
  58. }
  59. return min;
  60. }
  61. internal static int Max(int val0, params int[] vals)
  62. {
  63. int max = val0;
  64. for (int i = 0; i < vals.Length; ++i)
  65. {
  66. if (vals[i] > max)
  67. {
  68. max = vals[i];
  69. }
  70. }
  71. return max;
  72. }
  73. public static PointF[] GetRgssOffsets(int quality)
  74. {
  75. unsafe
  76. {
  77. int sampleCount = quality * quality;
  78. PointF[] samplesArray = new PointF[sampleCount];
  79. fixed (PointF* pSamplesArray = samplesArray)
  80. {
  81. GetRgssOffsets(pSamplesArray, sampleCount, quality);
  82. }
  83. return samplesArray;
  84. }
  85. }
  86. public static unsafe void GetRgssOffsets(PointF* samplesArray, int sampleCount, int quality)
  87. {
  88. if (sampleCount < 1)
  89. {
  90. throw new ArgumentOutOfRangeException("sampleCount", "sampleCount must be [0, int.MaxValue]");
  91. }
  92. if (sampleCount != quality * quality)
  93. {
  94. throw new ArgumentOutOfRangeException("sampleCount != (quality * quality)");
  95. }
  96. if (sampleCount == 1)
  97. {
  98. samplesArray[0] = new PointF(0.0f, 0.0f);
  99. }
  100. else
  101. {
  102. for (int i = 0; i < sampleCount; ++i)
  103. {
  104. double y = (i + 1d) / (sampleCount + 1d);
  105. double x = y * quality;
  106. x -= (int)x;
  107. samplesArray[i] = new PointF((float)(x - 0.5d), (float)(y - 0.5d));
  108. }
  109. }
  110. }
  111. public static bool IsObsolete(Type type, bool inherit)
  112. {
  113. object[] attrs = type.GetCustomAttributes(typeof(ObsoleteAttribute), inherit);
  114. return (attrs.Length != 0);
  115. }
  116. public static void DrawDropShadow1px(Graphics g, Rectangle rect)
  117. {
  118. Brush b0 = new SolidBrush(Color.FromArgb(15, Color.Black));
  119. Brush b1 = new SolidBrush(Color.FromArgb(47, Color.Black));
  120. Pen p2 = new Pen(Color.FromArgb(63, Color.Black));
  121. g.FillRectangle(b0, rect.Left, rect.Top, 1, 1);
  122. g.FillRectangle(b1, rect.Left + 1, rect.Top, 1, 1);
  123. g.FillRectangle(b1, rect.Left, rect.Top + 1, 1, 1);
  124. g.FillRectangle(b0, rect.Right - 1, rect.Top, 1, 1);
  125. g.FillRectangle(b1, rect.Right - 2, rect.Top, 1, 1);
  126. g.FillRectangle(b1, rect.Right - 1, rect.Top + 1, 1, 1);
  127. g.FillRectangle(b0, rect.Left, rect.Bottom - 1, 1, 1);
  128. g.FillRectangle(b1, rect.Left + 1, rect.Bottom - 1, 1, 1);
  129. g.FillRectangle(b1, rect.Left, rect.Bottom - 2, 1, 1);
  130. g.FillRectangle(b0, rect.Right - 1, rect.Bottom - 1, 1, 1);
  131. g.FillRectangle(b1, rect.Right - 2, rect.Bottom - 1, 1, 1);
  132. g.FillRectangle(b1, rect.Right - 1, rect.Bottom - 2, 1, 1);
  133. g.DrawLine(p2, rect.Left + 2, rect.Top, rect.Right - 3, rect.Top);
  134. g.DrawLine(p2, rect.Left, rect.Top + 2, rect.Left, rect.Bottom - 3);
  135. g.DrawLine(p2, rect.Left + 2, rect.Bottom - 1, rect.Right - 3, rect.Bottom - 1);
  136. g.DrawLine(p2, rect.Right - 1, rect.Top + 2, rect.Right - 1, rect.Bottom - 3);
  137. b0.Dispose();
  138. b0 = null;
  139. b1.Dispose();
  140. b1 = null;
  141. p2.Dispose();
  142. p2 = null;
  143. }
  144. public static Keys LetterOrDigitCharToKeys(char c)
  145. {
  146. if (c >= 'a' && c <= 'z')
  147. {
  148. return (Keys)((int)(c - 'a') + (int)Keys.A);
  149. }
  150. else if (c >= 'A' && c <= 'Z')
  151. {
  152. return (Keys)((int)(c - 'A') + (int)Keys.A);
  153. }
  154. else if (c >= '0' && c <= '9')
  155. {
  156. return (Keys)((int)(c - '0') + (int)Keys.D0);
  157. }
  158. else
  159. {
  160. return Keys.None;
  161. }
  162. }
  163. public static Control FindFocus()
  164. {
  165. foreach (Form form in Application.OpenForms)
  166. {
  167. Control focused = FindFocus(form);
  168. if (focused != null)
  169. {
  170. return focused;
  171. }
  172. }
  173. return null;
  174. }
  175. private static Control FindFocus(Control c)
  176. {
  177. if (c.Focused)
  178. {
  179. return c;
  180. }
  181. foreach (Control child in c.Controls)
  182. {
  183. Control f = FindFocus(child);
  184. if (f != null)
  185. {
  186. return f;
  187. }
  188. }
  189. return null;
  190. }
  191. public static void DrawColorRectangle(Graphics g, Rectangle rect, Color color, bool drawBorder)
  192. {
  193. int inflateAmt = drawBorder ? -2 : 0;
  194. Rectangle colorRectangle = Rectangle.Inflate(rect, inflateAmt, inflateAmt);
  195. Brush colorBrush = new LinearGradientBrush(colorRectangle, Color.FromArgb(255, color), color, 90.0f, false);
  196. HatchBrush backgroundBrush = new HatchBrush(HatchStyle.LargeCheckerBoard, Color.FromArgb(191, 191, 191), Color.FromArgb(255, 255, 255));
  197. if (drawBorder)
  198. {
  199. g.DrawRectangle(Pens.Black, rect.Left, rect.Top, rect.Width - 1, rect.Height - 1);
  200. g.DrawRectangle(Pens.White, rect.Left + 1, rect.Top + 1, rect.Width - 3, rect.Height - 3);
  201. }
  202. PixelOffsetMode oldPOM = g.PixelOffsetMode;
  203. g.PixelOffsetMode = PixelOffsetMode.Half;
  204. g.FillRectangle(backgroundBrush, colorRectangle);
  205. g.FillRectangle(colorBrush, colorRectangle);
  206. g.PixelOffsetMode = oldPOM;
  207. backgroundBrush.Dispose();
  208. colorBrush.Dispose();
  209. }
  210. public static Size ComputeThumbnailSize(Size originalSize, int maxEdgeLength)
  211. {
  212. Size thumbSize;
  213. if (originalSize.Width > originalSize.Height)
  214. {
  215. int longSide = Math.Min(originalSize.Width, maxEdgeLength);
  216. thumbSize = new Size(longSide, Math.Max(1, (originalSize.Height * longSide) / originalSize.Width));
  217. }
  218. else if (originalSize.Height > originalSize.Width)
  219. {
  220. int longSide = Math.Min(originalSize.Height, maxEdgeLength);
  221. thumbSize = new Size(Math.Max(1, (originalSize.Width * longSide) / originalSize.Height), longSide);
  222. }
  223. else // if (docSize.Width == docSize.Height)
  224. {
  225. int longSide = Math.Min(originalSize.Width, maxEdgeLength);
  226. thumbSize = new Size(longSide, longSide);
  227. }
  228. return thumbSize;
  229. }
  230. public static bool IsClipboardImageAvailable()
  231. {
  232. try
  233. {
  234. return System.Windows.Forms.Clipboard.ContainsImage() ||
  235. System.Windows.Forms.Clipboard.ContainsData(DataFormats.EnhancedMetafile);
  236. }
  237. catch (ExternalException)
  238. {
  239. return false;
  240. }
  241. }
  242. public static Font CreateFont(string name, float size, FontStyle style)
  243. {
  244. Font returnFont;
  245. try
  246. {
  247. returnFont = new Font(name, size, style);
  248. }
  249. catch (Exception)
  250. {
  251. returnFont = new Font(FontFamily.GenericSansSerif, size);
  252. }
  253. return returnFont;
  254. }
  255. public static Font CreateFont(string name, float size, string backupName, float backupSize, FontStyle style)
  256. {
  257. Font returnFont;
  258. try
  259. {
  260. returnFont = new Font(name, size, style);
  261. }
  262. catch (Exception)
  263. {
  264. returnFont = CreateFont(backupName, backupSize, style);
  265. }
  266. return returnFont;
  267. }
  268. public static readonly Color TransparentKey = Color.FromArgb(192, 192, 192);
  269. public static string WebExceptionToErrorMessage(WebException wex)
  270. {
  271. string errorMessage;
  272. switch (wex.Status)
  273. {
  274. case WebExceptionStatus.ProtocolError:
  275. string format = PdnResources.GetString("WebExceptionStatus.ProtocolError.Format");
  276. HttpStatusCode statusCode = ((HttpWebResponse)wex.Response).StatusCode;
  277. errorMessage = string.Format(format, statusCode.ToString(), (int)statusCode);
  278. break;
  279. default:
  280. string stringName = "WebExceptionStatus." + wex.Status.ToString();
  281. errorMessage = PdnResources.GetString(stringName);
  282. break;
  283. }
  284. return errorMessage;
  285. }
  286. private static bool allowGCFullCollect = true;
  287. public static bool AllowGCFullCollect
  288. {
  289. get
  290. {
  291. return allowGCFullCollect;
  292. }
  293. set
  294. {
  295. allowGCFullCollect = value;
  296. }
  297. }
  298. public static void GCFullCollect()
  299. {
  300. if (AllowGCFullCollect)
  301. {
  302. GC.Collect();
  303. GC.WaitForPendingFinalizers();
  304. GC.Collect();
  305. GC.WaitForPendingFinalizers();
  306. }
  307. }
  308. private static int defaultSimplificationFactor = 50;
  309. public static int DefaultSimplificationFactor
  310. {
  311. get
  312. {
  313. return defaultSimplificationFactor;
  314. }
  315. set
  316. {
  317. defaultSimplificationFactor = value;
  318. }
  319. }
  320. public static bool IsArrowKey(Keys keyData)
  321. {
  322. Keys key = keyData & Keys.KeyCode;
  323. if (key == Keys.Up || key == Keys.Down || key == Keys.Left || key == Keys.Right)
  324. {
  325. return true;
  326. }
  327. else
  328. {
  329. return false;
  330. }
  331. }
  332. public static bool DoesControlHaveMouseCaptured(Control control)
  333. {
  334. bool result = false;
  335. result |= control.Capture;
  336. foreach (Control c in control.Controls)
  337. {
  338. result |= DoesControlHaveMouseCaptured(c);
  339. }
  340. return result;
  341. }
  342. public static void SplitRectangle(Rectangle rect, Rectangle[] rects)
  343. {
  344. int height = rect.Height;
  345. for (int i = 0; i < rects.Length; ++i)
  346. {
  347. Rectangle newRect = Rectangle.FromLTRB(rect.Left,
  348. rect.Top + ((height * i) / rects.Length),
  349. rect.Right,
  350. rect.Top + ((height * (i + 1)) / rects.Length));
  351. rects[i] = newRect;
  352. }
  353. }
  354. public static long TicksToMs(long ticks)
  355. {
  356. return ticks / 10000;
  357. }
  358. public static string GetStaticName(Type type)
  359. {
  360. PropertyInfo pi = type.GetProperty("StaticName", BindingFlags.Static | BindingFlags.Public | BindingFlags.GetProperty);
  361. return (string)pi.GetValue(null, null);
  362. }
  363. public static readonly float[][] Identity5x5F = new float[][] {
  364. new float[] { 1, 0, 0, 0, 0 },
  365. new float[] { 0, 1, 0, 0, 0 },
  366. new float[] { 0, 0, 1, 0, 0 },
  367. new float[] { 0, 0, 0, 1, 0 },
  368. new float[] { 0, 0, 0, 0, 1 }
  369. };
  370. public static readonly ColorMatrix IdentityColorMatrix = new ColorMatrix(Identity5x5F);
  371. [ThreadStatic]
  372. private static Matrix identityMatrix = null;
  373. public static Matrix IdentityMatrix
  374. {
  375. get
  376. {
  377. if (identityMatrix == null)
  378. {
  379. identityMatrix = new Matrix();
  380. identityMatrix.Reset();
  381. }
  382. return identityMatrix;
  383. }
  384. }
  385. /// <summary>
  386. /// Rounds an integer to the smallest power of 2 that is greater
  387. /// than or equal to it.
  388. /// </summary>
  389. public static int Log2RoundUp(int x)
  390. {
  391. if (x == 0)
  392. {
  393. return 1;
  394. }
  395. if (x == 1)
  396. {
  397. return 1;
  398. }
  399. return 1 << (1 + HighestBit(x - 1));
  400. }
  401. private static int HighestBit(int x)
  402. {
  403. if (x == 0)
  404. {
  405. return 0;
  406. }
  407. int b = 0;
  408. int hi = 0;
  409. while (b <= 30)
  410. {
  411. if ((x & (1 << b)) != 0)
  412. {
  413. hi = b;
  414. }
  415. ++b;
  416. }
  417. return hi;
  418. }
  419. private int CountBits(int x)
  420. {
  421. uint y = (uint)x;
  422. int count = 0;
  423. for (int bit = 0; bit < 32; ++bit)
  424. {
  425. if ((y & ((uint)1 << bit)) != 0)
  426. {
  427. ++count;
  428. }
  429. }
  430. return count;
  431. }
  432. public static string RemoveSpaces(string s)
  433. {
  434. StringBuilder sb = new StringBuilder();
  435. foreach (char c in s)
  436. {
  437. if (!char.IsWhiteSpace(c))
  438. {
  439. sb.Append(c);
  440. }
  441. }
  442. return sb.ToString();
  443. }
  444. public static int Max(int[,] array)
  445. {
  446. int max = int.MinValue;
  447. for (int i = array.GetLowerBound(0); i <= array.GetUpperBound(0); ++i)
  448. {
  449. for (int j = array.GetLowerBound(1); j <= array.GetUpperBound(1); ++j)
  450. {
  451. if (array[i,j] > max)
  452. {
  453. max = array[i,j];
  454. }
  455. }
  456. }
  457. return max;
  458. }
  459. public static int Sum(int[][] array)
  460. {
  461. int sum = 0;
  462. for (int i = 0; i < array.Length; ++i)
  463. {
  464. int[] row = array[i];
  465. for (int j = 0; j < row.Length; ++j)
  466. {
  467. sum += row[j];
  468. }
  469. }
  470. return sum;
  471. }
  472. // TODO: obsolete these NUD funcitons, move them into PdnNumericUpDown
  473. public static void ClipNumericUpDown(NumericUpDown upDown)
  474. {
  475. if (upDown.Value < upDown.Minimum)
  476. {
  477. upDown.Value = upDown.Minimum;
  478. }
  479. else if (upDown.Value > upDown.Maximum)
  480. {
  481. upDown.Value = upDown.Maximum;
  482. }
  483. }
  484. public static bool GetUpDownValueFromText(NumericUpDown nud, out double val)
  485. {
  486. if (nud.Text == string.Empty)
  487. {
  488. val = 0;
  489. return false;
  490. }
  491. else
  492. {
  493. try
  494. {
  495. if (nud.DecimalPlaces == 0)
  496. {
  497. val = (double)int.Parse(nud.Text);
  498. }
  499. else
  500. {
  501. val = double.Parse(nud.Text);
  502. }
  503. }
  504. catch
  505. {
  506. val = 0;
  507. return false;
  508. }
  509. return true;
  510. }
  511. }
  512. public static bool CheckNumericUpDown(NumericUpDown upDown)
  513. {
  514. int a;
  515. bool result = int.TryParse(upDown.Text, out a);
  516. if (result && (a <= (int)upDown.Maximum) && (a >= (int)upDown.Minimum))
  517. {
  518. return true;
  519. }
  520. else
  521. {
  522. return false;
  523. }
  524. }
  525. public static void SetNumericUpDownValue(NumericUpDown upDown, decimal newValue)
  526. {
  527. if (upDown.Value != newValue)
  528. {
  529. upDown.Value = newValue;
  530. }
  531. }
  532. public static void SetNumericUpDownValue(NumericUpDown upDown, int newValue)
  533. {
  534. SetNumericUpDownValue(upDown, (decimal)newValue);
  535. }
  536. public static string SizeStringFromBytes(long bytes)
  537. {
  538. double bytesDouble = (double)bytes;
  539. string toStringFormat;
  540. string formatString;
  541. if (bytesDouble > (1024 * 1024 * 1024))
  542. {
  543. // Gigs
  544. bytesDouble /= 1024 * 1024 * 1024;
  545. toStringFormat = "F1";
  546. formatString = PdnResources.GetString("Utility.SizeStringFromBytes.GBFormat");
  547. }
  548. else if (bytesDouble > (1024 * 1024))
  549. {
  550. // Megs
  551. bytesDouble /= 1024 * 1024;
  552. toStringFormat = "F1";
  553. formatString = PdnResources.GetString("Utility.SizeStringFromBytes.MBFormat");
  554. }
  555. else if (bytesDouble > (1024))
  556. {
  557. // K
  558. bytesDouble /= 1024;
  559. toStringFormat = "F1";
  560. formatString = PdnResources.GetString("Utility.SizeStringFromBytes.KBFormat");
  561. }
  562. else
  563. {
  564. // Bytes
  565. toStringFormat = "F0";
  566. formatString = PdnResources.GetString("Utility.SizeStringFromBytes.BytesFormat");
  567. }
  568. string bytesString = bytesDouble.ToString(toStringFormat);
  569. string sizeString = string.Format(formatString, bytesString);
  570. return sizeString;
  571. }
  572. public static void ShowWiaError(IWin32Window owner)
  573. {
  574. // WIA requires Windows XP SP1 or later, or Windows Server 2003
  575. // So if we know they're on WS2k3, we tell them to enable WIA.
  576. // If they're on XP or later, tell them that WIA isn't available.
  577. // Otherwise we tell them they need XP SP1 (for the Win2K folks).
  578. if (OS.Type == OSType.Server)
  579. {
  580. Utility.ErrorBox(owner, PdnResources.GetString("WIA.Error.EnableMe"));
  581. }
  582. else
  583. {
  584. Utility.ErrorBox(owner, PdnResources.GetString("WIA.Error.UnableToLoad"));
  585. }
  586. }
  587. public static void ShowNonAdminErrorBox(IWin32Window parent)
  588. {
  589. ErrorBox(parent, PdnResources.GetString("NonAdminErrorBox.Message"));
  590. }
  591. public static void ErrorBox(IWin32Window parent, string message)
  592. {
  593. MessageBox.Show(parent, message, PdnInfo.GetBareProductName(), MessageBoxButtons.OK, MessageBoxIcon.Error);
  594. }
  595. public static DialogResult ErrorBoxOKCancel(IWin32Window parent, string message)
  596. {
  597. return MessageBox.Show(parent, message, PdnInfo.GetBareProductName(), MessageBoxButtons.OKCancel, MessageBoxIcon.Error);
  598. }
  599. public static void InfoBox(IWin32Window parent, string message)
  600. {
  601. MessageBox.Show(parent, message, PdnInfo.GetBareProductName(), MessageBoxButtons.OK, MessageBoxIcon.Information);
  602. }
  603. public static DialogResult InfoBoxOKCancel(IWin32Window parent, string message)
  604. {
  605. return MessageBox.Show(parent, message, PdnInfo.GetBareProductName(), MessageBoxButtons.OKCancel, MessageBoxIcon.Information);
  606. }
  607. public static DialogResult AskOKCancel(IWin32Window parent, string question)
  608. {
  609. return MessageBox.Show(parent, question, PdnInfo.GetBareProductName(), MessageBoxButtons.OKCancel, MessageBoxIcon.Question);
  610. }
  611. public static DialogResult AskYesNo(IWin32Window parent, string question)
  612. {
  613. return MessageBox.Show(parent, question, PdnInfo.GetBareProductName(), MessageBoxButtons.YesNo, MessageBoxIcon.Question);
  614. }
  615. public static DialogResult AskYesNoCancel(IWin32Window parent, string question)
  616. {
  617. return MessageBox.Show(parent, question, PdnInfo.GetBareProductName(), MessageBoxButtons.YesNoCancel, MessageBoxIcon.Question);
  618. }
  619. public static Icon ImageToIcon(Image image)
  620. {
  621. return ImageToIcon(image, Utility.TransparentKey);
  622. }
  623. public static Icon ImageToIcon(Image image, bool disposeImage)
  624. {
  625. return ImageToIcon(image, Utility.TransparentKey, disposeImage);
  626. }
  627. public static Icon ImageToIcon(Image image, Color seeThru)
  628. {
  629. return ImageToIcon(image, seeThru, false);
  630. }
  631. /// <summary>
  632. /// Converts an Image to an Icon.
  633. /// </summary>
  634. /// <param name="image">The Image to convert to an icon. Must be an appropriate icon size (32x32, 16x16, etc).</param>
  635. /// <param name="seeThru">The color that will be treated as transparent in the icon.</param>
  636. /// <param name="disposeImage">Whether or not to dispose the passed-in Image.</param>
  637. /// <returns>An Icon representation of the Image.</returns>
  638. public static Icon ImageToIcon(Image image, Color seeThru, bool disposeImage)
  639. {
  640. Bitmap bitmap = new Bitmap(image);
  641. for (int y = 0; y < bitmap.Height; ++y)
  642. {
  643. for (int x = 0; x < bitmap.Width; ++x)
  644. {
  645. if (bitmap.GetPixel(x, y) == seeThru)
  646. {
  647. bitmap.SetPixel(x, y, Color.FromArgb(0));
  648. }
  649. }
  650. }
  651. Icon icon = Icon.FromHandle(bitmap.GetHicon());
  652. bitmap.Dispose();
  653. if (disposeImage)
  654. {
  655. image.Dispose();
  656. }
  657. return icon;
  658. }
  659. public static Icon BitmapToIcon(Bitmap bitmap, bool disposeBitmap)
  660. {
  661. Icon icon = Icon.FromHandle(bitmap.GetHicon());
  662. if (disposeBitmap)
  663. {
  664. bitmap.Dispose();
  665. }
  666. return icon;
  667. }
  668. public static Icon SurfaceToIcon(Surface surface, bool disposeSurface)
  669. {
  670. Bitmap bitmap = surface.CreateAliasedBitmap();
  671. Icon icon = Icon.FromHandle(bitmap.GetHicon());
  672. bitmap.Dispose();
  673. if (disposeSurface)
  674. {
  675. surface.Dispose();
  676. }
  677. return icon;
  678. }
  679. public static Point GetRectangleCenter(Rectangle rect)
  680. {
  681. return new Point((rect.Left + rect.Right) / 2, (rect.Top + rect.Bottom) / 2);
  682. }
  683. public static PointF GetRectangleCenter(RectangleF rect)
  684. {
  685. return new PointF((rect.Left + rect.Right) / 2, (rect.Top + rect.Bottom) / 2);
  686. }
  687. public static Scanline[] GetRectangleScans(Rectangle rect)
  688. {
  689. Scanline[] scans = new Scanline[rect.Height];
  690. for (int y = 0; y < rect.Height; ++y)
  691. {
  692. scans[y] = new Scanline(rect.X, rect.Y + y, rect.Width);
  693. }
  694. return scans;
  695. }
  696. public static Scanline[] GetRegionScans(Rectangle[] region)
  697. {
  698. int scanCount = 0;
  699. for (int i = 0; i < region.Length; ++i)
  700. {
  701. scanCount += region[i].Height;
  702. }
  703. Scanline[] scans = new Scanline[scanCount];
  704. int scanIndex = 0;
  705. foreach (Rectangle rect in region)
  706. {
  707. for (int y = 0; y < rect.Height; ++y)
  708. {
  709. scans[scanIndex] = new Scanline(rect.X, rect.Y + y, rect.Width);
  710. ++scanIndex;
  711. }
  712. }
  713. return scans;
  714. }
  715. public static Rectangle[] ScanlinesToRectangles(Scanline[] scans)
  716. {
  717. return ScanlinesToRectangles(scans, 0, scans.Length);
  718. }
  719. public static Rectangle[] ScanlinesToRectangles(Scanline[] scans, int startIndex, int length)
  720. {
  721. Rectangle[] rects = new Rectangle[length];
  722. for (int i = 0; i < length; ++i)
  723. {
  724. Scanline scan = scans[i + startIndex];
  725. rects[i] = new Rectangle(scan.X, scan.Y, scan.Length, 1);
  726. }
  727. return rects;
  728. }
  729. /// <summary>
  730. /// Found on Google Groups when searching for "Region.Union" while looking
  731. /// for bugs:
  732. /// ---
  733. /// Hello,
  734. ///
  735. /// I did not run your code, but I know Region.Union is flawed in both 1.0 and
  736. /// 1.1, so I assume it is in the gdi+ unmanged code dll. The best workaround,
  737. /// in terms of speed, is to use a PdnGraphicsPath, but it must be a path with
  738. /// FillMode = FillMode.Winding. You add the rectangles to the path, then you do
  739. /// union onto an empty region with the path. The important point is to do only
  740. /// one union call on a given empty region. We created a "super region" object
  741. /// to hide all these bugs and optimize clipping operations. In fact, it is much
  742. /// faster to use the path than to call Region.Union for each rectangle.
  743. ///
  744. /// Too bad about Region.Union. A lot of people will hit this bug, as it is
  745. /// essential in high-performance animation.
  746. ///
  747. /// Regards,
  748. /// Frank Hileman
  749. /// Prodige Software Corporation
  750. /// ---
  751. /// </summary>
  752. /// <param name="rectsF"></param>
  753. /// <param name="startIndex"></param>
  754. /// <param name="length"></param>
  755. /// <returns></returns>
  756. public static PdnRegion RectanglesToRegion(RectangleF[] rectsF, int startIndex, int length)
  757. {
  758. PdnRegion region;
  759. if (rectsF == null || rectsF.Length == 0 || length == 0)
  760. {
  761. region = PdnRegion.CreateEmpty();
  762. }
  763. else
  764. {
  765. using (PdnGraphicsPath path = new PdnGraphicsPath())
  766. {
  767. path.FillMode = FillMode.Winding;
  768. if (startIndex == 0 && length == rectsF.Length)
  769. {
  770. path.AddRectangles(rectsF);
  771. }
  772. else
  773. {
  774. for (int i = startIndex; i < startIndex + length; ++i)
  775. {
  776. path.AddRectangle(rectsF[i]);
  777. }
  778. }
  779. region = new PdnRegion(path);
  780. }
  781. }
  782. return region;
  783. }
  784. public static PdnRegion RectanglesToRegion(RectangleF[] rectsF)
  785. {
  786. return RectanglesToRegion(rectsF, 0, rectsF != null ? rectsF.Length : 0);
  787. }
  788. public static PdnRegion RectanglesToRegion(RectangleF[] rectsF1, RectangleF[] rectsF2, params RectangleF[][] rectsFA)
  789. {
  790. using (PdnGraphicsPath path = new PdnGraphicsPath())
  791. {
  792. path.FillMode = FillMode.Winding;
  793. if (rectsF1 != null && rectsF1.Length > 0)
  794. {
  795. path.AddRectangles(rectsF1);
  796. }
  797. if (rectsF2 != null && rectsF2.Length > 0)
  798. {
  799. path.AddRectangles(rectsF2);
  800. }
  801. foreach (RectangleF[] rectsF in rectsFA)
  802. {
  803. if (rectsF != null && rectsF.Length > 0)
  804. {
  805. path.AddRectangles(rectsF);
  806. }
  807. }
  808. return new PdnRegion(path);
  809. }
  810. }
  811. public static PdnRegion RectanglesToRegion(Rectangle[] rects, int startIndex, int length)
  812. {
  813. PdnRegion region;
  814. if (length == 0)
  815. {
  816. region = PdnRegion.CreateEmpty();
  817. }
  818. else
  819. {
  820. using (PdnGraphicsPath path = new PdnGraphicsPath())
  821. {
  822. path.FillMode = FillMode.Winding;
  823. if (startIndex == 0 && length == rects.Length)
  824. {
  825. path.AddRectangles(rects);
  826. }
  827. else
  828. {
  829. for (int i = startIndex; i < startIndex + length; ++i)
  830. {
  831. path.AddRectangle(rects[i]);
  832. }
  833. }
  834. region = new PdnRegion(path);
  835. path.Dispose();
  836. }
  837. }
  838. return region;
  839. }
  840. public static PdnRegion RectanglesToRegion(Rectangle[] rects)
  841. {
  842. return RectanglesToRegion(rects, 0, rects.Length);
  843. }
  844. public static int GetRegionArea(RectangleF[] rectsF)
  845. {
  846. int area = 0;
  847. foreach (RectangleF rectF in rectsF)
  848. {
  849. Rectangle rect = Rectangle.Truncate(rectF);
  850. area += rect.Width * rect.Height;
  851. }
  852. return area;
  853. }
  854. public static RectangleF RectangleFromCenter(PointF center, float halfSize)
  855. {
  856. RectangleF ret = new RectangleF(center.X, center.Y, 0, 0);
  857. ret.Inflate(halfSize, halfSize);
  858. return ret;
  859. }
  860. public static List<PointF> PointListToPointFList(List<Point> ptList)
  861. {
  862. List<PointF> ret = new List<PointF>(ptList.Count);
  863. for (int i = 0; i < ptList.Count; ++i)
  864. {
  865. ret.Add((PointF)ptList[i]);
  866. }
  867. return ret;
  868. }
  869. public static PointF[] PointArrayToPointFArray(Point[] ptArray)
  870. {
  871. PointF[] ret = new PointF[ptArray.Length];
  872. for (int i = 0; i < ret.Length; ++i)
  873. {
  874. ret[i] = (PointF)ptArray[i];
  875. }
  876. return ret;
  877. }
  878. public static Rectangle[] InflateRectangles(Rectangle[] rects, int amount)
  879. {
  880. Rectangle[] inflated = new Rectangle[rects.Length];
  881. for (int i = 0; i < rects.Length; ++i)
  882. {
  883. inflated[i] = Rectangle.Inflate(rects[i], amount, amount);
  884. }
  885. return inflated;
  886. }
  887. public static void InflateRectanglesInPlace(Rectangle[] rects, int amount)
  888. {
  889. for (int i = 0; i < rects.Length; ++i)
  890. {
  891. rects[i].Inflate(amount, amount);
  892. }
  893. }
  894. public static RectangleF[] InflateRectangles(RectangleF[] rectsF, int amount)
  895. {
  896. RectangleF[] inflated = new RectangleF[rectsF.Length];
  897. for (int i = 0; i < rectsF.Length; ++i)
  898. {
  899. inflated[i] = RectangleF.Inflate(rectsF[i], amount, amount);
  900. }
  901. return inflated;
  902. }
  903. public static void InflateRectanglesInPlace(RectangleF[] rectsF, float amount)
  904. {
  905. for (int i = 0; i < rectsF.Length; ++i)
  906. {
  907. rectsF[i].Inflate(amount, amount);
  908. }
  909. }
  910. public static Rectangle PointsToConstrainedRectangle(Point a, Point b)
  911. {
  912. Rectangle rect = Utility.PointsToRectangle(a, b);
  913. int minWH = Math.Min(rect.Width, rect.Height);
  914. rect.Width = minWH;
  915. rect.Height = minWH;
  916. if (rect.Y != a.Y)
  917. {
  918. rect.Location = new Point(rect.X, a.Y - minWH);
  919. }
  920. if (rect.X != a.X)
  921. {
  922. rect.Location = new Point(a.X - minWH, rect.Y);
  923. }
  924. return rect;
  925. }
  926. public static RectangleF PointsToConstrainedRectangle(PointF a, PointF b)
  927. {
  928. RectangleF rect = Utility.PointsToRectangle(a, b);
  929. float minWH = Math.Min(rect.Width, rect.Height);
  930. rect.Width = minWH;
  931. rect.Height = minWH;
  932. if (rect.Y != a.Y)
  933. {
  934. rect.Location = new PointF(rect.X, a.Y - minWH);
  935. }
  936. if (rect.X != a.X)
  937. {
  938. rect.Location = new PointF(a.X - minWH, rect.Y);
  939. }
  940. return rect;
  941. }
  942. /// <summary>
  943. /// Takes two points and creates a bounding rectangle from them.
  944. /// </summary>
  945. /// <param name="a">One corner of the rectangle.</param>
  946. /// <param name="b">The other corner of the rectangle.</param>
  947. /// <returns>A Rectangle instance that bounds the two points.</returns>
  948. public static Rectangle PointsToRectangle(Point a, Point b)
  949. {
  950. int x = Math.Min(a.X, b.X);
  951. int y = Math.Min(a.Y, b.Y);
  952. int width = Math.Abs(a.X - b.X) + 1;
  953. int height = Math.Abs(a.Y - b.Y) + 1;
  954. return new Rectangle(x, y, width, height);
  955. }
  956. public static RectangleF PointsToRectangle(PointF a, PointF b)
  957. {
  958. float x = Math.Min(a.X, b.X);
  959. float y = Math.Min(a.Y, b.Y);
  960. float width = Math.Abs(a.X - b.X) + 1;
  961. float height = Math.Abs(a.Y - b.Y) + 1;
  962. return new RectangleF(x, y, width, height);
  963. }
  964. public static Rectangle PointsToRectangleExclusive(Point a, Point b)
  965. {
  966. int x = Math.Min(a.X, b.X);
  967. int y = Math.Min(a.Y, b.Y);
  968. int width = Math.Abs(a.X - b.X);
  969. int height = Math.Abs(a.Y - b.Y);
  970. return new Rectangle(x, y, width, height);
  971. }
  972. public static RectangleF PointsToRectangleExclusive(PointF a, PointF b)
  973. {
  974. float x = Math.Min(a.X, b.X);
  975. float y = Math.Min(a.Y, b.Y);
  976. float width = Math.Abs(a.X - b.X);
  977. float height = Math.Abs(a.Y - b.Y);
  978. return new RectangleF(x, y, width, height);
  979. }
  980. public static RectangleF[] PointsToRectangles(PointF[] pointsF)
  981. {
  982. if (pointsF.Length == 0)
  983. {
  984. return new RectangleF[] { };
  985. }
  986. if (pointsF.Length == 1)
  987. {
  988. return new RectangleF[] { new RectangleF(pointsF[0].X, pointsF[0].Y, 1, 1) };
  989. }
  990. RectangleF[] rectsF = new RectangleF[pointsF.Length - 1];
  991. for (int i = 0; i < pointsF.Length - 1; ++i)
  992. {
  993. rectsF[i] = PointsToRectangle(pointsF[i], pointsF[i + 1]);
  994. }
  995. return rectsF;
  996. }
  997. public static Rectangle[] PointsToRectangles(Point[] points)
  998. {
  999. if (points.Length == 0)
  1000. {
  1001. return new Rectangle[] { };
  1002. }
  1003. if (points.Length == 1)
  1004. {
  1005. return new Rectangle[] { new Rectangle(points[0].X, points[0].Y, 1, 1) };
  1006. }
  1007. Rectangle[] rects = new Rectangle[points.Length - 1];
  1008. for (int i = 0; i < points.Length - 1; ++i)
  1009. {
  1010. rects[i] = PointsToRectangle(points[i], points[i + 1]);
  1011. }
  1012. return rects;
  1013. }
  1014. /// <summary>
  1015. /// Converts a RectangleF to RectangleF by rounding down the Location and rounding
  1016. /// up the Size.
  1017. /// </summary>
  1018. public static Rectangle RoundRectangle(RectangleF rectF)
  1019. {
  1020. float left = (float)Math.Floor(rectF.Left);
  1021. float top = (float)Math.Floor(rectF.Top);
  1022. float right = (float)Math.Ceiling(rectF.Right);
  1023. float bottom = (float)Math.Ceiling(rectF.Bottom);
  1024. return Rectangle.Truncate(RectangleF.FromLTRB(left, top, right, bottom));
  1025. }
  1026. public static Stack Reverse(Stack reverseMe)
  1027. {
  1028. Stack reversed = new Stack();
  1029. foreach (object o in reverseMe)
  1030. {
  1031. reversed.Push(o);
  1032. }
  1033. return reversed;
  1034. }
  1035. public static void SerializeObjectToStream(object graph, Stream stream)
  1036. {
  1037. new BinaryFormatter().Serialize(stream, graph);
  1038. }
  1039. public static object DeserializeObjectFromStream(Stream stream)
  1040. {
  1041. return new BinaryFormatter().Deserialize(stream);
  1042. }
  1043. [Obsolete("Use rect.Contains() instead", true)]
  1044. public static bool IsPointInRectangle(Point pt, Rectangle rect)
  1045. {
  1046. return rect.Contains(pt);
  1047. }
  1048. [Obsolete("Use rect.Contains() instead", true)]
  1049. public static bool IsPointInRectangle(int x, int y, Rectangle rect)
  1050. {
  1051. return rect.Contains(x, y);
  1052. }
  1053. public static Bitmap FullCloneBitmap(Bitmap cloneMe)
  1054. {
  1055. Bitmap bitmap = new Bitmap(cloneMe.Width, cloneMe.Height, cloneMe.PixelFormat);
  1056. using (Graphics g = Graphics.FromImage(bitmap))
  1057. {
  1058. g.DrawImage(cloneMe, 0, 0, cloneMe.Width, cloneMe.Height);
  1059. }
  1060. return bitmap;
  1061. }
  1062. /// <summary>
  1063. /// Allows you to find the bounding box for a Region object without requiring
  1064. /// the presence of a Graphics object.
  1065. /// (Region.GetBounds takes a Graphics instance as its only parameter.)
  1066. /// </summary>
  1067. /// <param name="region">The region you want to find a bounding box for.</param>
  1068. /// <returns>A RectangleF structure that surrounds the Region.</returns>
  1069. public static Rectangle GetRegionBounds(PdnRegion region)
  1070. {
  1071. Rectangle[] rects = region.GetRegionScansReadOnlyInt();
  1072. return GetRegionBounds(rects, 0, rects.Length);
  1073. }
  1074. /// <summary>
  1075. /// Allows you to find the bounding box for a "region" that is described as an
  1076. /// array of bounding boxes.
  1077. /// </summary>
  1078. /// <param name="rectsF">The "region" you want to find a bounding box for.</param>
  1079. /// <returns>A RectangleF structure that surrounds the Region.</returns>
  1080. public static RectangleF GetRegionBounds(RectangleF[] rectsF, int startIndex, int length)
  1081. {
  1082. if (rectsF.Length == 0)
  1083. {
  1084. return RectangleF.Empty;
  1085. }
  1086. float left = rectsF[startIndex].Left;
  1087. float top = rectsF[startIndex].Top;
  1088. float right = rectsF[startIndex].Right;
  1089. float bottom = rectsF[startIndex].Bottom;
  1090. for (int i = startIndex + 1; i < startIndex + length; ++i)
  1091. {
  1092. RectangleF rectF = rectsF[i];
  1093. if (rectF.Left < left)
  1094. {
  1095. left = rectF.Left;
  1096. }
  1097. if (rectF.Top < top)
  1098. {
  1099. top = rectF.Top;
  1100. }
  1101. if (rectF.Right > right)
  1102. {
  1103. right = rectF.Right;
  1104. }
  1105. if (rectF.Bottom > bottom)
  1106. {
  1107. bottom = rectF.Bottom;
  1108. }
  1109. }
  1110. return RectangleF.FromLTRB(left, top, right, bottom);
  1111. }
  1112. public static RectangleF GetTraceBounds(PointF[] pointsF, int startIndex, int length)
  1113. {
  1114. if (pointsF.Length == 0)
  1115. {
  1116. return RectangleF.Empty;
  1117. }
  1118. float left = pointsF[startIndex].X;
  1119. float top = pointsF[startIndex].Y;
  1120. float right = 1 + pointsF[startIndex].X;
  1121. float bottom = 1 + pointsF[startIndex].Y;
  1122. for (int i = startIndex + 1; i < startIndex + length; ++i)
  1123. {
  1124. PointF pointF = pointsF[i];
  1125. if (pointF.X < left)
  1126. {
  1127. left = pointF.X;
  1128. }
  1129. if (pointF.Y < top)
  1130. {
  1131. top = pointF.Y;
  1132. }
  1133. if (pointF.X > right)
  1134. {
  1135. right = pointF.X;
  1136. }
  1137. if (pointF.Y > bottom)
  1138. {
  1139. bottom = pointF.Y;
  1140. }
  1141. }
  1142. return RectangleF.FromLTRB(left, top, right, bottom);
  1143. }
  1144. public static Rectangle GetTraceBounds(Point[] points, int startIndex, int length)
  1145. {
  1146. if (points.Length == 0)
  1147. {
  1148. return Rectangle.Empty;
  1149. }
  1150. int left = points[startIndex].X;
  1151. int top = points[startIndex].Y;
  1152. int right = 1 + points[startIndex].X;
  1153. int bottom = 1 + points[startIndex].Y;
  1154. for (int i = startIndex + 1; i < startIndex + length; ++i)
  1155. {
  1156. Point point = points[i];
  1157. if (point.X < left)
  1158. {
  1159. left = point.X;
  1160. }
  1161. if (point.Y < top)
  1162. {
  1163. top = point.Y;
  1164. }
  1165. if (point.X > right)
  1166. {
  1167. right = point.X;
  1168. }
  1169. if (point.Y > bottom)
  1170. {
  1171. bottom = point.Y;
  1172. }
  1173. }
  1174. return Rectangle.FromLTRB(left, top, right, bottom);
  1175. }
  1176. /// <summary>
  1177. /// Allows you to find the bounding box for a "region" that is described as an
  1178. /// array of bounding boxes.
  1179. /// </summary>
  1180. /// <param name="rectsF">The "region" you want to find a bounding box for.</param>
  1181. /// <returns>A RectangleF structure that surrounds the Region.</returns>
  1182. public static Rectangle GetRegionBounds(Rectangle[] rects, int startIndex, int length)
  1183. {
  1184. if (rects.Length == 0)
  1185. {
  1186. return Rectangle.Empty;
  1187. }
  1188. int left = rects[startIndex].Left;
  1189. int top = rects[startIndex].Top;
  1190. int right = rects[startIndex].Right;
  1191. int bottom = rects[startIndex].Bottom;
  1192. for (int i = startIndex + 1; i < startIndex + length; ++i)
  1193. {
  1194. Rectangle rect = rects[i];
  1195. if (rect.Left < left)
  1196. {
  1197. left = rect.Left;
  1198. }
  1199. if (rect.Top < top)
  1200. {
  1201. top = rect.Top;
  1202. }
  1203. if (rect.Right > right)
  1204. {
  1205. right = rect.Right;
  1206. }
  1207. if (rect.Bottom > bottom)
  1208. {
  1209. bottom = rect.Bottom;
  1210. }
  1211. }
  1212. return Rectangle.FromLTRB(left, top, right, bottom);
  1213. }
  1214. public static RectangleF GetRegionBounds(RectangleF[] rectsF)
  1215. {
  1216. return GetRegionBounds(rectsF, 0, rectsF.Length);
  1217. }
  1218. public static Rectangle GetRegionBounds(Rectangle[] rects)
  1219. {
  1220. return GetRegionBounds(rects, 0, rects.Length);
  1221. }
  1222. private static float DistanceSquared(RectangleF[] rectsF, int indexA, int indexB)
  1223. {
  1224. PointF centerA = new PointF(rectsF[indexA].Left + (rectsF[indexA].Width / 2), rectsF[indexA].Top + (rectsF[indexA].Height / 2));
  1225. PointF centerB = new PointF(rectsF[indexB].Left + (rectsF[indexB].Width / 2), rectsF[indexB].Top + (rectsF[indexB].Height / 2));
  1226. return ((centerA.X - centerB.X) * (centerA.X - centerB.X)) +
  1227. ((centerA.Y - centerB.Y) * (centerA.Y - centerB.Y));
  1228. }
  1229. /// <summary>
  1230. /// Simplifies a Region into N number of bounding boxes.
  1231. /// </summary>
  1232. /// <param name="region">The Region to simplify.</param>
  1233. /// <param name="complexity">The maximum number of bounding boxes to return, or 0 for however many are necessary (equivalent to using Region.GetRegionScans).</param>
  1234. /// <returns></returns>
  1235. public static Rectangle[] SimplifyRegion(PdnRegion region, int complexity)
  1236. {
  1237. Rectangle[] rects = region.GetRegionScansReadOnlyInt();
  1238. return SimplifyRegion(rects, complexity);
  1239. }
  1240. public static Rectangle[] SimplifyRegion(Rectangle[] rects, int complexity)
  1241. {
  1242. if (complexity == 0 || rects.Length < complexity)
  1243. {
  1244. return (Rectangle[])rects.Clone();
  1245. }
  1246. Rectangle[] boxes = new Rectangle[complexity];
  1247. for (int i = 0; i < complexity; ++i)
  1248. {
  1249. int startIndex = (i * rects.Length) / complexity;
  1250. int length = Math.Min(rects.Length, ((i + 1) * rects.Length) / complexity) - startIndex;
  1251. boxes[i] = GetRegionBounds(rects, startIndex, length);
  1252. }
  1253. return boxes;
  1254. }
  1255. public static RectangleF[] SimplifyTrace(PointF[] pointsF, int complexity)
  1256. {
  1257. if (complexity == 0 ||
  1258. (pointsF.Length - 1) < complexity)
  1259. {
  1260. return PointsToRectangles(pointsF);
  1261. }
  1262. RectangleF[] boxes = new RectangleF[complexity];
  1263. int parLength = pointsF.Length - 1; // "(points as Rectangles).Length"
  1264. for (int i = 0; i < complexity; ++i)
  1265. {
  1266. int startIndex = (i * parLength) / complexity;
  1267. int length = Math.Min(parLength, ((i + 1) * parLength) / complexity) - startIndex;
  1268. boxes[i] = GetTraceBounds(pointsF, startIndex, length + 1);
  1269. }
  1270. return boxes;
  1271. }
  1272. public static Rectangle[] SimplifyTrace(PdnGraphicsPath trace, int complexity)
  1273. {
  1274. return SimplifyRegion(TraceToRectangles(trace), complexity);
  1275. }
  1276. public static Rectangle[] SimplifyTrace(PdnGraphicsPath trace)
  1277. {
  1278. return SimplifyTrace(trace, DefaultSimplificationFactor);
  1279. }
  1280. public static Rectangle[] TraceToRectangles(PdnGraphicsPath trace, int complexity)
  1281. {
  1282. int pointCount = trace.PointCount;
  1283. if (pointCount == 0)
  1284. {
  1285. return new Rectangle[0];
  1286. }
  1287. PointF[] pathPoints = trace.PathPoints;
  1288. byte[] pathTypes = trace.PathTypes;
  1289. int figureStart = 0;
  1290. // first get count of rectangles we'll need
  1291. Rectangle[] rects = new Rectangle[pointCount];
  1292. for (int i = 0; i < pointCount; ++i)
  1293. {
  1294. byte type = pathTypes[i];
  1295. Point a = Point.Truncate(pathPoints[i]);
  1296. Point b;
  1297. if ((type & (byte)PathPointType.CloseSubpath) != 0)
  1298. {
  1299. b = Point.Truncate(pathPoints[figureStart]);
  1300. figureStart = i + 1;
  1301. }
  1302. else
  1303. {
  1304. b = Point.Truncate(pathPoints[i + 1]);
  1305. }
  1306. rects[i] = Utility.PointsToRectangle(a, b);
  1307. }
  1308. return rects;
  1309. }
  1310. public static Rectangle[] TraceToRectangles(PdnGraphicsPath trace)
  1311. {
  1312. return TraceToRectangles(trace, DefaultSimplificationFactor);
  1313. }
  1314. public static RectangleF[] SimplifyTrace(PointF[] pointsF)
  1315. {
  1316. return SimplifyTrace(pointsF, defaultSimplificationFactor);
  1317. }
  1318. public static Rectangle[] SimplifyAndInflateRegion(Rectangle[] rects, int complexity, int inflationAmount)
  1319. {
  1320. Rectangle[] simplified = SimplifyRegion(rects, complexity);
  1321. for (int i = 0; i < simplified.Length; ++i)
  1322. {
  1323. simplified[i].Inflate(inflationAmount, inflationAmount);
  1324. }
  1325. return simplified;
  1326. }
  1327. public static Rectangle[] SimplifyAndInflateRegion(Rectangle[] rects)
  1328. {
  1329. return SimplifyAndInflateRegion(rects, defaultSimplificationFactor, 1);
  1330. }
  1331. public static PdnRegion SimplifyAndInflateRegion(PdnRegion region, int complexity, int inflationAmount)
  1332. {
  1333. Rectangle[] rectRegion = SimplifyRegion(region, complexity);
  1334. for (int i = 0; i < rectRegion.Length; ++i)
  1335. {
  1336. rectRegion[i].Inflate(inflationAmount, inflationAmount);
  1337. }
  1338. return RectanglesToRegion(rectRegion);
  1339. }
  1340. public static PdnRegion SimplifyAndInflateRegion(PdnRegion region)
  1341. {
  1342. return SimplifyAndInflateRegion(region, defaultSimplificationFactor, 1);
  1343. }
  1344. public static RectangleF[] TranslateRectangles(RectangleF[] rectsF, PointF offset)
  1345. {
  1346. RectangleF[] retRectsF = new RectangleF[rectsF.Length];
  1347. int i = 0;
  1348. foreach (RectangleF rectF in rectsF)
  1349. {
  1350. retRectsF[i] = new RectangleF(rectF.X + offset.X, rectF.Y + offset.Y, rectF.Width, rectF.Height);
  1351. ++i;
  1352. }
  1353. return retRectsF;
  1354. }
  1355. public static Rectangle[] TranslateRectangles(Rectangle[] rects, int dx, int dy)
  1356. {
  1357. Rectangle[] retRects = new Rectangle[rects.Length];
  1358. for (int i = 0; i < rects.Length; ++i)
  1359. {
  1360. retRects[i] = new Rectangle(rects[i].X + dx, rects[i].Y + dy, rects[i].Width, rects[i].Height);
  1361. }
  1362. return retRects;
  1363. }
  1364. public static void TranslatePointsInPlace(PointF[] ptsF, float dx, float dy)
  1365. {
  1366. for (int i = 0; i < ptsF.Length; ++i)
  1367. {
  1368. ptsF[i].X += dx;
  1369. ptsF[i].Y += dy;
  1370. }
  1371. }
  1372. public static void TranslatePointsInPlace(Point[] pts, int dx, int dy)
  1373. {
  1374. for (int i = 0; i < pts.Length; ++i)
  1375. {
  1376. pts[i].X += dx;
  1377. pts[i].Y += dy;
  1378. }
  1379. }
  1380. public static Rectangle[] TruncateRectangles(RectangleF[] rectsF)
  1381. {
  1382. Rectangle[] rects = new Rectangle[rectsF.Length];
  1383. for (int i = 0; i < rectsF.Length; ++i)
  1384. {
  1385. rects[i] = Rectangle.Truncate(rectsF[i]);
  1386. }
  1387. return rects;
  1388. }
  1389. public static Point[] TruncatePoints(PointF[] pointsF)
  1390. {
  1391. Point[] points = new Point[pointsF.Length];
  1392. for (int i = 0; i < pointsF.Length; ++i)
  1393. {
  1394. points[i] = Point.Truncate(pointsF[i]);
  1395. }
  1396. return points;
  1397. }
  1398. public static Point[] RoundPoints(PointF[] pointsF)
  1399. {
  1400. Point[] points = new Point[pointsF.Length];
  1401. for (int i = 0; i < pointsF.Length; ++i)
  1402. {
  1403. points[i] = Point.Round(pointsF[i]);
  1404. }
  1405. return points;
  1406. }
  1407. /// <summary>
  1408. /// The Sutherland-Hodgman clipping alrogithm.
  1409. /// http://ezekiel.vancouver.wsu.edu/~cs442/lectures/clip/clip/index.html
  1410. ///
  1411. /// # Clipping a convex polygon to a convex region (e.g., rectangle) will always produce a convex polygon (or no polygon if completely outside the clipping region).
  1412. /// # Clipping a concave polygon to a rectangle may produce several polygons (see figure above) or, as the following algorithm does, produce a single, possibly degenerate, polygon.
  1413. /// # Divide and conquer: Clip entire polygon against a single edge (i.e., half-plane). Repeat for each edge in the clipping region.
  1414. ///
  1415. /// The input is a sequence of vertices: {v0, v1, ... vn} given as an array of Points
  1416. /// the result is a sequence of vertices, given as an array of Points. This result may have
  1417. /// less than, equal, more than, or 0 vertices.
  1418. /// </summary>
  1419. /// <param name="vertices"></param>
  1420. /// <returns></returns>
  1421. public static List<PointF> SutherlandHodgman(RectangleF bounds, List<PointF> v)
  1422. {
  1423. List<PointF> p1 = SutherlandHodgmanOneAxis(bounds, RectangleEdge.Left, v);
  1424. List<PointF> p2 = SutherlandHodgmanOneAxis(bounds, RectangleEdge.Right, p1);
  1425. List<PointF> p3 = SutherlandHodgmanOneAxis(bounds, RectangleEdge.Top, p2);
  1426. List<PointF> p4 = SutherlandHodgmanOneAxis(bounds, RectangleEdge.Bottom, p3);
  1427. return p4;
  1428. }
  1429. private enum RectangleEdge
  1430. {
  1431. Left,
  1432. Right,
  1433. Top,
  1434. Bottom
  1435. }
  1436. private static List<PointF> SutherlandHodgmanOneAxis(RectangleF bounds, RectangleEdge edge, List<PointF> v)
  1437. {
  1438. if (v.Count == 0)
  1439. {
  1440. return new List<PointF>();
  1441. }
  1442. List<PointF> polygon = new List<PointF>();
  1443. PointF s = v[v.Count - 1];
  1444. for (int i = 0; i < v.Count; ++i)
  1445. {
  1446. PointF p = v[i];
  1447. bool pIn = IsInside(bounds, edge, p);
  1448. bool sIn = IsInside(bounds, edge, s);
  1449. if (sIn && pIn)
  1450. {
  1451. // case 1: inside -> inside
  1452. polygon.Add(p);
  1453. }
  1454. else if (sIn && !pIn)
  1455. {
  1456. // case 2: inside -> outside
  1457. polygon.Add(LineIntercept(bounds, edge, s, p));
  1458. }
  1459. else if (!sIn && !pIn)
  1460. {
  1461. // case 3: outside -> outside
  1462. // emit nothing
  1463. }
  1464. else if (!sIn && pIn)
  1465. {
  1466. // case 4: outside -> inside
  1467. polygon.Add(LineIntercept(bounds, edge, s, p));
  1468. polygon.Add(p);
  1469. }
  1470. s = p;
  1471. }
  1472. return polygon;
  1473. }
  1474. private static bool IsInside(RectangleF bounds, RectangleEdge edge, PointF p)
  1475. {
  1476. switch (edge)
  1477. {
  1478. case RectangleEdge.Left:
  1479. return !(p.X < bounds.Left);
  1480. case RectangleEdge.Right:
  1481. return !(p.X >= bounds.Right);
  1482. case RectangleEdge.Top:
  1483. return !(p.Y < bounds.Top);
  1484. case RectangleEdge.Bottom:
  1485. return !(p.Y >= bounds.Bottom);
  1486. default:
  1487. throw new InvalidEnumArgumentException("edge");
  1488. }
  1489. }
  1490. private static Point LineIntercept(Rectangle bounds, RectangleEdge edge, Point a, Point b)
  1491. {
  1492. if (a == b)
  1493. {
  1494. return a;
  1495. }
  1496. switch (edge)
  1497. {
  1498. case RectangleEdge.Bottom:
  1499. if (b.Y == a.Y)
  1500. {
  1501. throw new ArgumentException("no intercept found");
  1502. }
  1503. return new Point(a.X + (((b.X - a.X) * (bounds.Bottom - a.Y)) / (b.Y - a.Y)), bounds.Bottom);
  1504. case RectangleEdge.Left:
  1505. if (b.X == a.X)
  1506. {
  1507. throw new ArgumentException("no intercept found");
  1508. }
  1509. return new Point(bounds.Left, a.Y + (((b.Y - a.Y) * (bounds.Left - a.X)) / (b.X - a.X)));
  1510. case RectangleEdge.Right:
  1511. if (b.X == a.X)
  1512. {
  1513. throw new ArgumentException("no intercept found");
  1514. }
  1515. return new Point(bounds.Right, a.Y + (((b.Y - a.Y) * (bounds.Right - a.X)) / (b.X - a.X)));
  1516. case RectangleEdge.Top:
  1517. if (b.Y == a.Y)
  1518. {
  1519. throw new ArgumentException("no intercept found");
  1520. }
  1521. return new Point(a.X + (((b.X - a.X) * (bounds.Top - a.Y)) / (b.Y - a.Y)), bounds.Top);
  1522. }
  1523. throw new ArgumentException("no intercept found");
  1524. }
  1525. private static PointF LineIntercept(RectangleF bounds, RectangleEdge edge, PointF a, PointF b)
  1526. {
  1527. if (a == b)
  1528. {
  1529. return a;
  1530. }
  1531. switch (edge)
  1532. {
  1533. case RectangleEdge.Bottom:
  1534. if (b.Y == a.Y)
  1535. {
  1536. throw new ArgumentException("no intercept found");
  1537. }
  1538. return new PointF(a.X + (((b.X - a.X) * (bounds.Bottom - a.Y)) / (b.Y - a.Y)), bounds.Bottom);
  1539. case RectangleEdge.Left:
  1540. if (b.X == a.X)
  1541. {
  1542. throw new ArgumentException("no intercept found");
  1543. }
  1544. return new PointF(bounds.Left, a.Y + (((b.Y - a.Y) * (bounds.Left - a.X)) / (b.X - a.X)));
  1545. case RectangleEdge.Right:
  1546. if (b.X == a.X)
  1547. {
  1548. throw new ArgumentException("no intercept found");
  1549. }
  1550. return new PointF(bounds.Right, a.Y + (((b.Y - a.Y) * (bounds.Right - a.X)) / (b.X - a.X)));
  1551. case RectangleEdge.Top:
  1552. if (b.Y == a.Y)
  1553. {
  1554. throw new ArgumentException("no intercept found");
  1555. }
  1556. return new PointF(a.X + (((b.X - a.X) * (bounds.Top - a.Y)) / (b.Y - a.Y)), bounds.Top);
  1557. }
  1558. throw new ArgumentException("no intercept found");
  1559. }
  1560. public static Point[] GetLinePoints(Point first, Point second)
  1561. {
  1562. Point[] coords = null;
  1563. int x1 = first.X;
  1564. int y1 = first.Y;
  1565. int x2 = second.X;
  1566. int y2 = second.Y;
  1567. int dx = x2 - x1;
  1568. int dy = y2 - y1;
  1569. int dxabs = Math.Abs(dx);
  1570. int dyabs = Math.Abs(dy);
  1571. int px = x1;
  1572. int py = y1;
  1573. int sdx = Math.Sign(dx);
  1574. int sdy = Math.Sign(dy);
  1575. int x = 0;
  1576. int y = 0;
  1577. if (dxabs > dyabs)
  1578. {
  1579. coords = new Point[dxabs + 1];
  1580. for (int i = 0; i <= dxabs; i++)
  1581. {
  1582. y += dyabs;
  1583. if (y >= dxabs)
  1584. {
  1585. y -= dxabs;
  1586. py += sdy;
  1587. }
  1588. coords[i] = new Point(px, py);
  1589. px += sdx;
  1590. }
  1591. }
  1592. else
  1593. // had to add in this cludge for slopes of 1 ... wasn't drawing half the line
  1594. if (dxabs == dyabs)
  1595. {
  1596. coords = new Point[dxabs + 1];
  1597. for (int i = 0; i <= dxabs; i++)
  1598. {
  1599. coords[i] = new Point(px, py);
  1600. px += sdx;
  1601. py += sdy;
  1602. }
  1603. }
  1604. else
  1605. {
  1606. coords = new Point[dyabs + 1];
  1607. for (int i = 0; i <= dyabs; i++)
  1608. {
  1609. x += dxabs;
  1610. if (x >= dyabs)
  1611. {
  1612. x -= dyabs;
  1613. px += sdx;
  1614. }
  1615. coords[i] = new Point(px, py);
  1616. py += sdy;
  1617. }
  1618. }
  1619. return coords;
  1620. }
  1621. public static long GetTimeMs()
  1622. {
  1623. return Utility.TicksToMs(DateTime.Now.Ticks);
  1624. }
  1625. /// <summary>
  1626. /// Returns the Distance between two points
  1627. /// </summary>
  1628. public static float Distance(PointF a, PointF b)
  1629. {
  1630. return Magnitude(new PointF(a.X - b.X, a.Y - b.Y));
  1631. }
  1632. /// <summary>
  1633. /// Returns the Magnitude (distance to origin) of a point
  1634. /// </summary>
  1635. // TODO: In v4.0 codebase, turn this into an extension method
  1636. public static float Magnitude(PointF p)
  1637. {
  1638. return (float)Math.Sqrt(p.X * p.X + p.Y * p.Y);
  1639. }
  1640. // TODO: In v4.0 codebase, turn this into an extension method
  1641. public static double Clamp(double x, double min, double max)
  1642. {
  1643. if (x < min)
  1644. {
  1645. return min;
  1646. }
  1647. else if (x > max)
  1648. {
  1649. return max;
  1650. }
  1651. else
  1652. {
  1653. return x;
  1654. }
  1655. }
  1656. // TODO: In v4.0 codebase, turn this into an extension method
  1657. public static float Clamp(float x, float min, float max)
  1658. {
  1659. if (x < min)
  1660. {
  1661. return min;
  1662. }
  1663. else if (x > max)
  1664. {
  1665. return max;
  1666. }
  1667. else
  1668. {
  1669. return x;
  1670. }
  1671. }
  1672. // TODO: In v4.0 codebase, turn this into an extension method
  1673. public static int Clamp(int x, int min, int max)
  1674. {
  1675. if (x < min)
  1676. {
  1677. return min;
  1678. }
  1679. else if (x > max)
  1680. {
  1681. return max;
  1682. }
  1683. else
  1684. {
  1685. return x;
  1686. }
  1687. }
  1688. public static byte ClampToByte(double x)
  1689. {
  1690. if (x > 255)
  1691. {
  1692. return 255;
  1693. }
  1694. else if (x < 0)
  1695. {
  1696. return 0;
  1697. }
  1698. else
  1699. {
  1700. return (byte)x;
  1701. }
  1702. }
  1703. public static byte ClampToByte(float x)
  1704. {
  1705. if (x > 255)
  1706. {
  1707. return 255;
  1708. }
  1709. else if (x < 0)
  1710. {
  1711. return 0;
  1712. }
  1713. else
  1714. {
  1715. return (byte)x;
  1716. }
  1717. }
  1718. public static byte ClampToByte(int x)
  1719. {
  1720. if (x > 255)
  1721. {
  1722. return 255;
  1723. }
  1724. else if (x < 0)
  1725. {
  1726. return 0;
  1727. }
  1728. else
  1729. {
  1730. return (byte)x;
  1731. }
  1732. }
  1733. public static float Lerp(float from, float to, float frac)
  1734. {
  1735. return (from + frac * (to - from));
  1736. }
  1737. public static double Lerp(double from, double to, double frac)
  1738. {
  1739. return (from + frac * (to - from));
  1740. }
  1741. public static PointF Lerp(PointF from, PointF to, float frac)
  1742. {
  1743. return new PointF(Lerp(from.X, to.X, frac), Lerp(from.Y, to.Y, frac));
  1744. }
  1745. public static int ColorDifference(ColorBgra a, ColorBgra b)
  1746. {
  1747. return (int)Math.Ceiling(Math.Sqrt(ColorDifferenceSquared(a, b)));
  1748. }
  1749. public static int ColorDifferenceSquared(ColorBgra a, ColorBgra b)
  1750. {
  1751. int diffSq = 0, tmp;
  1752. tmp = a.R - b.R;
  1753. diffSq += tmp * tmp;
  1754. tmp = a.G - b.G;
  1755. diffSq += tmp * tmp;
  1756. tmp = a.B - b.B;
  1757. diffSq += tmp * tmp;
  1758. return diffSq / 3;
  1759. }
  1760. public static DialogResult ShowDialog(Form showMe, IWin32Window owner)
  1761. {
  1762. DialogResult dr;
  1763. if (showMe is PdnBaseForm)
  1764. {
  1765. PdnBaseForm showMe2 = (PdnBaseForm)showMe;
  1766. double oldOpacity = showMe2.Opacity;
  1767. showMe2.Opacity = 0.9;
  1768. dr = showMe2.ShowDialog(owner);
  1769. showMe2.Opacity = oldOpacity;
  1770. }
  1771. else
  1772. {
  1773. double oldOpacity = showMe.Opacity;
  1774. showMe.Opacity = 0.9;
  1775. dr = showMe.ShowDialog(owner);
  1776. showMe.Opacity = oldOpacity;
  1777. }
  1778. Control control = owner as Control;
  1779. if (control != null)
  1780. {
  1781. Form form = control.FindForm();
  1782. if (form != null)
  1783. {
  1784. form.Activate();
  1785. }
  1786. control.Update();
  1787. }
  1788. return dr;
  1789. }
  1790. public static void ShowHelp(Control parent)
  1791. {
  1792. string helpFileUrlFormat = PdnResources.GetString("HelpFile.Url.Format");
  1793. string baseSiteUrl = InvariantStrings.WebsiteUrl;
  1794. string helpFileUrl = string.Format(helpFileUrlFormat, baseSiteUrl);
  1795. PdnInfo.OpenUrl(parent, helpFileUrl);
  1796. }
  1797. /// <summary>
  1798. /// Reads a 16-bit unsigned integer from a Stream in little-endian format.
  1799. /// </summary>
  1800. /// <param name="stream"></param>
  1801. /// <returns>-1 on failure, else the 16-bit unsigned integer that was read.</returns>
  1802. public static int ReadUInt16(Stream stream)
  1803. {
  1804. int byte1 = stream.ReadByte();
  1805. if (byte1 == -1)
  1806. {
  1807. return -1;
  1808. }
  1809. int byte2 = stream.ReadByte();
  1810. if (byte2 == -1)
  1811. {
  1812. return -1;
  1813. }
  1814. return byte1 + (byte2 << 8);
  1815. }
  1816. public static void WriteUInt16(Stream stream, UInt16 word)
  1817. {
  1818. stream.WriteByte((byte)(word & 0xff));
  1819. stream.WriteByte((byte)(word >> 8));
  1820. }
  1821. public static void WriteUInt24(Stream stream, int uint24)
  1822. {
  1823. stream.WriteByte((byte)(uint24 & 0xff));
  1824. stream.WriteByte((byte)((uint24 >> 8) & 0xff));
  1825. stream.WriteByte((byte)((uint24 >> 16) & 0xff));
  1826. }
  1827. public static void WriteUInt32(Stream stream, UInt32 uint32)
  1828. {
  1829. stream.WriteByte((byte)(uint32 & 0xff));
  1830. stream.WriteByte((byte)((uint32 >> 8) & 0xff));
  1831. stream.WriteByte((byte)((uint32 >> 16) & 0xff));
  1832. stream.WriteByte((byte)((uint32 >> 24) & 0xff));
  1833. }
  1834. /// <summary>
  1835. /// Reads a 24-bit unsigned integer from a Stream in little-endian format.
  1836. /// </summary>
  1837. /// <param name="stream"></param>
  1838. /// <returns>-1 on failure, else the 24-bit unsigned integer that was read.</returns>
  1839. public static int ReadUInt24(Stream stream)
  1840. {
  1841. int byte1 = stream.ReadByte();
  1842. if (byte1 == -1)
  1843. {
  1844. return -1;
  1845. }
  1846. int byte2 = stream.ReadByte();
  1847. if (byte2 == -1)
  1848. {
  1849. return -1;
  1850. }
  1851. int byte3 = stream.ReadByte();
  1852. if (byte3 == -1)
  1853. {
  1854. return -1;
  1855. }
  1856. return byte1 + (byte2 << 8) + (byte3 << 16);
  1857. }
  1858. /// <summary>
  1859. /// Reads a 32-bit unsigned integer from a Stream in little-endian format.
  1860. /// </summary>
  1861. /// <param name="stream"></param>
  1862. /// <returns>-1 on failure, else the 32-bit unsigned integer that was read.</returns>
  1863. public static long ReadUInt32(Stream stream)
  1864. {
  1865. int byte1 = stream.ReadByte();
  1866. if (byte1 == -1)
  1867. {
  1868. return -1;
  1869. }
  1870. int byte2 = stream.ReadByte();
  1871. if (byte2 == -1)
  1872. {
  1873. return -1;
  1874. }
  1875. int byte3 = stream.ReadByte();
  1876. if (byte3 == -1)
  1877. {
  1878. return -1;
  1879. }
  1880. int byte4 = stream.ReadByte();
  1881. if (byte4 == -1)
  1882. {
  1883. return -1;
  1884. }
  1885. return unchecked((long)((uint)(byte1 + (byte2 << 8) + (byte3 << 16) + (byte4 << 24))));
  1886. }
  1887. public static int ReadFromStream(Stream input, byte[] buffer, int offset, int count)
  1888. {
  1889. int totalBytesRead = 0;
  1890. while (totalBytesRead < count)
  1891. {
  1892. int bytesRead = input.Read(buffer, offset + totalBytesRead, count - totalBytesRead);
  1893. if (bytesRead == 0)
  1894. {
  1895. throw new IOException("ran out of data");
  1896. }
  1897. totalBytesRead += bytesRead;
  1898. }
  1899. return totalBytesRead;
  1900. }
  1901. public static long CopyStream(Stream input, Stream output, long maxBytes)
  1902. {
  1903. long bytesCopied = 0;
  1904. byte[] buffer = new byte[4096];
  1905. while (true)
  1906. {
  1907. int bytesRead = input.Read(buffer, 0, buffer.Length);
  1908. if (bytesRead == 0)
  1909. {
  1910. break;
  1911. }
  1912. else
  1913. {
  1914. int bytesToCopy;
  1915. if (maxBytes != -1 && (bytesCopied + bytesRead) > maxBytes)
  1916. {
  1917. bytesToCopy = (int)(maxBytes - bytesCopied);
  1918. }
  1919. else
  1920. {
  1921. bytesToCopy = bytesRead;
  1922. }
  1923. output.Write(buffer, 0, bytesRead);
  1924. bytesCopied += bytesToCopy;
  1925. if (bytesToCopy != bytesRead)
  1926. {
  1927. break;
  1928. }
  1929. }
  1930. }
  1931. return bytesCopied;
  1932. }
  1933. public static long CopyStream(Stream input, Stream output)
  1934. {
  1935. return CopyStream(input, output, -1);
  1936. }
  1937. private struct Edge
  1938. {
  1939. public int miny; // int
  1940. public int maxy; // int
  1941. public int x; // fixed point: 24.8
  1942. public int dxdy; // fixed point: 24.8
  1943. public Edge(int miny, int maxy, int x, int dxdy)
  1944. {
  1945. this.miny = miny;
  1946. this.maxy = maxy;
  1947. this.x = x;
  1948. this.dxdy = dxdy;
  1949. }
  1950. }
  1951. public static Scanline[] GetScans(Point[] vertices)
  1952. {
  1953. return GetScans(vertices, 0, vertices.Length);
  1954. }
  1955. public static Scanline[] GetScans(Point[] vertices, int startIndex, int length)
  1956. {
  1957. if (length > vertices.Length - startIndex)
  1958. {
  1959. throw new ArgumentException("out of bounds: length > vertices.Length - startIndex");
  1960. }
  1961. int ymax = 0;
  1962. // Build edge table
  1963. Edge[] edgeTable = new Edge[length];
  1964. int edgeCount = 0;
  1965. for (int i = startIndex; i < startIndex + length; ++i)
  1966. {
  1967. Point top = vertices[i];
  1968. Point bottom = vertices[(((i + 1) - startIndex) % length) + startIndex];
  1969. int dy;
  1970. if (top.Y > bottom.Y)
  1971. {
  1972. Point temp = top;
  1973. top = bottom;
  1974. bottom = temp;
  1975. }
  1976. dy = bottom.Y - top.Y;
  1977. if (dy != 0)
  1978. {
  1979. edgeTable[edgeCount] = new Edge(top.Y, bottom.Y, top.X << 8, (((bottom.X - top.X) << 8) / dy));
  1980. ymax = Math.Max(ymax, bottom.Y);
  1981. ++edgeCount;
  1982. }
  1983. }
  1984. // Sort edge table by miny
  1985. for (int i = 0; i < edgeCount - 1; ++i)
  1986. {
  1987. int min = i;
  1988. for (int j = i + 1; j < edgeCount; ++j)
  1989. {
  1990. if (edgeTable[j].miny < edgeTable[min].miny)
  1991. {
  1992. min = j;
  1993. }
  1994. }
  1995. if (min != i)
  1996. {
  1997. Edge temp = edgeTable[min];
  1998. edgeTable[min] = edgeTable[i];
  1999. edgeTable[i] = temp;
  2000. }
  2001. }
  2002. // Compute how many scanlines we will be emitting
  2003. int scanCount = 0;
  2004. int activeLow = 0;
  2005. int activeHigh = 0;
  2006. int yscan1 = edgeTable[0].miny;
  2007. // we assume that edgeTable[0].miny == yscan
  2008. while (activeHigh < edgeCount - 1 &&
  2009. edgeTable[activeHigh + 1].miny == yscan1)
  2010. {
  2011. ++activeHigh;
  2012. }
  2013. while (yscan1 <= ymax)
  2014. {
  2015. // Find new edges where yscan == miny
  2016. while (activeHigh < edgeCount - 1 &&
  2017. edgeTable[activeHigh + 1].miny == yscan1)
  2018. {
  2019. ++activeHigh;
  2020. }
  2021. int count = 0;
  2022. for (int i = activeLow; i <= activeHigh; ++i)
  2023. {
  2024. if (edgeTable[i].maxy > yscan1)
  2025. {
  2026. ++count;
  2027. }
  2028. }
  2029. scanCount += count / 2;
  2030. ++yscan1;
  2031. // Remove edges where yscan == maxy
  2032. while (activeLow < edgeCount - 1 &&
  2033. edgeTable[activeLow].maxy <= yscan1)
  2034. {
  2035. ++activeLow;
  2036. }
  2037. if (activeLow > activeHigh)
  2038. {
  2039. activeHigh = activeLow;
  2040. }
  2041. }
  2042. // Allocate scanlines that we'll return
  2043. Scanline[] scans = new Scanline[scanCount];
  2044. // Active Edge Table (AET): it is indices into the Edge Table (ET)
  2045. int[] active = new int[edgeCount];
  2046. int activeCount = 0;
  2047. int yscan2 = edgeTable[0].miny;
  2048. int scansIndex = 0;
  2049. // Repeat until both the ET and AET are empty
  2050. while (yscan2 <= ymax)
  2051. {
  2052. // Move any edges from the ET to the AET where yscan == miny
  2053. for (int i = 0; i < edgeCount; ++i)
  2054. {
  2055. if (edgeTable[i].miny == yscan2)
  2056. {
  2057. active[activeCount] = i;
  2058. ++activeCount;
  2059. }
  2060. }
  2061. // Sort the AET on x
  2062. for (int i = 0; i < activeCount - 1; ++i)
  2063. {
  2064. int min = i;
  2065. for (int j = i + 1; j < activeCount; ++j)
  2066. {
  2067. if (edgeTable[active[j]].x < edgeTable[active[min]].x)
  2068. {
  2069. min = j;
  2070. }
  2071. }
  2072. if (min != i)
  2073. {
  2074. int temp = active[min];
  2075. active[min] = active[i];
  2076. active[i] = temp;
  2077. }
  2078. }
  2079. // For each pair of entries in the AET, fill in pixels between their info
  2080. for (int i = 0; i < activeCount; i += 2)
  2081. {
  2082. Edge el = edgeTable[active[i]];
  2083. Edge er = edgeTable[active[i + 1]];
  2084. int startx = (el.x + 0xff) >> 8; // ceil(x)
  2085. int endx = er.x >> 8; // floor(x)
  2086. scans[scansIndex] = new Scanline(startx, yscan2, endx - startx);
  2087. ++scansIndex;
  2088. }
  2089. ++yscan2;
  2090. // Remove from the AET any edge where yscan == maxy
  2091. int k = 0;
  2092. while (k < activeCount && activeCount > 0)
  2093. {
  2094. if (edgeTable[active[k]].maxy == yscan2)
  2095. {
  2096. // remove by shifting everything down one
  2097. for (int j = k + 1; j < activeCount; ++j)
  2098. {
  2099. active[j - 1] = active[j];
  2100. }
  2101. --activeCount;
  2102. }
  2103. else
  2104. {
  2105. ++k;
  2106. }
  2107. }
  2108. // Update x for each entry in AET
  2109. for (int i = 0; i < activeCount; ++i)
  2110. {
  2111. edgeTable[active[i]].x += edgeTable[active[i]].dxdy;
  2112. }
  2113. }
  2114. return scans;
  2115. }
  2116. public static PointF TransformOnePoint(Matrix matrix, PointF ptF)
  2117. {
  2118. PointF[] ptFs = new PointF[1] { ptF };
  2119. matrix.TransformPoints(ptFs);
  2120. return ptFs[0];
  2121. }
  2122. public static PointF TransformOneVector(Matrix matrix, PointF ptF)
  2123. {
  2124. PointF[] ptFs = new PointF[1] { ptF };
  2125. matrix.TransformVectors(ptFs);
  2126. return ptFs[0];
  2127. }
  2128. public static PointF NormalizeVector(PointF vecF)
  2129. {
  2130. float magnitude = Magnitude(vecF);
  2131. vecF.X /= magnitude;
  2132. vecF.Y /= magnitude;
  2133. return vecF;
  2134. }
  2135. public static PointF NormalizeVector2(PointF vecF)
  2136. {
  2137. float magnitude = Magnitude(vecF);
  2138. if (magnitude == 0)
  2139. {
  2140. vecF.X = 0;
  2141. vecF.Y = 0;
  2142. }
  2143. else
  2144. {
  2145. vecF.X /= magnitude;
  2146. vecF.Y /= magnitude;
  2147. }
  2148. return vecF;
  2149. }
  2150. public static void NormalizeVectors(PointF[] vecsF)
  2151. {
  2152. for (int i = 0; i < vecsF.Length; ++i)
  2153. {
  2154. vecsF[i] = NormalizeVector(vecsF[i]);
  2155. }
  2156. }
  2157. public static PointF RotateVector(PointF vecF, float angleDelta)
  2158. {
  2159. angleDelta *= (float)( Math.PI / 180.0);
  2160. float vecFLen = Magnitude(vecF);
  2161. float vecFAngle = angleDelta + (float)Math.Atan2(vecF.Y, vecF.X);
  2162. vecF.X = (float)Math.Cos(vecFAngle);
  2163. vecF.Y = (float)Math.Sin(vecFAngle);
  2164. return vecF;
  2165. }
  2166. public static void RotateVectors(PointF[] vecFs, float angleDelta)
  2167. {
  2168. for (int i = 0; i < vecFs.Length; ++i)
  2169. {
  2170. vecFs[i] = RotateVector(vecFs[i], angleDelta);
  2171. }
  2172. }
  2173. public static PointF MultiplyVector(PointF vecF, float scalar)
  2174. {
  2175. return new PointF(vecF.X * scalar, vecF.Y * scalar);
  2176. }
  2177. public static PointF AddVectors(PointF a, PointF b)
  2178. {
  2179. return new PointF(a.X + b.X, a.Y + b.Y);
  2180. }
  2181. public static PointF SubtractVectors(PointF lhs, PointF rhs)
  2182. {
  2183. return new PointF(lhs.X - rhs.X, lhs.Y - rhs.Y);
  2184. }
  2185. public static PointF NegateVector(PointF v)
  2186. {
  2187. return new PointF(-v.X, -v.Y);
  2188. }
  2189. public static float GetAngleOfTransform(Matrix matrix)
  2190. {
  2191. PointF[] pts = new PointF[] { new PointF(1.0f, 0.0f) };
  2192. matrix.TransformVectors(pts);
  2193. double atan2 = Math.Atan2(pts[0].Y, pts[0].X);
  2194. double angle = atan2 * (180.0f / Math.PI);
  2195. return (float)angle;
  2196. }
  2197. public static bool IsTransformFlipped(Matrix matrix)
  2198. {
  2199. PointF ptX = new PointF(1.0f, 0.0f);
  2200. PointF ptXT = Utility.TransformOneVector(matrix, ptX);
  2201. double atan2X = Math.Atan2(ptXT.Y, ptXT.X);
  2202. double angleX = atan2X * (180.0 / Math.PI);
  2203. PointF ptY = new PointF(0.0f, 1.0f);
  2204. PointF ptYT = Utility.TransformOneVector(matrix, ptY);
  2205. double atan2Y = Math.Atan2(ptYT.Y, ptYT.X);
  2206. double angleY = (atan2Y * (180.0 / Math.PI)) - 90.0;
  2207. while (angleX < 0)
  2208. {
  2209. angleX += 360;
  2210. }
  2211. while (angleY < 0)
  2212. {
  2213. angleY += 360;
  2214. }
  2215. double angleDelta = Math.Abs(angleX - angleY);
  2216. return angleDelta > 1.0 && angleDelta < 359.0;
  2217. }
  2218. /// <summary>
  2219. /// Calculates the dot product of two vectors.
  2220. /// </summary>
  2221. public static float DotProduct(PointF lhs, PointF rhs)
  2222. {
  2223. return lhs.X * rhs.X + lhs.Y * rhs.Y;
  2224. }
  2225. /// <summary>
  2226. /// Calculates the orthogonal projection of y on to u.
  2227. /// yhat = u * ((y dot u) / (u dot u))
  2228. /// z = y - yhat
  2229. /// Section 6.2 (pg. 381) of Linear Algebra and its Applications, Second Edition, by David C. Lay
  2230. /// </summary>
  2231. /// <param name="y">The vector to decompose</param>
  2232. /// <param name="u">The non-zero vector to project y on to</param>
  2233. /// <param name="yhat">The orthogonal projection of y onto u</param>
  2234. /// <param name="yhatLen">The length of yhat such that yhat = yhatLen * u</param>
  2235. /// <param name="z">The component of y orthogonal to u</param>
  2236. /// <remarks>
  2237. /// As a special case, if u=(0,0) the results are all zero.
  2238. /// </remarks>
  2239. public static void GetProjection(PointF y, PointF u, out PointF yhat, out float yhatLen, out PointF z)
  2240. {
  2241. if (u.X == 0 && u.Y == 0)
  2242. {
  2243. yhat = new PointF(0, 0);
  2244. yhatLen = 0;
  2245. z = new PointF(0, 0);
  2246. }
  2247. else
  2248. {
  2249. float yDotU = DotProduct(y, u);
  2250. float uDotU = DotProduct(u, u);
  2251. yhatLen = yDotU / uDotU;
  2252. yhat = MultiplyVector(u, yhatLen);
  2253. z = SubtractVectors(y, yhat);
  2254. }
  2255. }
  2256. public static int GreatestCommonDivisor(int a, int b)
  2257. {
  2258. int r;
  2259. if (a < b)
  2260. {
  2261. r = a;
  2262. a = b;
  2263. b = r;
  2264. }
  2265. do
  2266. {
  2267. r = a % b;
  2268. a = b;
  2269. b = r;
  2270. } while (r != 0);
  2271. return a;
  2272. }
  2273. public static void Swap(ref int a, ref int b)
  2274. {
  2275. int t;
  2276. t = a;
  2277. a = b;
  2278. b = t;
  2279. }
  2280. public static void Swap<T>(ref T a, ref T b)
  2281. {
  2282. T t;
  2283. t = a;
  2284. a = b;
  2285. b = t;
  2286. }
  2287. private static byte[] DownloadSmallFile(Uri uri, WebProxy proxy)
  2288. {
  2289. WebRequest request = WebRequest.Create(uri);
  2290. if (proxy != null)
  2291. {
  2292. request.Proxy = proxy;
  2293. }
  2294. request.Timeout = 5000;
  2295. WebResponse response = request.GetResponse();
  2296. Stream stream = response.GetResponseStream();
  2297. try
  2298. {
  2299. byte[] buffer = new byte[8192];
  2300. int offset = 0;
  2301. while (offset < buffer.Length)
  2302. {
  2303. int bytesRead = stream.Read(buffer, offset, buffer.Length - offset);
  2304. if (bytesRead == 0)
  2305. {
  2306. byte[] smallerBuffer = new byte[offset + bytesRead];
  2307. for (int i = 0; i < offset + bytesRead; ++i)
  2308. {
  2309. smallerBuffer[i] = buffer[i];
  2310. }
  2311. buffer = smallerBuffer;
  2312. }
  2313. offset += bytesRead;
  2314. }
  2315. return buffer;
  2316. }
  2317. finally
  2318. {
  2319. if (stream != null)
  2320. {
  2321. stream.Close();
  2322. stream = null;
  2323. }
  2324. if (response != null)
  2325. {
  2326. response.Close();
  2327. response = null;
  2328. }
  2329. }
  2330. }
  2331. public static T[] RepeatArray<T>(T[] array, int repeatCount)
  2332. {
  2333. T[] returnArray = new T[repeatCount * array.Length];
  2334. for (int i = 0; i < repeatCount; ++i)
  2335. {
  2336. for (int j = 0; j < array.Length; ++j)
  2337. {
  2338. int index = (i * array.Length) + j;
  2339. returnArray[index] = array[j];
  2340. }
  2341. }
  2342. return returnArray;
  2343. }
  2344. /// <summary>
  2345. /// Downloads a small file (max 8192 bytes) and returns it as a byte array.
  2346. /// </summary>
  2347. /// <returns>The contents of the file if downloaded successfully.</returns>
  2348. public static byte[] DownloadSmallFile(Uri uri)
  2349. {
  2350. byte[] bytes = null;
  2351. Exception exception = null;
  2352. WebProxy[] proxiesPre = Network.GetProxyList();
  2353. WebProxy[] proxies = RepeatArray(proxiesPre, 2); // see bug #1942
  2354. foreach (WebProxy proxy in proxies)
  2355. {
  2356. try
  2357. {
  2358. bytes = DownloadSmallFile(uri, proxy);
  2359. exception = null;
  2360. }
  2361. catch (Exception ex)
  2362. {
  2363. exception = ex;
  2364. bytes = null;
  2365. }
  2366. if (bytes != null)
  2367. {
  2368. break;
  2369. }
  2370. }
  2371. if (exception != null)
  2372. {
  2373. WebException we = exception as WebException;
  2374. if (we != null)
  2375. {
  2376. throw new WebException(null, we, we.Status, we.Response);
  2377. }
  2378. else
  2379. {
  2380. throw new ApplicationException("An exception occurred while trying to download '" + uri.ToString() + "'", exception);
  2381. }
  2382. }
  2383. return bytes;
  2384. }
  2385. private static void DownloadFile(Uri uri, Stream output, WebProxy proxy, ProgressEventHandler progressCallback)
  2386. {
  2387. WebRequest request = WebRequest.Create(uri);
  2388. if (proxy != null)
  2389. {
  2390. request.Proxy = proxy;
  2391. }
  2392. request.Timeout = 5000;
  2393. WebResponse response = request.GetResponse();
  2394. Stream stream = null;
  2395. SiphonStream siphonOutputStream = null;
  2396. try
  2397. {
  2398. stream = response.GetResponseStream();
  2399. siphonOutputStream = new SiphonStream(output, 1024); // monitor the completion of writes to 'output'
  2400. siphonOutputStream.IOFinished +=
  2401. delegate(object sender, IOEventArgs e)
  2402. {
  2403. if (progressCallback != null)
  2404. {
  2405. double percent = 100.0 * Utility.Clamp(((double)e.Position / (double)response.ContentLength), 0, 100);
  2406. progressCallback(uri, new ProgressEventArgs(percent));
  2407. }
  2408. };
  2409. Utility.CopyStream(stream, siphonOutputStream, 128 * 1024 * 1024); // cap at 128mb
  2410. siphonOutputStream.Flush();
  2411. }
  2412. finally
  2413. {
  2414. if (siphonOutputStream != null)
  2415. {
  2416. siphonOutputStream.Close();
  2417. siphonOutputStream = null;
  2418. }
  2419. if (stream != null)
  2420. {
  2421. stream.Close();
  2422. stream = null;
  2423. }
  2424. if (response != null)
  2425. {
  2426. response.Close();
  2427. response = null;
  2428. }
  2429. }
  2430. }
  2431. /// <summary>
  2432. /// Download a file (max 128MB) and saves it to the given Stream.
  2433. /// </summary>
  2434. public static void DownloadFile(Uri uri, Stream output, ProgressEventHandler progressCallback)
  2435. {
  2436. long startPosition = output.Position;
  2437. Exception exception = null;
  2438. WebProxy[] proxies = Network.GetProxyList();
  2439. foreach (WebProxy proxy in proxies)
  2440. {
  2441. bool success = false;
  2442. try
  2443. {
  2444. DownloadFile(uri, output, proxy, progressCallback);
  2445. exception = null;
  2446. success = true;
  2447. }
  2448. catch (Exception ex)
  2449. {
  2450. exception = ex;
  2451. }
  2452. // If the output stream was written to, then we know
  2453. // that we were either successful in downloading the
  2454. // file, or there was an error unrelated to using the
  2455. // proxy (maybe they unplugged the network cable, who
  2456. // knows!)
  2457. if (output.Position != startPosition || success)
  2458. {
  2459. break;
  2460. }
  2461. }
  2462. if (exception != null)
  2463. {
  2464. WebException we = exception as WebException;
  2465. if (we != null)
  2466. {
  2467. throw new WebException(null, we, we.Status, we.Response);
  2468. }
  2469. else
  2470. {
  2471. throw new ApplicationException("An exception occurred while trying to download '" + uri.ToString() + "'", exception);
  2472. }
  2473. }
  2474. }
  2475. public static byte FastScaleByteByByte(byte a, byte b)
  2476. {
  2477. int r1 = a * b + 0x80;
  2478. int r2 = ((r1 >> 8) + r1) >> 8;
  2479. return (byte)r2;
  2480. }
  2481. public static int FastDivideShortByByte(ushort n, byte d)
  2482. {
  2483. int i = d * 3;
  2484. uint m = masTable[i];
  2485. uint a = masTable[i + 1];
  2486. uint s = masTable[i + 2];
  2487. uint nTimesMPlusA = unchecked((n * m) + a);
  2488. uint shifted = nTimesMPlusA >> (int)s;
  2489. int r = (int)shifted;
  2490. return r;
  2491. }
  2492. // i = z * 3;
  2493. // (x / z) = ((x * masTable[i]) + masTable[i + 1]) >> masTable[i + 2)
  2494. private static readonly uint[] masTable =
  2495. {
  2496. 0x00000000, 0x00000000, 0, // 0
  2497. 0x00000001, 0x00000000, 0, // 1
  2498. 0x00000001, 0x00000000, 1, // 2
  2499. 0xAAAAAAAB, 0x00000000, 33, // 3
  2500. 0x00000001, 0x00000000, 2, // 4
  2501. 0xCCCCCCCD, 0x00000000, 34, // 5
  2502. 0xAAAAAAAB, 0x00000000, 34, // 6
  2503. 0x49249249, 0x49249249, 33, // 7
  2504. 0x00000001, 0x00000000, 3, // 8
  2505. 0x38E38E39, 0x00000000, 33, // 9
  2506. 0xCCCCCCCD, 0x00000000, 35, // 10
  2507. 0xBA2E8BA3, 0x00000000, 35, // 11
  2508. 0xAAAAAAAB, 0x00000000, 35, // 12
  2509. 0x4EC4EC4F, 0x00000000, 34, // 13
  2510. 0x49249249, 0x49249249, 34, // 14
  2511. 0x88888889, 0x00000000, 35, // 15
  2512. 0x00000001, 0x00000000, 4, // 16
  2513. 0xF0F0F0F1, 0x00000000, 36, // 17
  2514. 0x38E38E39, 0x00000000, 34, // 18
  2515. 0xD79435E5, 0xD79435E5, 36, // 19
  2516. 0xCCCCCCCD, 0x00000000, 36, // 20
  2517. 0xC30C30C3, 0xC30C30C3, 36, // 21
  2518. 0xBA2E8BA3, 0x00000000, 36, // 22
  2519. 0xB21642C9, 0x00000000, 36, // 23
  2520. 0xAAAAAAAB, 0x00000000, 36, // 24
  2521. 0x51EB851F, 0x00000000, 35, // 25
  2522. 0x4EC4EC4F, 0x00000000, 35, // 26
  2523. 0x97B425ED, 0x97B425ED, 36, // 27
  2524. 0x49249249, 0x49249249, 35, // 28
  2525. 0x8D3DCB09, 0x00000000, 36, // 29
  2526. 0x88888889, 0x00000000, 36, // 30
  2527. 0x42108421, 0x42108421, 35, // 31
  2528. 0x00000001, 0x00000000, 5, // 32
  2529. 0x3E0F83E1, 0x00000000, 35, // 33
  2530. 0xF0F0F0F1, 0x00000000, 37, // 34
  2531. 0x75075075, 0x75075075, 36, // 35
  2532. 0x38E38E39, 0x00000000, 35, // 36
  2533. 0x6EB3E453, 0x6EB3E453, 36, // 37
  2534. 0xD79435E5, 0xD79435E5, 37, // 38
  2535. 0x69069069, 0x69069069, 36, // 39
  2536. 0xCCCCCCCD, 0x00000000, 37, // 40
  2537. 0xC7CE0C7D, 0x00000000, 37, // 41
  2538. 0xC30C30C3, 0xC30C30C3, 37, // 42
  2539. 0x2FA0BE83, 0x00000000, 35, // 43
  2540. 0xBA2E8BA3, 0x00000000, 37, // 44
  2541. 0x5B05B05B, 0x5B05B05B, 36, // 45
  2542. 0xB21642C9, 0x00000000, 37, // 46
  2543. 0xAE4C415D, 0x00000000, 37, // 47
  2544. 0xAAAAAAAB, 0x00000000, 37, // 48
  2545. 0x5397829D, 0x00000000, 36, // 49
  2546. 0x51EB851F, 0x00000000, 36, // 50
  2547. 0xA0A0A0A1, 0x00000000, 37, // 51
  2548. 0x4EC4EC4F, 0x00000000, 36, // 52
  2549. 0x9A90E7D9, 0x9A90E7D9, 37, // 53
  2550. 0x97B425ED, 0x97B425ED, 37, // 54
  2551. 0x94F2094F, 0x94F2094F, 37, // 55
  2552. 0x49249249, 0x49249249, 36, // 56
  2553. 0x47DC11F7, 0x47DC11F7, 36, // 57
  2554. 0x8D3DCB09, 0x00000000, 37, // 58
  2555. 0x22B63CBF, 0x00000000, 35, // 59
  2556. 0x88888889, 0x00000000, 37, // 60
  2557. 0x4325C53F, 0x00000000, 36, // 61
  2558. 0x42108421, 0x42108421, 36, // 62
  2559. 0x41041041, 0x41041041, 36, // 63
  2560. 0x00000001, 0x00000000, 6, // 64
  2561. 0xFC0FC0FD, 0x00000000, 38, // 65
  2562. 0x3E0F83E1, 0x00000000, 36, // 66
  2563. 0x07A44C6B, 0x00000000, 33, // 67
  2564. 0xF0F0F0F1, 0x00000000, 38, // 68
  2565. 0x76B981DB, 0x00000000, 37, // 69
  2566. 0x75075075, 0x75075075, 37, // 70
  2567. 0xE6C2B449, 0x00000000, 38, // 71
  2568. 0x38E38E39, 0x00000000, 36, // 72
  2569. 0x381C0E07, 0x381C0E07, 36, // 73
  2570. 0x6EB3E453, 0x6EB3E453, 37, // 74
  2571. 0x1B4E81B5, 0x00000000, 35, // 75
  2572. 0xD79435E5, 0xD79435E5, 38, // 76
  2573. 0x3531DEC1, 0x00000000, 36, // 77
  2574. 0x69069069, 0x69069069, 37, // 78
  2575. 0xCF6474A9, 0x00000000, 38, // 79
  2576. 0xCCCCCCCD, 0x00000000, 38, // 80
  2577. 0xCA4587E7, 0x00000000, 38, // 81
  2578. 0xC7CE0C7D, 0x00000000, 38, // 82
  2579. 0x3159721F, 0x00000000, 36, // 83
  2580. 0xC30C30C3, 0xC30C30C3, 38, // 84
  2581. 0xC0C0C0C1, 0x00000000, 38, // 85
  2582. 0x2FA0BE83, 0x00000000, 36, // 86
  2583. 0x2F149903, 0x00000000, 36, // 87
  2584. 0xBA2E8BA3, 0x00000000, 38, // 88
  2585. 0xB81702E1, 0x00000000, 38, // 89
  2586. 0x5B05B05B, 0x5B05B05B, 37, // 90
  2587. 0x2D02D02D, 0x2D02D02D, 36, // 91
  2588. 0xB21642C9, 0x00000000, 38, // 92
  2589. 0xB02C0B03, 0x00000000, 38, // 93
  2590. 0xAE4C415D, 0x00000000, 38, // 94
  2591. 0x2B1DA461, 0x2B1DA461, 36, // 95
  2592. 0xAAAAAAAB, 0x00000000, 38, // 96
  2593. 0xA8E83F57, 0xA8E83F57, 38, // 97
  2594. 0x5397829D, 0x00000000, 37, // 98
  2595. 0xA57EB503, 0x00000000, 38, // 99
  2596. 0x51EB851F, 0x00000000, 37, // 100
  2597. 0xA237C32B, 0xA237C32B, 38, // 101
  2598. 0xA0A0A0A1, 0x00000000, 38, // 102
  2599. 0x9F1165E7, 0x9F1165E7, 38, // 103
  2600. 0x4EC4EC4F, 0x00000000, 37, // 104
  2601. 0x27027027, 0x27027027, 36, // 105
  2602. 0x9A90E7D9, 0x9A90E7D9, 38, // 106
  2603. 0x991F1A51, 0x991F1A51, 38, // 107
  2604. 0x97B425ED, 0x97B425ED, 38, // 108
  2605. 0x2593F69B, 0x2593F69B, 36, // 109
  2606. 0x94F2094F, 0x94F2094F, 38, // 110
  2607. 0x24E6A171, 0x24E6A171, 36, // 111
  2608. 0x49249249, 0x49249249, 37, // 112
  2609. 0x90FDBC09, 0x90FDBC09, 38, // 113
  2610. 0x47DC11F7, 0x47DC11F7, 37, // 114
  2611. 0x8E78356D, 0x8E78356D, 38, // 115
  2612. 0x8D3DCB09, 0x00000000, 38, // 116
  2613. 0x23023023, 0x23023023, 36, // 117
  2614. 0x22B63CBF, 0x00000000, 36, // 118
  2615. 0x44D72045, 0x00000000, 37, // 119
  2616. 0x88888889, 0x00000000, 38, // 120
  2617. 0x8767AB5F, 0x8767AB5F, 38, // 121
  2618. 0x4325C53F, 0x00000000, 37, // 122
  2619. 0x85340853, 0x85340853, 38, // 123
  2620. 0x42108421, 0x42108421, 37, // 124
  2621. 0x10624DD3, 0x00000000, 35, // 125
  2622. 0x41041041, 0x41041041, 37, // 126
  2623. 0x10204081, 0x10204081, 35, // 127
  2624. 0x00000001, 0x00000000, 7, // 128
  2625. 0x0FE03F81, 0x00000000, 35, // 129
  2626. 0xFC0FC0FD, 0x00000000, 39, // 130
  2627. 0xFA232CF3, 0x00000000, 39, // 131
  2628. 0x3E0F83E1, 0x00000000, 37, // 132
  2629. 0xF6603D99, 0x00000000, 39, // 133
  2630. 0x07A44C6B, 0x00000000, 34, // 134
  2631. 0xF2B9D649, 0x00000000, 39, // 135
  2632. 0xF0F0F0F1, 0x00000000, 39, // 136
  2633. 0x077975B9, 0x00000000, 34, // 137
  2634. 0x76B981DB, 0x00000000, 38, // 138
  2635. 0x75DED953, 0x00000000, 38, // 139
  2636. 0x75075075, 0x75075075, 38, // 140
  2637. 0x3A196B1F, 0x00000000, 37, // 141
  2638. 0xE6C2B449, 0x00000000, 39, // 142
  2639. 0xE525982B, 0x00000000, 39, // 143
  2640. 0x38E38E39, 0x00000000, 37, // 144
  2641. 0xE1FC780F, 0x00000000, 39, // 145
  2642. 0x381C0E07, 0x381C0E07, 37, // 146
  2643. 0xDEE95C4D, 0x00000000, 39, // 147
  2644. 0x6EB3E453, 0x6EB3E453, 38, // 148
  2645. 0xDBEB61EF, 0x00000000, 39, // 149
  2646. 0x1B4E81B5, 0x00000000, 36, // 150
  2647. 0x36406C81, 0x00000000, 37, // 151
  2648. 0xD79435E5, 0xD79435E5, 39, // 152
  2649. 0xD62B80D7, 0x00000000, 39, // 153
  2650. 0x3531DEC1, 0x00000000, 37, // 154
  2651. 0xD3680D37, 0x00000000, 39, // 155
  2652. 0x69069069, 0x69069069, 38, // 156
  2653. 0x342DA7F3, 0x00000000, 37, // 157
  2654. 0xCF6474A9, 0x00000000, 39, // 158
  2655. 0xCE168A77, 0xCE168A77, 39, // 159
  2656. 0xCCCCCCCD, 0x00000000, 39, // 160
  2657. 0xCB8727C1, 0x00000000, 39, // 161
  2658. 0xCA4587E7, 0x00000000, 39, // 162
  2659. 0xC907DA4F, 0x00000000, 39, // 163
  2660. 0xC7CE0C7D, 0x00000000, 39, // 164
  2661. 0x634C0635, 0x00000000, 38, // 165
  2662. 0x3159721F, 0x00000000, 37, // 166
  2663. 0x621B97C3, 0x00000000, 38, // 167
  2664. 0xC30C30C3, 0xC30C30C3, 39, // 168
  2665. 0x60F25DEB, 0x00000000, 38, // 169
  2666. 0xC0C0C0C1, 0x00000000, 39, // 170
  2667. 0x17F405FD, 0x17F405FD, 36, // 171
  2668. 0x2FA0BE83, 0x00000000, 37, // 172
  2669. 0xBD691047, 0xBD691047, 39, // 173
  2670. 0x2F149903, 0x00000000, 37, // 174
  2671. 0x5D9F7391, 0x00000000, 38, // 175
  2672. 0xBA2E8BA3, 0x00000000, 39, // 176
  2673. 0x5C90A1FD, 0x5C90A1FD, 38, // 177
  2674. 0xB81702E1, 0x00000000, 39, // 178
  2675. 0x5B87DDAD, 0x5B87DDAD, 38, // 179
  2676. 0x5B05B05B, 0x5B05B05B, 38, // 180
  2677. 0xB509E68B, 0x00000000, 39, // 181
  2678. 0x2D02D02D, 0x2D02D02D, 37, // 182
  2679. 0xB30F6353, 0x00000000, 39, // 183
  2680. 0xB21642C9, 0x00000000, 39, // 184
  2681. 0x1623FA77, 0x1623FA77, 36, // 185
  2682. 0xB02C0B03, 0x00000000, 39, // 186
  2683. 0xAF3ADDC7, 0x00000000, 39, // 187
  2684. 0xAE4C415D, 0x00000000, 39, // 188
  2685. 0x15AC056B, 0x15AC056B, 36, // 189
  2686. 0x2B1DA461, 0x2B1DA461, 37, // 190
  2687. 0xAB8F69E3, 0x00000000, 39, // 191
  2688. 0xAAAAAAAB, 0x00000000, 39, // 192
  2689. 0x15390949, 0x00000000, 36, // 193
  2690. 0xA8E83F57, 0xA8E83F57, 39, // 194
  2691. 0x15015015, 0x15015015, 36, // 195
  2692. 0x5397829D, 0x00000000, 38, // 196
  2693. 0xA655C439, 0xA655C439, 39, // 197
  2694. 0xA57EB503, 0x00000000, 39, // 198
  2695. 0x5254E78F, 0x00000000, 38, // 199
  2696. 0x51EB851F, 0x00000000, 38, // 200
  2697. 0x028C1979, 0x00000000, 33, // 201
  2698. 0xA237C32B, 0xA237C32B, 39, // 202
  2699. 0xA16B312F, 0x00000000, 39, // 203
  2700. 0xA0A0A0A1, 0x00000000, 39, // 204
  2701. 0x4FEC04FF, 0x00000000, 38, // 205
  2702. 0x9F1165E7, 0x9F1165E7, 39, // 206
  2703. 0x27932B49, 0x00000000, 37, // 207
  2704. 0x4EC4EC4F, 0x00000000, 38, // 208
  2705. 0x9CC8E161, 0x00000000, 39, // 209
  2706. 0x27027027, 0x27027027, 37, // 210
  2707. 0x9B4C6F9F, 0x00000000, 39, // 211
  2708. 0x9A90E7D9, 0x9A90E7D9, 39, // 212
  2709. 0x99D722DB, 0x00000000, 39, // 213
  2710. 0x991F1A51, 0x991F1A51, 39, // 214
  2711. 0x4C346405, 0x00000000, 38, // 215
  2712. 0x97B425ED, 0x97B425ED, 39, // 216
  2713. 0x4B809701, 0x4B809701, 38, // 217
  2714. 0x2593F69B, 0x2593F69B, 37, // 218
  2715. 0x12B404AD, 0x12B404AD, 36, // 219
  2716. 0x94F2094F, 0x94F2094F, 39, // 220
  2717. 0x25116025, 0x25116025, 37, // 221
  2718. 0x24E6A171, 0x24E6A171, 37, // 222
  2719. 0x24BC44E1, 0x24BC44E1, 37, // 223
  2720. 0x49249249, 0x49249249, 38, // 224
  2721. 0x91A2B3C5, 0x00000000, 39, // 225
  2722. 0x90FDBC09, 0x90FDBC09, 39, // 226
  2723. 0x905A3863, 0x905A3863, 39, // 227
  2724. 0x47DC11F7, 0x47DC11F7, 38, // 228
  2725. 0x478BBCED, 0x00000000, 38, // 229
  2726. 0x8E78356D, 0x8E78356D, 39, // 230
  2727. 0x46ED2901, 0x46ED2901, 38, // 231
  2728. 0x8D3DCB09, 0x00000000, 39, // 232
  2729. 0x2328A701, 0x2328A701, 37, // 233
  2730. 0x23023023, 0x23023023, 37, // 234
  2731. 0x45B81A25, 0x45B81A25, 38, // 235
  2732. 0x22B63CBF, 0x00000000, 37, // 236
  2733. 0x08A42F87, 0x08A42F87, 35, // 237
  2734. 0x44D72045, 0x00000000, 38, // 238
  2735. 0x891AC73B, 0x00000000, 39, // 239
  2736. 0x88888889, 0x00000000, 39, // 240
  2737. 0x10FEF011, 0x00000000, 36, // 241
  2738. 0x8767AB5F, 0x8767AB5F, 39, // 242
  2739. 0x86D90545, 0x00000000, 39, // 243
  2740. 0x4325C53F, 0x00000000, 38, // 244
  2741. 0x85BF3761, 0x85BF3761, 39, // 245
  2742. 0x85340853, 0x85340853, 39, // 246
  2743. 0x10953F39, 0x10953F39, 36, // 247
  2744. 0x42108421, 0x42108421, 38, // 248
  2745. 0x41CC9829, 0x41CC9829, 38, // 249
  2746. 0x10624DD3, 0x00000000, 36, // 250
  2747. 0x828CBFBF, 0x00000000, 39, // 251
  2748. 0x41041041, 0x41041041, 38, // 252
  2749. 0x81848DA9, 0x00000000, 39, // 253
  2750. 0x10204081, 0x10204081, 36, // 254
  2751. 0x80808081, 0x00000000, 39 // 255
  2752. };
  2753. }
  2754. }