/[Sims3RigEditor]/trunk/ViewDDS/Utility.cs
ViewVC logotype

Contents of /trunk/ViewDDS/Utility.cs

Parent Directory Parent Directory | Revision Log Revision Log


Revision 39 - (show annotations) (download)
Thu Aug 5 21:38:32 2010 UTC (9 years, 11 months ago) by william
File size: 109663 byte(s)
update Paint.NET DDS plugin, again...

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

  ViewVC Help
Powered by ViewVC 1.1.22