aboutsummaryrefslogtreecommitdiffstats
path: root/Software/Visual_Studio/SideChains/RealTimeGraphEx/WriteableBitmap/WriteableBitmapTransformationExtensions.cs
diff options
context:
space:
mode:
authorRoy Ben-Shabat <Roy@Twine-s.com>2018-01-16 12:17:10 +0200
committerRoy Ben-Shabat <Roy@Twine-s.com>2018-01-16 12:17:10 +0200
commit0fda2ba3ff49bdc1ffc6833f658e2164af187008 (patch)
tree6f3a24d0671ebda50debb8511ab40e0bda0a0df0 /Software/Visual_Studio/SideChains/RealTimeGraphEx/WriteableBitmap/WriteableBitmapTransformationExtensions.cs
parent28103646681686bf1b58275d5dbccb92d2b26f9f (diff)
downloadTango-0fda2ba3ff49bdc1ffc6833f658e2164af187008.tar.gz
Tango-0fda2ba3ff49bdc1ffc6833f658e2164af187008.zip
Embedded RealTimeGraphEx library to solution.
Added graphs to technician view. Implemented simple sensors data test using Machine Emulator.
Diffstat (limited to 'Software/Visual_Studio/SideChains/RealTimeGraphEx/WriteableBitmap/WriteableBitmapTransformationExtensions.cs')
-rw-r--r--Software/Visual_Studio/SideChains/RealTimeGraphEx/WriteableBitmap/WriteableBitmapTransformationExtensions.cs623
1 files changed, 623 insertions, 0 deletions
diff --git a/Software/Visual_Studio/SideChains/RealTimeGraphEx/WriteableBitmap/WriteableBitmapTransformationExtensions.cs b/Software/Visual_Studio/SideChains/RealTimeGraphEx/WriteableBitmap/WriteableBitmapTransformationExtensions.cs
new file mode 100644
index 000000000..afdda8d75
--- /dev/null
+++ b/Software/Visual_Studio/SideChains/RealTimeGraphEx/WriteableBitmap/WriteableBitmapTransformationExtensions.cs
@@ -0,0 +1,623 @@
+#region Header
+//
+// Project: WriteableBitmapEx - WriteableBitmap extensions
+// Description: Collection of transformation extension methods for the WriteableBitmap class.
+//
+// Changed by: $Author: unknown $
+// Changed on: $Date: 2015-03-05 18:18:24 +0100 (Do, 05 Mrz 2015) $
+// Changed in: $Revision: 113191 $
+// Project: $URL: https://writeablebitmapex.svn.codeplex.com/svn/trunk/Source/WriteableBitmapEx/WriteableBitmapTransformationExtensions.cs $
+// Id: $Id: WriteableBitmapTransformationExtensions.cs 113191 2015-03-05 17:18:24Z unknown $
+//
+//
+// Copyright © 2009-2015 Rene Schulte and WriteableBitmapEx Contributors
+//
+// This code is open source. Please read the License.txt for details. No worries, we won't sue you! ;)
+//
+#endregion
+
+using System;
+
+#if NETFX_CORE
+using Windows.Foundation;
+
+namespace Windows.UI.Xaml.Media.Imaging
+#else
+namespace System.Windows.Media.Imaging
+#endif
+{
+ /// <summary>
+ /// Collection of transformation extension methods for the WriteableBitmap class.
+ /// </summary>
+ internal
+#if WPF
+ unsafe
+#endif
+ static partial class WriteableBitmapExtensions
+ {
+ #region Enums
+
+ /// <summary>
+ /// The interpolation method.
+ /// </summary>
+ internal enum Interpolation
+ {
+ /// <summary>
+ /// The nearest neighbor algorithm simply selects the color of the nearest pixel.
+ /// </summary>
+ NearestNeighbor = 0,
+
+ /// <summary>
+ /// Linear interpolation in 2D using the average of 3 neighboring pixels.
+ /// </summary>
+ Bilinear,
+ }
+
+ /// <summary>
+ /// The mode for flipping.
+ /// </summary>
+ internal enum FlipMode
+ {
+ /// <summary>
+ /// Flips the image vertical (around the center of the y-axis).
+ /// </summary>
+ Vertical,
+
+ /// <summary>
+ /// Flips the image horizontal (around the center of the x-axis).
+ /// </summary>
+ Horizontal
+ }
+
+ #endregion
+
+ #region Methods
+
+ #region Crop
+
+ /// <summary>
+ /// Creates a new cropped WriteableBitmap.
+ /// </summary>
+ /// <param name="bmp">The WriteableBitmap.</param>
+ /// <param name="x">The x coordinate of the rectangle that defines the crop region.</param>
+ /// <param name="y">The y coordinate of the rectangle that defines the crop region.</param>
+ /// <param name="width">The width of the rectangle that defines the crop region.</param>
+ /// <param name="height">The height of the rectangle that defines the crop region.</param>
+ /// <returns>A new WriteableBitmap that is a cropped version of the input.</returns>
+ internal static WriteableBitmap Crop(this WriteableBitmap bmp, int x, int y, int width, int height)
+ {
+ using (var srcContext = bmp.GetBitmapContext())
+ {
+ var srcWidth = srcContext.Width;
+ var srcHeight = srcContext.Height;
+
+ // If the rectangle is completely out of the bitmap
+ if (x > srcWidth || y > srcHeight)
+ {
+ return BitmapFactory.New(0, 0);
+ }
+
+ // Clamp to boundaries
+ if (x < 0) x = 0;
+ if (x + width > srcWidth) width = srcWidth - x;
+ if (y < 0) y = 0;
+ if (y + height > srcHeight) height = srcHeight - y;
+
+ // Copy the pixels line by line using fast BlockCopy
+ var result = BitmapFactory.New(width, height);
+ using (var destContext = result.GetBitmapContext())
+ {
+ for (var line = 0; line < height; line++)
+ {
+ var srcOff = ((y + line) * srcWidth + x) * SizeOfArgb;
+ var dstOff = line * width * SizeOfArgb;
+ BitmapContext.BlockCopy(srcContext, srcOff, destContext, dstOff, width * SizeOfArgb);
+ }
+
+ return result;
+ }
+ }
+ }
+ /// <summary>
+ /// Creates a new cropped WriteableBitmap.
+ /// </summary>
+ /// <param name="bmp">The WriteableBitmap.</param>
+ /// <param name="region">The rectangle that defines the crop region.</param>
+ /// <returns>A new WriteableBitmap that is a cropped version of the input.</returns>
+ internal static WriteableBitmap Crop(this WriteableBitmap bmp, Rect region)
+ {
+ return bmp.Crop((int)region.X, (int)region.Y, (int)region.Width, (int)region.Height);
+ }
+
+ #endregion
+
+ #region Resize
+
+ /// <summary>
+ /// Creates a new resized WriteableBitmap.
+ /// </summary>
+ /// <param name="bmp">The WriteableBitmap.</param>
+ /// <param name="width">The new desired width.</param>
+ /// <param name="height">The new desired height.</param>
+ /// <param name="interpolation">The interpolation method that should be used.</param>
+ /// <returns>A new WriteableBitmap that is a resized version of the input.</returns>
+ internal static WriteableBitmap Resize(this WriteableBitmap bmp, int width, int height, Interpolation interpolation)
+ {
+ using (var srcContext = bmp.GetBitmapContext())
+ {
+ var pd = Resize(srcContext, srcContext.Width, srcContext.Height, width, height, interpolation);
+
+ var result = BitmapFactory.New(width, height);
+ using (var dstContext = result.GetBitmapContext())
+ {
+ BitmapContext.BlockCopy(pd, 0, dstContext, 0, SizeOfArgb * pd.Length);
+ }
+ return result;
+ }
+ }
+
+ /// <summary>
+ /// Creates a new resized bitmap.
+ /// </summary>
+ /// <param name="srcContext">The source context.</param>
+ /// <param name="widthSource">The width of the source pixels.</param>
+ /// <param name="heightSource">The height of the source pixels.</param>
+ /// <param name="width">The new desired width.</param>
+ /// <param name="height">The new desired height.</param>
+ /// <param name="interpolation">The interpolation method that should be used.</param>
+ /// <returns>A new bitmap that is a resized version of the input.</returns>
+ internal static int[] Resize(BitmapContext srcContext, int widthSource, int heightSource, int width, int height, Interpolation interpolation)
+ {
+ return Resize(srcContext.Pixels, widthSource, heightSource, width, height, interpolation);
+ }
+
+ /// <summary>
+ /// Creates a new resized bitmap.
+ /// </summary>
+ /// <param name="pixels">The source pixels.</param>
+ /// <param name="widthSource">The width of the source pixels.</param>
+ /// <param name="heightSource">The height of the source pixels.</param>
+ /// <param name="width">The new desired width.</param>
+ /// <param name="height">The new desired height.</param>
+ /// <param name="interpolation">The interpolation method that should be used.</param>
+ /// <returns>A new bitmap that is a resized version of the input.</returns>
+#if WPF
+ internal static int[] Resize(int* pixels, int widthSource, int heightSource, int width, int height, Interpolation interpolation)
+#else
+ internal static int[] Resize(int[] pixels, int widthSource, int heightSource, int width, int height, Interpolation interpolation)
+#endif
+ {
+ var pd = new int[width * height];
+ var xs = (float)widthSource / width;
+ var ys = (float)heightSource / height;
+
+ float fracx, fracy, ifracx, ifracy, sx, sy, l0, l1, rf, gf, bf;
+ int c, x0, x1, y0, y1;
+ byte c1a, c1r, c1g, c1b, c2a, c2r, c2g, c2b, c3a, c3r, c3g, c3b, c4a, c4r, c4g, c4b;
+ byte a, r, g, b;
+
+ // Nearest Neighbor
+ if (interpolation == Interpolation.NearestNeighbor)
+ {
+ var srcIdx = 0;
+ for (var y = 0; y < height; y++)
+ {
+ for (var x = 0; x < width; x++)
+ {
+ sx = x * xs;
+ sy = y * ys;
+ x0 = (int)sx;
+ y0 = (int)sy;
+
+ pd[srcIdx++] = pixels[y0 * widthSource + x0];
+ }
+ }
+ }
+
+ // Bilinear
+ else if (interpolation == Interpolation.Bilinear)
+ {
+ var srcIdx = 0;
+ for (var y = 0; y < height; y++)
+ {
+ for (var x = 0; x < width; x++)
+ {
+ sx = x * xs;
+ sy = y * ys;
+ x0 = (int)sx;
+ y0 = (int)sy;
+
+ // Calculate coordinates of the 4 interpolation points
+ fracx = sx - x0;
+ fracy = sy - y0;
+ ifracx = 1f - fracx;
+ ifracy = 1f - fracy;
+ x1 = x0 + 1;
+ if (x1 >= widthSource)
+ {
+ x1 = x0;
+ }
+ y1 = y0 + 1;
+ if (y1 >= heightSource)
+ {
+ y1 = y0;
+ }
+
+
+ // Read source color
+ c = pixels[y0 * widthSource + x0];
+ c1a = (byte)(c >> 24);
+ c1r = (byte)(c >> 16);
+ c1g = (byte)(c >> 8);
+ c1b = (byte)(c);
+
+ c = pixels[y0 * widthSource + x1];
+ c2a = (byte)(c >> 24);
+ c2r = (byte)(c >> 16);
+ c2g = (byte)(c >> 8);
+ c2b = (byte)(c);
+
+ c = pixels[y1 * widthSource + x0];
+ c3a = (byte)(c >> 24);
+ c3r = (byte)(c >> 16);
+ c3g = (byte)(c >> 8);
+ c3b = (byte)(c);
+
+ c = pixels[y1 * widthSource + x1];
+ c4a = (byte)(c >> 24);
+ c4r = (byte)(c >> 16);
+ c4g = (byte)(c >> 8);
+ c4b = (byte)(c);
+
+
+ // Calculate colors
+ // Alpha
+ l0 = ifracx * c1a + fracx * c2a;
+ l1 = ifracx * c3a + fracx * c4a;
+ a = (byte)(ifracy * l0 + fracy * l1);
+
+ // Red
+ l0 = ifracx * c1r + fracx * c2r;
+ l1 = ifracx * c3r + fracx * c4r;
+ rf = ifracy * l0 + fracy * l1;
+
+ // Green
+ l0 = ifracx * c1g + fracx * c2g;
+ l1 = ifracx * c3g + fracx * c4g;
+ gf = ifracy * l0 + fracy * l1;
+
+ // Blue
+ l0 = ifracx * c1b + fracx * c2b;
+ l1 = ifracx * c3b + fracx * c4b;
+ bf = ifracy * l0 + fracy * l1;
+
+ // Cast to byte
+ r = (byte)rf;
+ g = (byte)gf;
+ b = (byte)bf;
+
+ // Write destination
+ pd[srcIdx++] = (a << 24) | (r << 16) | (g << 8) | b;
+ }
+ }
+ }
+ return pd;
+ }
+
+ #endregion
+
+ #region Rotate
+
+ /// <summary>
+ /// Rotates the bitmap in 90° steps clockwise and returns a new rotated WriteableBitmap.
+ /// </summary>
+ /// <param name="bmp">The WriteableBitmap.</param>
+ /// <param name="angle">The angle in degrees the bitmap should be rotated in 90° steps clockwise.</param>
+ /// <returns>A new WriteableBitmap that is a rotated version of the input.</returns>
+ internal static WriteableBitmap Rotate(this WriteableBitmap bmp, int angle)
+ {
+ using (var context = bmp.GetBitmapContext())
+ {
+ // Use refs for faster access (really important!) speeds up a lot!
+ var w = context.Width;
+ var h = context.Height;
+ var p = context.Pixels;
+ var i = 0;
+ WriteableBitmap result = null;
+ angle %= 360;
+
+ if (angle > 0 && angle <= 90)
+ {
+ result = BitmapFactory.New(h, w);
+ using (var destContext = result.GetBitmapContext())
+ {
+ var rp = destContext.Pixels;
+ for (var x = 0; x < w; x++)
+ {
+ for (var y = h - 1; y >= 0; y--)
+ {
+ var srcInd = y * w + x;
+ rp[i] = p[srcInd];
+ i++;
+ }
+ }
+ }
+ }
+ else if (angle > 90 && angle <= 180)
+ {
+ result = BitmapFactory.New(w, h);
+ using (var destContext = result.GetBitmapContext())
+ {
+ var rp = destContext.Pixels;
+ for (var y = h - 1; y >= 0; y--)
+ {
+ for (var x = w - 1; x >= 0; x--)
+ {
+ var srcInd = y * w + x;
+ rp[i] = p[srcInd];
+ i++;
+ }
+ }
+ }
+ }
+ else if (angle > 180 && angle <= 270)
+ {
+ result = BitmapFactory.New(h, w);
+ using (var destContext = result.GetBitmapContext())
+ {
+ var rp = destContext.Pixels;
+ for (var x = w - 1; x >= 0; x--)
+ {
+ for (var y = 0; y < h; y++)
+ {
+ var srcInd = y * w + x;
+ rp[i] = p[srcInd];
+ i++;
+ }
+ }
+ }
+ }
+ else
+ {
+ result = bmp.Clone();
+ }
+ return result;
+ }
+ }
+
+ /// <summary>
+ /// Rotates the bitmap in any degree returns a new rotated WriteableBitmap.
+ /// </summary>
+ /// <param name="bmp">The WriteableBitmap.</param>
+ /// <param name="angle">Arbitrary angle in 360 Degrees (positive = clockwise).</param>
+ /// <param name="crop">if true: keep the size, false: adjust canvas to new size</param>
+ /// <returns>A new WriteableBitmap that is a rotated version of the input.</returns>
+ internal static WriteableBitmap RotateFree(this WriteableBitmap bmp, double angle, bool crop = true)
+ {
+ // rotating clockwise, so it's negative relative to Cartesian quadrants
+ double cnAngle = -1.0 * (Math.PI / 180) * angle;
+
+ // general iterators
+ int i, j;
+ // calculated indices in Cartesian coordinates
+ int x, y;
+ double fDistance, fPolarAngle;
+ // for use in neighboring indices in Cartesian coordinates
+ int iFloorX, iCeilingX, iFloorY, iCeilingY;
+ // calculated indices in Cartesian coordinates with trailing decimals
+ double fTrueX, fTrueY;
+ // for interpolation
+ double fDeltaX, fDeltaY;
+
+ // interpolated "top" pixels
+ double fTopRed, fTopGreen, fTopBlue, fTopAlpha;
+
+ // interpolated "bottom" pixels
+ double fBottomRed, fBottomGreen, fBottomBlue, fBottomAlpha;
+
+ // final interpolated color components
+ int iRed, iGreen, iBlue, iAlpha;
+
+ int iCentreX, iCentreY;
+ int iDestCentreX, iDestCentreY;
+ int iWidth, iHeight, newWidth, newHeight;
+ using (var bmpContext = bmp.GetBitmapContext())
+ {
+
+ iWidth = bmpContext.Width;
+ iHeight = bmpContext.Height;
+
+ if (crop)
+ {
+ newWidth = iWidth;
+ newHeight = iHeight;
+ }
+ else
+ {
+ var rad = angle / (180 / Math.PI);
+ newWidth = (int)Math.Ceiling(Math.Abs(Math.Sin(rad) * iHeight) + Math.Abs(Math.Cos(rad) * iWidth));
+ newHeight = (int)Math.Ceiling(Math.Abs(Math.Sin(rad) * iWidth) + Math.Abs(Math.Cos(rad) * iHeight));
+ }
+
+
+ iCentreX = iWidth / 2;
+ iCentreY = iHeight / 2;
+
+ iDestCentreX = newWidth / 2;
+ iDestCentreY = newHeight / 2;
+
+ var bmBilinearInterpolation = BitmapFactory.New(newWidth, newHeight);
+
+ using (var bilinearContext = bmBilinearInterpolation.GetBitmapContext())
+ {
+ var newp = bilinearContext.Pixels;
+ var oldp = bmpContext.Pixels;
+ var oldw = bmpContext.Width;
+
+ // assigning pixels of destination image from source image
+ // with bilinear interpolation
+ for (i = 0; i < newHeight; ++i)
+ {
+ for (j = 0; j < newWidth; ++j)
+ {
+ // convert raster to Cartesian
+ x = j - iDestCentreX;
+ y = iDestCentreY - i;
+
+ // convert Cartesian to polar
+ fDistance = Math.Sqrt(x * x + y * y);
+ if (x == 0)
+ {
+ if (y == 0)
+ {
+ // center of image, no rotation needed
+ newp[i * newWidth + j] = oldp[iCentreY * oldw + iCentreX];
+ continue;
+ }
+ if (y < 0)
+ {
+ fPolarAngle = 1.5 * Math.PI;
+ }
+ else
+ {
+ fPolarAngle = 0.5 * Math.PI;
+ }
+ }
+ else
+ {
+ fPolarAngle = Math.Atan2(y, x);
+ }
+
+ // the crucial rotation part
+ // "reverse" rotate, so minus instead of plus
+ fPolarAngle -= cnAngle;
+
+ // convert polar to Cartesian
+ fTrueX = fDistance * Math.Cos(fPolarAngle);
+ fTrueY = fDistance * Math.Sin(fPolarAngle);
+
+ // convert Cartesian to raster
+ fTrueX = fTrueX + iCentreX;
+ fTrueY = iCentreY - fTrueY;
+
+ iFloorX = (int)(Math.Floor(fTrueX));
+ iFloorY = (int)(Math.Floor(fTrueY));
+ iCeilingX = (int)(Math.Ceiling(fTrueX));
+ iCeilingY = (int)(Math.Ceiling(fTrueY));
+
+ // check bounds
+ if (iFloorX < 0 || iCeilingX < 0 || iFloorX >= iWidth || iCeilingX >= iWidth || iFloorY < 0 ||
+ iCeilingY < 0 || iFloorY >= iHeight || iCeilingY >= iHeight) continue;
+
+ fDeltaX = fTrueX - iFloorX;
+ fDeltaY = fTrueY - iFloorY;
+
+ var clrTopLeft = oldp[iFloorY * oldw + iFloorX];
+ var clrTopRight = oldp[iFloorY * oldw + iCeilingX];
+ var clrBottomLeft = oldp[iCeilingY * oldw + iFloorX];
+ var clrBottomRight = oldp[iCeilingY * oldw + iCeilingX];
+
+ fTopAlpha = (1 - fDeltaX) * ((clrTopLeft >> 24) & 0xFF) + fDeltaX * ((clrTopRight >> 24) & 0xFF);
+ fTopRed = (1 - fDeltaX) * ((clrTopLeft >> 16) & 0xFF) + fDeltaX * ((clrTopRight >> 16) & 0xFF);
+ fTopGreen = (1 - fDeltaX) * ((clrTopLeft >> 8) & 0xFF) + fDeltaX * ((clrTopRight >> 8) & 0xFF);
+ fTopBlue = (1 - fDeltaX) * (clrTopLeft & 0xFF) + fDeltaX * (clrTopRight & 0xFF);
+
+ // linearly interpolate horizontally between bottom neighbors
+ fBottomAlpha = (1 - fDeltaX) * ((clrBottomLeft >> 24) & 0xFF) + fDeltaX * ((clrBottomRight >> 24) & 0xFF);
+ fBottomRed = (1 - fDeltaX) * ((clrBottomLeft >> 16) & 0xFF) + fDeltaX * ((clrBottomRight >> 16) & 0xFF);
+ fBottomGreen = (1 - fDeltaX) * ((clrBottomLeft >> 8) & 0xFF) + fDeltaX * ((clrBottomRight >> 8) & 0xFF);
+ fBottomBlue = (1 - fDeltaX) * (clrBottomLeft & 0xFF) + fDeltaX * (clrBottomRight & 0xFF);
+
+ // linearly interpolate vertically between top and bottom interpolated results
+ iRed = (int)(Math.Round((1 - fDeltaY) * fTopRed + fDeltaY * fBottomRed));
+ iGreen = (int)(Math.Round((1 - fDeltaY) * fTopGreen + fDeltaY * fBottomGreen));
+ iBlue = (int)(Math.Round((1 - fDeltaY) * fTopBlue + fDeltaY * fBottomBlue));
+ iAlpha = (int)(Math.Round((1 - fDeltaY) * fTopAlpha + fDeltaY * fBottomAlpha));
+
+ // make sure color values are valid
+ if (iRed < 0) iRed = 0;
+ if (iRed > 255) iRed = 255;
+ if (iGreen < 0) iGreen = 0;
+ if (iGreen > 255) iGreen = 255;
+ if (iBlue < 0) iBlue = 0;
+ if (iBlue > 255) iBlue = 255;
+ if (iAlpha < 0) iAlpha = 0;
+ if (iAlpha > 255) iAlpha = 255;
+
+ var a = iAlpha + 1;
+ newp[i * newWidth + j] = (iAlpha << 24)
+ | ((byte)((iRed * a) >> 8) << 16)
+ | ((byte)((iGreen * a) >> 8) << 8)
+ | ((byte)((iBlue * a) >> 8));
+ }
+ }
+ return bmBilinearInterpolation;
+ }
+ }
+ }
+
+ #endregion
+
+ #region Flip
+
+ /// <summary>
+ /// Flips (reflects the image) either vertical or horizontal.
+ /// </summary>
+ /// <param name="bmp">The WriteableBitmap.</param>
+ /// <param name="flipMode">The flip mode.</param>
+ /// <returns>A new WriteableBitmap that is a flipped version of the input.</returns>
+ internal static WriteableBitmap Flip(this WriteableBitmap bmp, FlipMode flipMode)
+ {
+ using (var context = bmp.GetBitmapContext())
+ {
+ // Use refs for faster access (really important!) speeds up a lot!
+ var w = context.Width;
+ var h = context.Height;
+ var p = context.Pixels;
+ var i = 0;
+ WriteableBitmap result = null;
+
+ if (flipMode == FlipMode.Horizontal)
+ {
+ result = BitmapFactory.New(w, h);
+ using (var destContext = result.GetBitmapContext())
+ {
+ var rp = destContext.Pixels;
+ for (var y = h - 1; y >= 0; y--)
+ {
+ for (var x = 0; x < w; x++)
+ {
+ var srcInd = y * w + x;
+ rp[i] = p[srcInd];
+ i++;
+ }
+ }
+ }
+ }
+ else if (flipMode == FlipMode.Vertical)
+ {
+ result = BitmapFactory.New(w, h);
+ using (var destContext = result.GetBitmapContext())
+ {
+ var rp = destContext.Pixels;
+ for (var y = 0; y < h; y++)
+ {
+ for (var x = w - 1; x >= 0; x--)
+ {
+ var srcInd = y * w + x;
+ rp[i] = p[srcInd];
+ i++;
+ }
+ }
+ }
+ }
+
+ return result;
+ }
+ }
+
+ #endregion
+
+ #endregion
+ }
+} \ No newline at end of file