/src/Core/Utility.cs
C# | 3273 lines | 2568 code | 519 blank | 186 comment | 377 complexity | 4946d19edb99d6fa1f3119903511463b MD5 | raw file
Possible License(s): Unlicense
Large files files are truncated, but you can click here to view the full file
- /////////////////////////////////////////////////////////////////////////////////
- // Paint.NET //
- // Copyright (C) dotPDN LLC, Rick Brewster, Tom Jackson, and contributors. //
- // Portions Copyright (C) Microsoft Corporation. All Rights Reserved. //
- // See src/Resources/Files/License.txt for full licensing and attribution //
- // details. //
- // . //
- /////////////////////////////////////////////////////////////////////////////////
-
- using Microsoft.Win32;
- using PaintDotNet.Threading;
- using PaintDotNet.SystemLayer;
- using System;
- using System.Collections;
- using System.Collections.Generic;
- using System.ComponentModel;
- using System.Diagnostics;
- using System.Drawing;
- using System.Drawing.Drawing2D;
- using System.Drawing.Imaging;
- using System.Globalization;
- using System.IO;
- using System.Net;
- using System.Reflection;
- using System.Runtime.InteropServices;
- using System.Runtime.Serialization;
- using System.Runtime.Serialization.Formatters.Binary;
- using System.Text;
- using System.Threading;
- using System.Windows.Forms;
-
- namespace PaintDotNet
- {
- /// <summary>
- /// Defines miscellaneous constants and static functions.
- /// </summary>
- /// // TODO: refactor into mini static classes
- public sealed class Utility
- {
- private Utility()
- {
- }
-
- internal static bool IsNumber(float x)
- {
- return x >= float.MinValue && x <= float.MaxValue;
- }
-
- internal static bool IsNumber(double x)
- {
- return x >= double.MinValue && x <= double.MaxValue;
- }
-
- internal static int Min(int val0, params int[] vals)
- {
- int min = val0;
-
- for (int i = 0; i < vals.Length; ++i)
- {
- if (vals[i] < min)
- {
- min = vals[i];
- }
- }
-
- return min;
- }
-
- internal static int Max(int val0, params int[] vals)
- {
- int max = val0;
-
- for (int i = 0; i < vals.Length; ++i)
- {
- if (vals[i] > max)
- {
- max = vals[i];
- }
- }
-
- return max;
- }
-
- public static PointF[] GetRgssOffsets(int quality)
- {
- unsafe
- {
- int sampleCount = quality * quality;
- PointF[] samplesArray = new PointF[sampleCount];
-
- fixed (PointF* pSamplesArray = samplesArray)
- {
- GetRgssOffsets(pSamplesArray, sampleCount, quality);
- }
-
- return samplesArray;
- }
- }
-
- public static unsafe void GetRgssOffsets(PointF* samplesArray, int sampleCount, int quality)
- {
- if (sampleCount < 1)
- {
- throw new ArgumentOutOfRangeException("sampleCount", "sampleCount must be [0, int.MaxValue]");
- }
-
- if (sampleCount != quality * quality)
- {
- throw new ArgumentOutOfRangeException("sampleCount != (quality * quality)");
- }
-
- if (sampleCount == 1)
- {
- samplesArray[0] = new PointF(0.0f, 0.0f);
- }
- else
- {
- for (int i = 0; i < sampleCount; ++i)
- {
- double y = (i + 1d) / (sampleCount + 1d);
- double x = y * quality;
-
- x -= (int)x;
-
- samplesArray[i] = new PointF((float)(x - 0.5d), (float)(y - 0.5d));
- }
- }
- }
-
- public static bool IsObsolete(Type type, bool inherit)
- {
- object[] attrs = type.GetCustomAttributes(typeof(ObsoleteAttribute), inherit);
- return (attrs.Length != 0);
- }
-
- public static void DrawDropShadow1px(Graphics g, Rectangle rect)
- {
- Brush b0 = new SolidBrush(Color.FromArgb(15, Color.Black));
- Brush b1 = new SolidBrush(Color.FromArgb(47, Color.Black));
- Pen p2 = new Pen(Color.FromArgb(63, Color.Black));
-
- g.FillRectangle(b0, rect.Left, rect.Top, 1, 1);
- g.FillRectangle(b1, rect.Left + 1, rect.Top, 1, 1);
- g.FillRectangle(b1, rect.Left, rect.Top + 1, 1, 1);
-
- g.FillRectangle(b0, rect.Right - 1, rect.Top, 1, 1);
- g.FillRectangle(b1, rect.Right - 2, rect.Top, 1, 1);
- g.FillRectangle(b1, rect.Right - 1, rect.Top + 1, 1, 1);
-
- g.FillRectangle(b0, rect.Left, rect.Bottom - 1, 1, 1);
- g.FillRectangle(b1, rect.Left + 1, rect.Bottom - 1, 1, 1);
- g.FillRectangle(b1, rect.Left, rect.Bottom - 2, 1, 1);
-
- g.FillRectangle(b0, rect.Right - 1, rect.Bottom - 1, 1, 1);
- g.FillRectangle(b1, rect.Right - 2, rect.Bottom - 1, 1, 1);
- g.FillRectangle(b1, rect.Right - 1, rect.Bottom - 2, 1, 1);
-
- g.DrawLine(p2, rect.Left + 2, rect.Top, rect.Right - 3, rect.Top);
- g.DrawLine(p2, rect.Left, rect.Top + 2, rect.Left, rect.Bottom - 3);
- g.DrawLine(p2, rect.Left + 2, rect.Bottom - 1, rect.Right - 3, rect.Bottom - 1);
- g.DrawLine(p2, rect.Right - 1, rect.Top + 2, rect.Right - 1, rect.Bottom - 3);
-
- b0.Dispose();
- b0 = null;
- b1.Dispose();
- b1 = null;
- p2.Dispose();
- p2 = null;
- }
-
- public static Keys LetterOrDigitCharToKeys(char c)
- {
- if (c >= 'a' && c <= 'z')
- {
- return (Keys)((int)(c - 'a') + (int)Keys.A);
- }
- else if (c >= 'A' && c <= 'Z')
- {
- return (Keys)((int)(c - 'A') + (int)Keys.A);
- }
- else if (c >= '0' && c <= '9')
- {
- return (Keys)((int)(c - '0') + (int)Keys.D0);
- }
- else
- {
- return Keys.None;
- }
- }
-
- public static Control FindFocus()
- {
- foreach (Form form in Application.OpenForms)
- {
- Control focused = FindFocus(form);
-
- if (focused != null)
- {
- return focused;
- }
- }
-
- return null;
- }
-
- private static Control FindFocus(Control c)
- {
- if (c.Focused)
- {
- return c;
- }
-
- foreach (Control child in c.Controls)
- {
- Control f = FindFocus(child);
-
- if (f != null)
- {
- return f;
- }
- }
-
- return null;
- }
-
- public static void DrawColorRectangle(Graphics g, Rectangle rect, Color color, bool drawBorder)
- {
- int inflateAmt = drawBorder ? -2 : 0;
- Rectangle colorRectangle = Rectangle.Inflate(rect, inflateAmt, inflateAmt);
- Brush colorBrush = new LinearGradientBrush(colorRectangle, Color.FromArgb(255, color), color, 90.0f, false);
- HatchBrush backgroundBrush = new HatchBrush(HatchStyle.LargeCheckerBoard, Color.FromArgb(191, 191, 191), Color.FromArgb(255, 255, 255));
-
- if (drawBorder)
- {
- g.DrawRectangle(Pens.Black, rect.Left, rect.Top, rect.Width - 1, rect.Height - 1);
- g.DrawRectangle(Pens.White, rect.Left + 1, rect.Top + 1, rect.Width - 3, rect.Height - 3);
- }
-
- PixelOffsetMode oldPOM = g.PixelOffsetMode;
- g.PixelOffsetMode = PixelOffsetMode.Half;
- g.FillRectangle(backgroundBrush, colorRectangle);
- g.FillRectangle(colorBrush, colorRectangle);
- g.PixelOffsetMode = oldPOM;
-
- backgroundBrush.Dispose();
- colorBrush.Dispose();
- }
-
- public static Size ComputeThumbnailSize(Size originalSize, int maxEdgeLength)
- {
- Size thumbSize;
-
- if (originalSize.Width > originalSize.Height)
- {
- int longSide = Math.Min(originalSize.Width, maxEdgeLength);
- thumbSize = new Size(longSide, Math.Max(1, (originalSize.Height * longSide) / originalSize.Width));
- }
- else if (originalSize.Height > originalSize.Width)
- {
- int longSide = Math.Min(originalSize.Height, maxEdgeLength);
- thumbSize = new Size(Math.Max(1, (originalSize.Width * longSide) / originalSize.Height), longSide);
- }
- else // if (docSize.Width == docSize.Height)
- {
- int longSide = Math.Min(originalSize.Width, maxEdgeLength);
- thumbSize = new Size(longSide, longSide);
- }
-
- return thumbSize;
- }
-
- public static bool IsClipboardImageAvailable()
- {
- try
- {
- return System.Windows.Forms.Clipboard.ContainsImage() ||
- System.Windows.Forms.Clipboard.ContainsData(DataFormats.EnhancedMetafile);
- }
-
- catch (ExternalException)
- {
- return false;
- }
- }
-
- public static Font CreateFont(string name, float size, FontStyle style)
- {
- Font returnFont;
-
- try
- {
- returnFont = new Font(name, size, style);
- }
-
- catch (Exception)
- {
- returnFont = new Font(FontFamily.GenericSansSerif, size);
- }
-
- return returnFont;
- }
-
- public static Font CreateFont(string name, float size, string backupName, float backupSize, FontStyle style)
- {
- Font returnFont;
-
- try
- {
- returnFont = new Font(name, size, style);
- }
-
- catch (Exception)
- {
- returnFont = CreateFont(backupName, backupSize, style);
- }
-
- return returnFont;
- }
-
- public static readonly Color TransparentKey = Color.FromArgb(192, 192, 192);
-
- public static string WebExceptionToErrorMessage(WebException wex)
- {
- string errorMessage;
-
- switch (wex.Status)
- {
- case WebExceptionStatus.ProtocolError:
- string format = PdnResources.GetString("WebExceptionStatus.ProtocolError.Format");
- HttpStatusCode statusCode = ((HttpWebResponse)wex.Response).StatusCode;
- errorMessage = string.Format(format, statusCode.ToString(), (int)statusCode);
- break;
-
- default:
- string stringName = "WebExceptionStatus." + wex.Status.ToString();
- errorMessage = PdnResources.GetString(stringName);
- break;
- }
-
- return errorMessage;
- }
-
- private static bool allowGCFullCollect = true;
- public static bool AllowGCFullCollect
- {
- get
- {
- return allowGCFullCollect;
- }
-
- set
- {
- allowGCFullCollect = value;
- }
- }
-
- public static void GCFullCollect()
- {
- if (AllowGCFullCollect)
- {
- GC.Collect();
- GC.WaitForPendingFinalizers();
- GC.Collect();
- GC.WaitForPendingFinalizers();
- }
- }
-
- private static int defaultSimplificationFactor = 50;
- public static int DefaultSimplificationFactor
- {
- get
- {
- return defaultSimplificationFactor;
- }
-
- set
- {
- defaultSimplificationFactor = value;
- }
- }
-
- public static bool IsArrowKey(Keys keyData)
- {
- Keys key = keyData & Keys.KeyCode;
-
- if (key == Keys.Up || key == Keys.Down || key == Keys.Left || key == Keys.Right)
- {
- return true;
- }
- else
- {
- return false;
- }
- }
-
- public static bool DoesControlHaveMouseCaptured(Control control)
- {
- bool result = false;
-
- result |= control.Capture;
-
- foreach (Control c in control.Controls)
- {
- result |= DoesControlHaveMouseCaptured(c);
- }
-
- return result;
- }
-
- public static void SplitRectangle(Rectangle rect, Rectangle[] rects)
- {
- int height = rect.Height;
-
- for (int i = 0; i < rects.Length; ++i)
- {
- Rectangle newRect = Rectangle.FromLTRB(rect.Left,
- rect.Top + ((height * i) / rects.Length),
- rect.Right,
- rect.Top + ((height * (i + 1)) / rects.Length));
-
- rects[i] = newRect;
- }
- }
-
- public static long TicksToMs(long ticks)
- {
- return ticks / 10000;
- }
-
- public static string GetStaticName(Type type)
- {
- PropertyInfo pi = type.GetProperty("StaticName", BindingFlags.Static | BindingFlags.Public | BindingFlags.GetProperty);
- return (string)pi.GetValue(null, null);
- }
-
- public static readonly float[][] Identity5x5F = new float[][] {
- new float[] { 1, 0, 0, 0, 0 },
- new float[] { 0, 1, 0, 0, 0 },
- new float[] { 0, 0, 1, 0, 0 },
- new float[] { 0, 0, 0, 1, 0 },
- new float[] { 0, 0, 0, 0, 1 }
- };
-
- public static readonly ColorMatrix IdentityColorMatrix = new ColorMatrix(Identity5x5F);
-
- [ThreadStatic]
- private static Matrix identityMatrix = null;
- public static Matrix IdentityMatrix
- {
- get
- {
- if (identityMatrix == null)
- {
- identityMatrix = new Matrix();
- identityMatrix.Reset();
- }
-
- return identityMatrix;
- }
- }
-
- /// <summary>
- /// Rounds an integer to the smallest power of 2 that is greater
- /// than or equal to it.
- /// </summary>
- public static int Log2RoundUp(int x)
- {
- if (x == 0)
- {
- return 1;
- }
-
- if (x == 1)
- {
- return 1;
- }
-
- return 1 << (1 + HighestBit(x - 1));
- }
-
- private static int HighestBit(int x)
- {
- if (x == 0)
- {
- return 0;
- }
-
- int b = 0;
- int hi = 0;
-
- while (b <= 30)
- {
- if ((x & (1 << b)) != 0)
- {
- hi = b;
- }
-
- ++b;
- }
-
- return hi;
- }
-
- private int CountBits(int x)
- {
- uint y = (uint)x;
- int count = 0;
-
- for (int bit = 0; bit < 32; ++bit)
- {
- if ((y & ((uint)1 << bit)) != 0)
- {
- ++count;
- }
- }
-
- return count;
- }
-
- public static string RemoveSpaces(string s)
- {
- StringBuilder sb = new StringBuilder();
-
- foreach (char c in s)
- {
- if (!char.IsWhiteSpace(c))
- {
- sb.Append(c);
- }
- }
-
- return sb.ToString();
- }
-
- public static int Max(int[,] array)
- {
- int max = int.MinValue;
-
- for (int i = array.GetLowerBound(0); i <= array.GetUpperBound(0); ++i)
- {
- for (int j = array.GetLowerBound(1); j <= array.GetUpperBound(1); ++j)
- {
- if (array[i,j] > max)
- {
- max = array[i,j];
- }
- }
- }
-
- return max;
- }
-
- public static int Sum(int[][] array)
- {
- int sum = 0;
-
- for (int i = 0; i < array.Length; ++i)
- {
- int[] row = array[i];
-
- for (int j = 0; j < row.Length; ++j)
- {
- sum += row[j];
- }
- }
-
- return sum;
- }
-
- // TODO: obsolete these NUD funcitons, move them into PdnNumericUpDown
- public static void ClipNumericUpDown(NumericUpDown upDown)
- {
- if (upDown.Value < upDown.Minimum)
- {
- upDown.Value = upDown.Minimum;
- }
- else if (upDown.Value > upDown.Maximum)
- {
- upDown.Value = upDown.Maximum;
- }
- }
-
- public static bool GetUpDownValueFromText(NumericUpDown nud, out double val)
- {
- if (nud.Text == string.Empty)
- {
- val = 0;
- return false;
- }
- else
- {
- try
- {
- if (nud.DecimalPlaces == 0)
- {
- val = (double)int.Parse(nud.Text);
- }
- else
- {
- val = double.Parse(nud.Text);
- }
- }
-
- catch
- {
- val = 0;
- return false;
- }
-
- return true;
- }
- }
-
- public static bool CheckNumericUpDown(NumericUpDown upDown)
- {
- int a;
- bool result = int.TryParse(upDown.Text, out a);
-
- if (result && (a <= (int)upDown.Maximum) && (a >= (int)upDown.Minimum))
- {
- return true;
- }
- else
- {
- return false;
- }
- }
-
- public static void SetNumericUpDownValue(NumericUpDown upDown, decimal newValue)
- {
- if (upDown.Value != newValue)
- {
- upDown.Value = newValue;
- }
- }
-
- public static void SetNumericUpDownValue(NumericUpDown upDown, int newValue)
- {
- SetNumericUpDownValue(upDown, (decimal)newValue);
- }
-
- public static string SizeStringFromBytes(long bytes)
- {
- double bytesDouble = (double)bytes;
- string toStringFormat;
- string formatString;
-
- if (bytesDouble > (1024 * 1024 * 1024))
- {
- // Gigs
- bytesDouble /= 1024 * 1024 * 1024;
- toStringFormat = "F1";
- formatString = PdnResources.GetString("Utility.SizeStringFromBytes.GBFormat");
- }
- else if (bytesDouble > (1024 * 1024))
- {
- // Megs
- bytesDouble /= 1024 * 1024;
- toStringFormat = "F1";
- formatString = PdnResources.GetString("Utility.SizeStringFromBytes.MBFormat");
- }
- else if (bytesDouble > (1024))
- {
- // K
- bytesDouble /= 1024;
- toStringFormat = "F1";
- formatString = PdnResources.GetString("Utility.SizeStringFromBytes.KBFormat");
- }
- else
- {
- // Bytes
- toStringFormat = "F0";
- formatString = PdnResources.GetString("Utility.SizeStringFromBytes.BytesFormat");
- }
-
- string bytesString = bytesDouble.ToString(toStringFormat);
- string sizeString = string.Format(formatString, bytesString);
-
- return sizeString;
- }
-
- public static void ShowWiaError(IWin32Window owner)
- {
- // WIA requires Windows XP SP1 or later, or Windows Server 2003
- // So if we know they're on WS2k3, we tell them to enable WIA.
- // If they're on XP or later, tell them that WIA isn't available.
- // Otherwise we tell them they need XP SP1 (for the Win2K folks).
- if (OS.Type == OSType.Server)
- {
- Utility.ErrorBox(owner, PdnResources.GetString("WIA.Error.EnableMe"));
- }
- else
- {
- Utility.ErrorBox(owner, PdnResources.GetString("WIA.Error.UnableToLoad"));
- }
- }
-
- public static void ShowNonAdminErrorBox(IWin32Window parent)
- {
- ErrorBox(parent, PdnResources.GetString("NonAdminErrorBox.Message"));
- }
-
- public static void ErrorBox(IWin32Window parent, string message)
- {
- MessageBox.Show(parent, message, PdnInfo.GetBareProductName(), MessageBoxButtons.OK, MessageBoxIcon.Error);
- }
-
- public static DialogResult ErrorBoxOKCancel(IWin32Window parent, string message)
- {
- return MessageBox.Show(parent, message, PdnInfo.GetBareProductName(), MessageBoxButtons.OKCancel, MessageBoxIcon.Error);
- }
-
- public static void InfoBox(IWin32Window parent, string message)
- {
- MessageBox.Show(parent, message, PdnInfo.GetBareProductName(), MessageBoxButtons.OK, MessageBoxIcon.Information);
- }
-
- public static DialogResult InfoBoxOKCancel(IWin32Window parent, string message)
- {
- return MessageBox.Show(parent, message, PdnInfo.GetBareProductName(), MessageBoxButtons.OKCancel, MessageBoxIcon.Information);
- }
-
- public static DialogResult AskOKCancel(IWin32Window parent, string question)
- {
- return MessageBox.Show(parent, question, PdnInfo.GetBareProductName(), MessageBoxButtons.OKCancel, MessageBoxIcon.Question);
- }
-
- public static DialogResult AskYesNo(IWin32Window parent, string question)
- {
- return MessageBox.Show(parent, question, PdnInfo.GetBareProductName(), MessageBoxButtons.YesNo, MessageBoxIcon.Question);
- }
-
- public static DialogResult AskYesNoCancel(IWin32Window parent, string question)
- {
- return MessageBox.Show(parent, question, PdnInfo.GetBareProductName(), MessageBoxButtons.YesNoCancel, MessageBoxIcon.Question);
- }
-
- public static Icon ImageToIcon(Image image)
- {
- return ImageToIcon(image, Utility.TransparentKey);
- }
-
- public static Icon ImageToIcon(Image image, bool disposeImage)
- {
- return ImageToIcon(image, Utility.TransparentKey, disposeImage);
- }
-
- public static Icon ImageToIcon(Image image, Color seeThru)
- {
- return ImageToIcon(image, seeThru, false);
- }
-
- /// <summary>
- /// Converts an Image to an Icon.
- /// </summary>
- /// <param name="image">The Image to convert to an icon. Must be an appropriate icon size (32x32, 16x16, etc).</param>
- /// <param name="seeThru">The color that will be treated as transparent in the icon.</param>
- /// <param name="disposeImage">Whether or not to dispose the passed-in Image.</param>
- /// <returns>An Icon representation of the Image.</returns>
- public static Icon ImageToIcon(Image image, Color seeThru, bool disposeImage)
- {
- Bitmap bitmap = new Bitmap(image);
-
- for (int y = 0; y < bitmap.Height; ++y)
- {
- for (int x = 0; x < bitmap.Width; ++x)
- {
- if (bitmap.GetPixel(x, y) == seeThru)
- {
- bitmap.SetPixel(x, y, Color.FromArgb(0));
- }
- }
- }
-
- Icon icon = Icon.FromHandle(bitmap.GetHicon());
- bitmap.Dispose();
-
- if (disposeImage)
- {
- image.Dispose();
- }
-
- return icon;
- }
-
- public static Icon BitmapToIcon(Bitmap bitmap, bool disposeBitmap)
- {
- Icon icon = Icon.FromHandle(bitmap.GetHicon());
-
- if (disposeBitmap)
- {
- bitmap.Dispose();
- }
-
- return icon;
- }
-
- public static Icon SurfaceToIcon(Surface surface, bool disposeSurface)
- {
- Bitmap bitmap = surface.CreateAliasedBitmap();
- Icon icon = Icon.FromHandle(bitmap.GetHicon());
-
- bitmap.Dispose();
-
- if (disposeSurface)
- {
- surface.Dispose();
- }
-
- return icon;
- }
-
- public static Point GetRectangleCenter(Rectangle rect)
- {
- return new Point((rect.Left + rect.Right) / 2, (rect.Top + rect.Bottom) / 2);
- }
-
- public static PointF GetRectangleCenter(RectangleF rect)
- {
- return new PointF((rect.Left + rect.Right) / 2, (rect.Top + rect.Bottom) / 2);
- }
-
- public static Scanline[] GetRectangleScans(Rectangle rect)
- {
- Scanline[] scans = new Scanline[rect.Height];
-
- for (int y = 0; y < rect.Height; ++y)
- {
- scans[y] = new Scanline(rect.X, rect.Y + y, rect.Width);
- }
-
- return scans;
- }
-
- public static Scanline[] GetRegionScans(Rectangle[] region)
- {
- int scanCount = 0;
-
- for (int i = 0; i < region.Length; ++i)
- {
- scanCount += region[i].Height;
- }
-
- Scanline[] scans = new Scanline[scanCount];
- int scanIndex = 0;
-
- foreach (Rectangle rect in region)
- {
- for (int y = 0; y < rect.Height; ++y)
- {
- scans[scanIndex] = new Scanline(rect.X, rect.Y + y, rect.Width);
- ++scanIndex;
- }
- }
-
- return scans;
- }
-
- public static Rectangle[] ScanlinesToRectangles(Scanline[] scans)
- {
- return ScanlinesToRectangles(scans, 0, scans.Length);
- }
-
- public static Rectangle[] ScanlinesToRectangles(Scanline[] scans, int startIndex, int length)
- {
- Rectangle[] rects = new Rectangle[length];
-
- for (int i = 0; i < length; ++i)
- {
- Scanline scan = scans[i + startIndex];
- rects[i] = new Rectangle(scan.X, scan.Y, scan.Length, 1);
- }
-
- return rects;
- }
-
- /// <summary>
- /// Found on Google Groups when searching for "Region.Union" while looking
- /// for bugs:
- /// ---
- /// Hello,
- ///
- /// I did not run your code, but I know Region.Union is flawed in both 1.0 and
- /// 1.1, so I assume it is in the gdi+ unmanged code dll. The best workaround,
- /// in terms of speed, is to use a PdnGraphicsPath, but it must be a path with
- /// FillMode = FillMode.Winding. You add the rectangles to the path, then you do
- /// union onto an empty region with the path. The important point is to do only
- /// one union call on a given empty region. We created a "super region" object
- /// to hide all these bugs and optimize clipping operations. In fact, it is much
- /// faster to use the path than to call Region.Union for each rectangle.
- ///
- /// Too bad about Region.Union. A lot of people will hit this bug, as it is
- /// essential in high-performance animation.
- ///
- /// Regards,
- /// Frank Hileman
- /// Prodige Software Corporation
- /// ---
- /// </summary>
- /// <param name="rectsF"></param>
- /// <param name="startIndex"></param>
- /// <param name="length"></param>
- /// <returns></returns>
- public static PdnRegion RectanglesToRegion(RectangleF[] rectsF, int startIndex, int length)
- {
- PdnRegion region;
-
- if (rectsF == null || rectsF.Length == 0 || length == 0)
- {
- region = PdnRegion.CreateEmpty();
- }
- else
- {
- using (PdnGraphicsPath path = new PdnGraphicsPath())
- {
- path.FillMode = FillMode.Winding;
-
- if (startIndex == 0 && length == rectsF.Length)
- {
- path.AddRectangles(rectsF);
- }
- else
- {
- for (int i = startIndex; i < startIndex + length; ++i)
- {
- path.AddRectangle(rectsF[i]);
- }
- }
-
- region = new PdnRegion(path);
- }
- }
-
- return region;
- }
-
- public static PdnRegion RectanglesToRegion(RectangleF[] rectsF)
- {
- return RectanglesToRegion(rectsF, 0, rectsF != null ? rectsF.Length : 0);
- }
-
- public static PdnRegion RectanglesToRegion(RectangleF[] rectsF1, RectangleF[] rectsF2, params RectangleF[][] rectsFA)
- {
- using (PdnGraphicsPath path = new PdnGraphicsPath())
- {
- path.FillMode = FillMode.Winding;
-
- if (rectsF1 != null && rectsF1.Length > 0)
- {
- path.AddRectangles(rectsF1);
- }
-
- if (rectsF2 != null && rectsF2.Length > 0)
- {
- path.AddRectangles(rectsF2);
- }
-
- foreach (RectangleF[] rectsF in rectsFA)
- {
- if (rectsF != null && rectsF.Length > 0)
- {
- path.AddRectangles(rectsF);
- }
- }
-
- return new PdnRegion(path);
- }
- }
-
- public static PdnRegion RectanglesToRegion(Rectangle[] rects, int startIndex, int length)
- {
- PdnRegion region;
-
- if (length == 0)
- {
- region = PdnRegion.CreateEmpty();
- }
- else
- {
- using (PdnGraphicsPath path = new PdnGraphicsPath())
- {
- path.FillMode = FillMode.Winding;
- if (startIndex == 0 && length == rects.Length)
- {
- path.AddRectangles(rects);
- }
- else
- {
- for (int i = startIndex; i < startIndex + length; ++i)
- {
- path.AddRectangle(rects[i]);
- }
- }
-
- region = new PdnRegion(path);
- path.Dispose();
- }
- }
-
- return region;
- }
-
- public static PdnRegion RectanglesToRegion(Rectangle[] rects)
- {
- return RectanglesToRegion(rects, 0, rects.Length);
- }
-
- public static int GetRegionArea(RectangleF[] rectsF)
- {
- int area = 0;
-
- foreach (RectangleF rectF in rectsF)
- {
- Rectangle rect = Rectangle.Truncate(rectF);
- area += rect.Width * rect.Height;
- }
-
- return area;
- }
-
- public static RectangleF RectangleFromCenter(PointF center, float halfSize)
- {
- RectangleF ret = new RectangleF(center.X, center.Y, 0, 0);
- ret.Inflate(halfSize, halfSize);
- return ret;
- }
-
- public static List<PointF> PointListToPointFList(List<Point> ptList)
- {
- List<PointF> ret = new List<PointF>(ptList.Count);
-
- for (int i = 0; i < ptList.Count; ++i)
- {
- ret.Add((PointF)ptList[i]);
- }
-
- return ret;
- }
-
- public static PointF[] PointArrayToPointFArray(Point[] ptArray)
- {
- PointF[] ret = new PointF[ptArray.Length];
-
- for (int i = 0; i < ret.Length; ++i)
- {
- ret[i] = (PointF)ptArray[i];
- }
-
- return ret;
- }
-
- public static Rectangle[] InflateRectangles(Rectangle[] rects, int amount)
- {
- Rectangle[] inflated = new Rectangle[rects.Length];
-
- for (int i = 0; i < rects.Length; ++i)
- {
- inflated[i] = Rectangle.Inflate(rects[i], amount, amount);
- }
-
- return inflated;
- }
-
- public static void InflateRectanglesInPlace(Rectangle[] rects, int amount)
- {
- for (int i = 0; i < rects.Length; ++i)
- {
- rects[i].Inflate(amount, amount);
- }
- }
-
- public static RectangleF[] InflateRectangles(RectangleF[] rectsF, int amount)
- {
- RectangleF[] inflated = new RectangleF[rectsF.Length];
-
- for (int i = 0; i < rectsF.Length; ++i)
- {
- inflated[i] = RectangleF.Inflate(rectsF[i], amount, amount);
- }
-
- return inflated;
- }
-
- public static void InflateRectanglesInPlace(RectangleF[] rectsF, float amount)
- {
- for (int i = 0; i < rectsF.Length; ++i)
- {
- rectsF[i].Inflate(amount, amount);
- }
- }
-
- public static Rectangle PointsToConstrainedRectangle(Point a, Point b)
- {
- Rectangle rect = Utility.PointsToRectangle(a, b);
- int minWH = Math.Min(rect.Width, rect.Height);
-
- rect.Width = minWH;
- rect.Height = minWH;
-
- if (rect.Y != a.Y)
- {
- rect.Location = new Point(rect.X, a.Y - minWH);
- }
-
- if (rect.X != a.X)
- {
- rect.Location = new Point(a.X - minWH, rect.Y);
- }
-
- return rect;
- }
-
- public static RectangleF PointsToConstrainedRectangle(PointF a, PointF b)
- {
- RectangleF rect = Utility.PointsToRectangle(a, b);
- float minWH = Math.Min(rect.Width, rect.Height);
-
- rect.Width = minWH;
- rect.Height = minWH;
-
- if (rect.Y != a.Y)
- {
- rect.Location = new PointF(rect.X, a.Y - minWH);
- }
-
- if (rect.X != a.X)
- {
- rect.Location = new PointF(a.X - minWH, rect.Y);
- }
-
- return rect;
- }
-
- /// <summary>
- /// Takes two points and creates a bounding rectangle from them.
- /// </summary>
- /// <param name="a">One corner of the rectangle.</param>
- /// <param name="b">The other corner of the rectangle.</param>
- /// <returns>A Rectangle instance that bounds the two points.</returns>
- public static Rectangle PointsToRectangle(Point a, Point b)
- {
- int x = Math.Min(a.X, b.X);
- int y = Math.Min(a.Y, b.Y);
- int width = Math.Abs(a.X - b.X) + 1;
- int height = Math.Abs(a.Y - b.Y) + 1;
-
- return new Rectangle(x, y, width, height);
- }
-
- public static RectangleF PointsToRectangle(PointF a, PointF b)
- {
- float x = Math.Min(a.X, b.X);
- float y = Math.Min(a.Y, b.Y);
- float width = Math.Abs(a.X - b.X) + 1;
- float height = Math.Abs(a.Y - b.Y) + 1;
-
- return new RectangleF(x, y, width, height);
- }
-
- public static Rectangle PointsToRectangleExclusive(Point a, Point b)
- {
- int x = Math.Min(a.X, b.X);
- int y = Math.Min(a.Y, b.Y);
- int width = Math.Abs(a.X - b.X);
- int height = Math.Abs(a.Y - b.Y);
-
- return new Rectangle(x, y, width, height);
- }
-
- public static RectangleF PointsToRectangleExclusive(PointF a, PointF b)
- {
- float x = Math.Min(a.X, b.X);
- float y = Math.Min(a.Y, b.Y);
- float width = Math.Abs(a.X - b.X);
- float height = Math.Abs(a.Y - b.Y);
-
- return new RectangleF(x, y, width, height);
- }
-
- public static RectangleF[] PointsToRectangles(PointF[] pointsF)
- {
- if (pointsF.Length == 0)
- {
- return new RectangleF[] { };
- }
-
- if (pointsF.Length == 1)
- {
- return new RectangleF[] { new RectangleF(pointsF[0].X, pointsF[0].Y, 1, 1) };
- }
-
- RectangleF[] rectsF = new RectangleF[pointsF.Length - 1];
-
- for (int i = 0; i < pointsF.Length - 1; ++i)
- {
- rectsF[i] = PointsToRectangle(pointsF[i], pointsF[i + 1]);
- }
-
- return rectsF;
- }
-
- public static Rectangle[] PointsToRectangles(Point[] points)
- {
- if (points.Length == 0)
- {
- return new Rectangle[] { };
- }
-
- if (points.Length == 1)
- {
- return new Rectangle[] { new Rectangle(points[0].X, points[0].Y, 1, 1) };
- }
-
- Rectangle[] rects = new Rectangle[points.Length - 1];
-
- for (int i = 0; i < points.Length - 1; ++i)
- {
- rects[i] = PointsToRectangle(points[i], points[i + 1]);
- }
-
- return rects;
- }
-
- /// <summary>
- /// Converts a RectangleF to RectangleF by rounding down the Location and rounding
- /// up the Size.
- /// </summary>
- public static Rectangle RoundRectangle(RectangleF rectF)
- {
- float left = (float)Math.Floor(rectF.Left);
- float top = (float)Math.Floor(rectF.Top);
- float right = (float)Math.Ceiling(rectF.Right);
- float bottom = (float)Math.Ceiling(rectF.Bottom);
-
- return Rectangle.Truncate(RectangleF.FromLTRB(left, top, right, bottom));
- }
-
- public static Stack Reverse(Stack reverseMe)
- {
- Stack reversed = new Stack();
-
- foreach (object o in reverseMe)
- {
- reversed.Push(o);
- }
-
- return reversed;
- }
-
- public static void SerializeObjectToStream(object graph, Stream stream)
- {
- new BinaryFormatter().Serialize(stream, graph);
- }
-
- public static object DeserializeObjectFromStream(Stream stream)
- {
- return new BinaryFormatter().Deserialize(stream);
- }
-
- [Obsolete("Use rect.Contains() instead", true)]
- public static bool IsPointInRectangle(Point pt, Rectangle rect)
- {
- return rect.Contains(pt);
- }
-
- [Obsolete("Use rect.Contains() instead", true)]
- public static bool IsPointInRectangle(int x, int y, Rectangle rect)
- {
- return rect.Contains(x, y);
- }
-
- public static Bitmap FullCloneBitmap(Bitmap cloneMe)
- {
- Bitmap bitmap = new Bitmap(cloneMe.Width, cloneMe.Height, cloneMe.PixelFormat);
-
- using (Graphics g = Graphics.FromImage(bitmap))
- {
- g.DrawImage(cloneMe, 0, 0, cloneMe.Width, cloneMe.Height);
- }
-
- return bitmap;
- }
-
- /// <summary>
- /// Allows you to find the bounding box for a Region object without requiring
- /// the presence of a Graphics object.
- /// (Region.GetBounds takes a Graphics instance as its only parameter.)
- /// </summary>
- /// <param name="region">The region you want to find a bounding box for.</param>
- /// <returns>A RectangleF structure that surrounds the Region.</returns>
- public static Rectangle GetRegionBounds(PdnRegion region)
- {
- Rectangle[] rects = region.GetRegionScansReadOnlyInt();
- return GetRegionBounds(rects, 0, rects.Length);
- }
-
- /// <summary>
- /// Allows you to find the bounding box for a "region" that is described as an
- /// array of bounding boxes.
- /// </summary>
- /// <param name="rectsF">The "region" you want to find a bounding box for.</param>
- /// <returns>A RectangleF structure that surrounds the Region.</returns>
- public static RectangleF GetRegionBounds(RectangleF[] rectsF, int startIndex, int length)
- {
- if (rectsF.Length == 0)
- {
- return RectangleF.Empty;
- }
-
- float left = rectsF[startIndex].Left;
- float top = rectsF[startIndex].Top;
- float right = rectsF[startIndex].Right;
- float bottom = rectsF[startIndex].Bottom;
-
- for (int i = startIndex + 1; i < startIndex + length; ++i)
- {
- RectangleF rectF = rectsF[i];
-
- if (rectF.Left < left)
- {
- left = rectF.Left;
- }
-
- if (rectF.Top < top)
- {
- top = rectF.Top;
- }
-
- if (rectF.Right > right)
- {
- right = rectF.Right;
- }
-
- if (rectF.Bottom > bottom)
- {
- bottom = rectF.Bottom;
- }
- }
-
- return RectangleF.FromLTRB(left, top, right, bottom);
- }
-
- public static RectangleF GetTraceBounds(PointF[] pointsF, int startIndex, int length)
- {
- if (pointsF.Length == 0)
- {
- return RectangleF.Empty;
- }
-
- float left = pointsF[startIndex].X;
- float top = pointsF[startIndex].Y;
- float right = 1 + pointsF[startIndex].X;
- float bottom = 1 + pointsF[startIndex].Y;
-
- for (int i = startIndex + 1; i < startIndex + length; ++i)
- {
- PointF pointF = pointsF[i];
-
- if (pointF.X < left)
- {
- left = pointF.X;
- }
-
- if (pointF.Y < top)
- {
- top = pointF.Y;
- }
-
- if (pointF.X > right)
- {
- right = pointF.X;
- }
-
- if (pointF.Y > bottom)
- {
- bottom = pointF.Y;
- }
- }
-
- return RectangleF.FromLTRB(left, top, right, bottom);
- }
-
- public static Rectangle GetTraceBounds(Point[] points, int startIndex, int length)
- {
- if (points.Length == 0)
- {
- return Rectangle.Empty;
- }
-
- int left = points[startIndex].X;
- int top = points[startIndex].Y;
- int right = 1 + points[startIndex].X;
- int bottom = 1 + points[startIndex].Y;
-
- for (int i = startIndex + 1; i < startIndex + length; ++i)
- {
- Point point = points[i];
-
- if (point.X < left)
- {
- left = point.X;
- }
-
- if (point.Y < top)
- {
- top = point.Y;
- }
-
- if (point.X > right)
- {
- right = point.X;
- }
-
- if (point.Y > bottom)
- {
- bottom = point.Y;
- }
- }
-
- return Rectangle.FromLTRB(left, top, right, bottom);
- }
-
- /// <summary>
- /// Allows you to find the bounding box for a "region" that is described as an
- /// array of bounding boxes.
- /// </summary>
- /// <param name="rectsF">The "region" you want to find a bounding box for.</param>
- /// <returns>A RectangleF structure that surrounds the Region.</returns>
- public static Rectangle GetRegionBounds(Rectangle[] rects, int startIndex, int length)
- {
- if (rects.Length == 0)
- {
- return Rectangle.Empty;
- }
-
- int left = rects[startIndex].Left;
- int top = rects[startIndex].Top;
- int right = rects[startIndex].Right;
- int bottom = rects[startIndex].Bottom;
-
- for (int i = startIndex + 1; i < startIndex + length; ++i)
- {
- Rectangle rect = rects[i];
-
- if (rect.Left < left)
- {
- left = rect.Left;
- }
-
- if (rect.Top < top)
- {
- top = rect.Top;
- }
-
- if (rect.Right > right)
- {
- right = rect.Right;
- }
-
- if (rect.Bottom > bottom)
- {
- bottom = rect.Bottom;
- }
- }
-
- return Rectangle.FromLTRB(left, top, right, bottom);
- }
-
- public static RectangleF GetRegionBounds(RectangleF[] rectsF)
- {
- return GetRegionBounds(rectsF, 0, rectsF.Length);
- }
-
- public static Rectangle GetRegionBounds(Rectangle[] rects)
- {
- return GetRegionBounds(rects, 0, rects.Length);
- }
-
- private static float DistanceSquared(RectangleF[] rectsF, int indexA, int indexB)
- {
- PointF centerA = new PointF(rectsF[indexA].Left + (rectsF[indexA].Width / 2), rectsF[indexA].Top + (rectsF[indexA].Height / 2));
- PointF centerB = new PointF(rectsF[indexB].Left + (rectsF[indexB].Width / 2), rectsF[indexB].Top + (rectsF[indexB].Height / 2));
-
- return ((centerA.X - centerB.X) * (centerA.X - centerB.X)) +
- ((centerA.Y - centerB.Y) * (centerA.Y - centerB.Y));
- }
-
- /// <summary>
- /// Simplifies a Region into N number of bounding boxes.
- /// </summary>
- /// <param name="region">The Region to simplify.</param>
- /// <param name="complexity">The maximum number of bounding boxes to return, or 0 for however many are necessary (equivalent to using Region.GetRegionScans).</param>
- /// <returns></returns>
- public static Rectangle[] SimplifyRegion(PdnRegion region, int complexity)
- {
- Rectangle[] rects = region.GetRegionScansReadOnlyInt();
- return SimplifyRegion(rects, complexity);
- }
-
- public static Rectangle[] SimplifyRegion(Rectangle[] rects, int complexity)
- {
- if (complexity == 0 || rects.Length < complexity)
- {
- return (Rectangle[])rects.Clone();
- }
-
- Rectangle[] boxes = new Rectangle[complexity];
-
- for (int i = 0; i < complexity; ++i)
- {
- int startIndex = (i * rects.Length) / complexity;
- int length = Math.Min(rects.Length, ((i + 1) * rects.Length) / complexity) - startIndex;
- boxes[i] = GetRegionBounds(rects, startIndex, length);
- }
-
- return boxes;
- }
-
-
- public static RectangleF[] SimplifyTrace(PointF[] pointsF, int complexity)
- {
- if (complexity == 0 ||
- (pointsF.Length - 1) < complexity)
- {
- return PointsToRectangles(pointsF);
- }
-
- RectangleF[] boxes = new RectangleF[complexity];
- int parLength = pointsF.Length - 1; // "(points as Rectangles).Length"
-
- for (int i = 0; i < complexity; ++i)
- {
- int startIndex = (i * parLength) / complexity;
- int length = Math.Min(parLength, ((i + 1) * parLength) / complexity) - sta…
Large files files are truncated, but you can click here to view the full file