Initial Commit
This commit is contained in:
36
Common/Auxiliary/ArrayExtensions.cs
Normal file
36
Common/Auxiliary/ArrayExtensions.cs
Normal file
@@ -0,0 +1,36 @@
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Linq;
|
||||
using System.Text;
|
||||
using Microsoft.Research.DynamicDataDisplay.Charts;
|
||||
|
||||
namespace Microsoft.Research.DynamicDataDisplay.Common.Auxiliary
|
||||
{
|
||||
internal static class ArrayExtensions
|
||||
{
|
||||
internal static T Last<T>(this T[] array) {
|
||||
return array[array.Length - 1];
|
||||
}
|
||||
|
||||
internal static T[] CreateArray<T>(int length, T defaultValue)
|
||||
{
|
||||
T[] res = new T[length];
|
||||
for (int i = 0; i < res.Length; i++)
|
||||
{
|
||||
res[i] = defaultValue;
|
||||
}
|
||||
return res;
|
||||
}
|
||||
|
||||
internal static IEnumerable<Range<T>> GetPairs<T>(this IList<T> array)
|
||||
{
|
||||
if (array == null)
|
||||
throw new ArgumentNullException("array");
|
||||
|
||||
for (int i = 0; i < array.Count - 1; i++)
|
||||
{
|
||||
yield return new Range<T>(array[i], array[i + 1]);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
17
Common/Auxiliary/BindingHelper.cs
Normal file
17
Common/Auxiliary/BindingHelper.cs
Normal file
@@ -0,0 +1,17 @@
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Linq;
|
||||
using System.Text;
|
||||
using System.Windows.Data;
|
||||
using System.Windows;
|
||||
|
||||
namespace Microsoft.Research.DynamicDataDisplay.Common.Auxiliary
|
||||
{
|
||||
public static class BindingHelper
|
||||
{
|
||||
public static Binding CreateAttachedPropertyBinding(DependencyProperty attachedProperty)
|
||||
{
|
||||
return new Binding { Path = new PropertyPath("(0)", attachedProperty) };
|
||||
}
|
||||
}
|
||||
}
|
||||
46
Common/Auxiliary/BoundsHelper.cs
Normal file
46
Common/Auxiliary/BoundsHelper.cs
Normal file
@@ -0,0 +1,46 @@
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Windows;
|
||||
using Microsoft.Research.DynamicDataDisplay.Common;
|
||||
|
||||
namespace Microsoft.Research.DynamicDataDisplay
|
||||
{
|
||||
public static class BoundsHelper
|
||||
{
|
||||
/// <summary>Computes bounding rectangle for sequence of points</summary>
|
||||
/// <param name="points">Points sequence</param>
|
||||
/// <returns>Minimal axis-aligned bounding rectangle</returns>
|
||||
public static DataRect GetViewportBounds(IEnumerable<Point> viewportPoints)
|
||||
{
|
||||
DataRect bounds = DataRect.Empty;
|
||||
|
||||
double xMin = Double.PositiveInfinity;
|
||||
double xMax = Double.NegativeInfinity;
|
||||
|
||||
double yMin = Double.PositiveInfinity;
|
||||
double yMax = Double.NegativeInfinity;
|
||||
|
||||
foreach (Point p in viewportPoints)
|
||||
{
|
||||
xMin = Math.Min(xMin, p.X);
|
||||
xMax = Math.Max(xMax, p.X);
|
||||
|
||||
yMin = Math.Min(yMin, p.Y);
|
||||
yMax = Math.Max(yMax, p.Y);
|
||||
}
|
||||
|
||||
// were some points in collection
|
||||
if (!Double.IsInfinity(xMin))
|
||||
{
|
||||
bounds = DataRect.Create(xMin, yMin, xMax, yMax);
|
||||
}
|
||||
|
||||
return bounds;
|
||||
}
|
||||
|
||||
public static DataRect GetViewportBounds(IEnumerable<Point> dataPoints, DataTransform transform)
|
||||
{
|
||||
return GetViewportBounds(dataPoints.DataToViewport(transform));
|
||||
}
|
||||
}
|
||||
}
|
||||
69
Common/Auxiliary/BrushHelper.cs
Normal file
69
Common/Auxiliary/BrushHelper.cs
Normal file
@@ -0,0 +1,69 @@
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Linq;
|
||||
using System.Text;
|
||||
using System.Windows.Media;
|
||||
|
||||
namespace Microsoft.Research.DynamicDataDisplay
|
||||
{
|
||||
public static class BrushHelper
|
||||
{
|
||||
/// <summary>
|
||||
/// Creates a SolidColorBrush with random hue of its color.
|
||||
/// </summary>
|
||||
/// <returns>A SolicColorBrush with random hue of its color.</returns>
|
||||
public static SolidColorBrush CreateBrushWithRandomHue()
|
||||
{
|
||||
return new SolidColorBrush { Color = ColorHelper.CreateColorWithRandomHue() };
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Makes SolidColorBrush transparent.
|
||||
/// </summary>
|
||||
/// <param name="brush">The brush.</param>
|
||||
/// <param name="alpha">The alpha, [0..255]</param>
|
||||
/// <returns></returns>
|
||||
public static SolidColorBrush MakeTransparent(this SolidColorBrush brush, int alpha)
|
||||
{
|
||||
Color color = brush.Color;
|
||||
color.A = (byte)alpha;
|
||||
|
||||
return new SolidColorBrush(color);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Makes SolidColorBrush transparent.
|
||||
/// </summary>
|
||||
/// <param name="brush">The brush.</param>
|
||||
/// <param name="alpha">The alpha, [0.0 .. 1.0].</param>
|
||||
/// <returns></returns>
|
||||
public static SolidColorBrush MakeTransparent(this SolidColorBrush brush, double opacity)
|
||||
{
|
||||
return MakeTransparent(brush, (int)(opacity * 255));
|
||||
}
|
||||
|
||||
public static SolidColorBrush ChangeLightness(this SolidColorBrush brush, double lightnessFactor)
|
||||
{
|
||||
Color color = brush.Color;
|
||||
HsbColor hsbColor = HsbColor.FromArgbColor(color);
|
||||
hsbColor.Brightness *= lightnessFactor;
|
||||
|
||||
if (hsbColor.Brightness > 1.0) hsbColor.Brightness = 1.0;
|
||||
|
||||
SolidColorBrush result = new SolidColorBrush(hsbColor.ToArgbColor());
|
||||
return result;
|
||||
}
|
||||
|
||||
public static SolidColorBrush ChangeSaturation(this SolidColorBrush brush, double saturationFactor)
|
||||
{
|
||||
Color color = brush.Color;
|
||||
HsbColor hsbColor = HsbColor.FromArgbColor(color);
|
||||
hsbColor.Saturation *= saturationFactor;
|
||||
|
||||
if (hsbColor.Saturation > 1.0) hsbColor.Saturation = 1.0;
|
||||
|
||||
SolidColorBrush result = new SolidColorBrush(hsbColor.ToArgbColor());
|
||||
return result;
|
||||
}
|
||||
}
|
||||
}
|
||||
22
Common/Auxiliary/ColorExtensions.cs
Normal file
22
Common/Auxiliary/ColorExtensions.cs
Normal file
@@ -0,0 +1,22 @@
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Linq;
|
||||
using System.Text;
|
||||
using System.Windows.Media;
|
||||
|
||||
namespace Microsoft.Research.DynamicDataDisplay.Common.Auxiliary
|
||||
{
|
||||
public static class ColorExtensions
|
||||
{
|
||||
public static Color MakeTransparent(this Color color, int alpha)
|
||||
{
|
||||
color.A = (byte)alpha;
|
||||
return color;
|
||||
}
|
||||
|
||||
public static Color MakeTransparent(this Color color, double opacity)
|
||||
{
|
||||
return MakeTransparent(color, (int)(255 * opacity));
|
||||
}
|
||||
}
|
||||
}
|
||||
104
Common/Auxiliary/ColorHelper.cs
Normal file
104
Common/Auxiliary/ColorHelper.cs
Normal file
@@ -0,0 +1,104 @@
|
||||
using System;
|
||||
using System.Windows.Media;
|
||||
using System.Diagnostics.CodeAnalysis;
|
||||
|
||||
namespace Microsoft.Research.DynamicDataDisplay
|
||||
{
|
||||
public static class ColorHelper
|
||||
{
|
||||
private readonly static Random random = new Random();
|
||||
|
||||
/// <summary>
|
||||
/// Creates color from HSB color space with random hue and saturation and brighness equal to 1.
|
||||
/// </summary>
|
||||
/// <returns></returns>
|
||||
public static Color CreateColorWithRandomHue()
|
||||
{
|
||||
double hue = random.NextDouble() * 360;
|
||||
HsbColor hsbColor = new HsbColor(hue, 1, 1);
|
||||
return hsbColor.ToArgbColor();
|
||||
}
|
||||
|
||||
public static Color[] CreateRandomColors(int colorNum)
|
||||
{
|
||||
double startHue = random.NextDouble() * 360;
|
||||
|
||||
Color[] res = new Color[colorNum];
|
||||
double hueStep = 360.0 / colorNum;
|
||||
for (int i = 0; i < res.Length; i++)
|
||||
{
|
||||
double hue = startHue + i * hueStep;
|
||||
res[i] = new HsbColor(hue, 1, 1).ToArgbColor();
|
||||
}
|
||||
|
||||
return res;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Creates color with fully random hue and slightly random saturation and brightness.
|
||||
/// </summary>
|
||||
/// <returns></returns>
|
||||
public static Color CreateRandomHsbColor()
|
||||
{
|
||||
double h = random.NextDouble() * 360;
|
||||
double s = random.NextDouble() * 0.5 + 0.5;
|
||||
double b = random.NextDouble() * 0.25 + 0.75;
|
||||
return new HsbColor(h, s, b).ToArgbColor();
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Creates color with random hue.
|
||||
/// </summary>
|
||||
/// <param name="saturation">The saturation, [0..1].</param>
|
||||
/// <param name="brightness">The brightness, [0..1]</param>
|
||||
/// <returns></returns>
|
||||
public static Color CreateColorWithRandomHue(double saturation, double brightness)
|
||||
{
|
||||
double h = random.NextDouble() * 360;
|
||||
|
||||
return new HsbColor(h, saturation, brightness).ToArgbColor();
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Creates brush with random hue.
|
||||
/// </summary>
|
||||
/// <param name="saturation">The saturation, [0..1].</param>
|
||||
/// <param name="brightness">The brightness, [0..1].</param>
|
||||
/// <returns></returns>
|
||||
public static Brush CreateBrushWithRandomHue(double saturation, double brightness)
|
||||
{
|
||||
Color color = CreateColorWithRandomHue(saturation, brightness);
|
||||
|
||||
return new SolidColorBrush(color);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Gets the random color (this property is created to use it from Xaml).
|
||||
/// </summary>
|
||||
/// <value>The random color.</value>
|
||||
public static Color RandomColor
|
||||
{
|
||||
get { return CreateRandomHsbColor(); }
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Gets the random brush.
|
||||
/// </summary>
|
||||
/// <value>The random brush.</value>
|
||||
public static SolidColorBrush RandomBrush
|
||||
{
|
||||
get { return new SolidColorBrush(CreateRandomHsbColor()); }
|
||||
}
|
||||
|
||||
public static int ToArgb(this Color color)
|
||||
{
|
||||
int result =
|
||||
color.A << 24 |
|
||||
color.R << 16 |
|
||||
color.G << 8 |
|
||||
color.B;
|
||||
|
||||
return result;
|
||||
}
|
||||
}
|
||||
}
|
||||
76
Common/Auxiliary/CoordinateUtils.cs
Normal file
76
Common/Auxiliary/CoordinateUtils.cs
Normal file
@@ -0,0 +1,76 @@
|
||||
using System.Collections.Generic;
|
||||
using System.Windows;
|
||||
using System;
|
||||
using Microsoft.Research.DynamicDataDisplay.Common;
|
||||
|
||||
namespace Microsoft.Research.DynamicDataDisplay
|
||||
{
|
||||
public static class CoordinateUtilities
|
||||
{
|
||||
public static Rect RectZoom(Rect rect, double ratio)
|
||||
{
|
||||
return RectZoom(rect, rect.GetCenter(), ratio);
|
||||
}
|
||||
|
||||
public static Rect RectZoom(Rect rect, double horizontalRatio, double verticalRatio)
|
||||
{
|
||||
return RectZoom(rect, rect.GetCenter(), horizontalRatio, verticalRatio);
|
||||
}
|
||||
|
||||
public static Rect RectZoom(Rect rect, Point zoomCenter, double ratio)
|
||||
{
|
||||
return RectZoom(rect, zoomCenter, ratio, ratio);
|
||||
}
|
||||
|
||||
public static Rect RectZoom(Rect rect, Point zoomCenter, double horizontalRatio, double verticalRatio)
|
||||
{
|
||||
Rect res = new Rect();
|
||||
res.X = zoomCenter.X - (zoomCenter.X - rect.X) * horizontalRatio;
|
||||
res.Y = zoomCenter.Y - (zoomCenter.Y - rect.Y) * verticalRatio;
|
||||
res.Width = rect.Width * horizontalRatio;
|
||||
res.Height = rect.Height * verticalRatio;
|
||||
return res;
|
||||
}
|
||||
|
||||
public static DataRect RectZoom(DataRect rect, double ratio)
|
||||
{
|
||||
return RectZoom(rect, rect.GetCenter(), ratio);
|
||||
}
|
||||
|
||||
public static DataRect RectZoom(DataRect rect, double horizontalRatio, double verticalRatio)
|
||||
{
|
||||
return RectZoom(rect, rect.GetCenter(), horizontalRatio, verticalRatio);
|
||||
}
|
||||
|
||||
public static DataRect RectZoom(DataRect rect, Point zoomCenter, double ratio)
|
||||
{
|
||||
return RectZoom(rect, zoomCenter, ratio, ratio);
|
||||
}
|
||||
|
||||
public static DataRect RectZoom(DataRect rect, Point zoomCenter, double horizontalRatio, double verticalRatio)
|
||||
{
|
||||
DataRect res = new DataRect();
|
||||
res.XMin = zoomCenter.X - (zoomCenter.X - rect.XMin) * horizontalRatio;
|
||||
res.YMin = zoomCenter.Y - (zoomCenter.Y - rect.YMin) * verticalRatio;
|
||||
res.Width = rect.Width * horizontalRatio;
|
||||
res.Height = rect.Height * verticalRatio;
|
||||
return res;
|
||||
}
|
||||
|
||||
public static DataRect RectZoomX(DataRect rect, Point zoomCenter, double ratio)
|
||||
{
|
||||
DataRect res = rect;
|
||||
res.XMin = zoomCenter.X - (zoomCenter.X - rect.XMin) * ratio;
|
||||
res.Width = rect.Width * ratio;
|
||||
return res;
|
||||
}
|
||||
|
||||
public static DataRect RectZoomY(DataRect rect, Point zoomCenter, double ratio)
|
||||
{
|
||||
DataRect res = rect;
|
||||
res.YMin = zoomCenter.Y - (zoomCenter.Y - rect.YMin) * ratio;
|
||||
res.Height = rect.Height * ratio;
|
||||
return res;
|
||||
}
|
||||
}
|
||||
}
|
||||
82
Common/Auxiliary/DataRectExtensions.cs
Normal file
82
Common/Auxiliary/DataRectExtensions.cs
Normal file
@@ -0,0 +1,82 @@
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Linq;
|
||||
using System.Text;
|
||||
using System.Windows;
|
||||
using Microsoft.Research.DynamicDataDisplay.Common;
|
||||
|
||||
namespace Microsoft.Research.DynamicDataDisplay
|
||||
{
|
||||
public static class DataRectExtensions
|
||||
{
|
||||
internal static bool IsNaN(this DataRect rect)
|
||||
{
|
||||
return !rect.IsEmpty &&
|
||||
(
|
||||
rect.XMin.IsNaN() ||
|
||||
rect.YMin.IsNaN() ||
|
||||
rect.XMax.IsNaN() ||
|
||||
rect.YMax.IsNaN()
|
||||
);
|
||||
}
|
||||
|
||||
public static Point GetCenter(this DataRect rect)
|
||||
{
|
||||
return new Point(rect.XMin + rect.Width * 0.5, rect.YMin + rect.Height * 0.5);
|
||||
}
|
||||
|
||||
public static DataRect Zoom(this DataRect rect, Point to, double ratio)
|
||||
{
|
||||
return CoordinateUtilities.RectZoom(rect, to, ratio);
|
||||
}
|
||||
|
||||
public static DataRect ZoomOutFromCenter(this DataRect rect, double ratio)
|
||||
{
|
||||
return CoordinateUtilities.RectZoom(rect, rect.GetCenter(), ratio);
|
||||
}
|
||||
|
||||
public static DataRect ZoomInToCenter(this DataRect rect, double ratio)
|
||||
{
|
||||
return CoordinateUtilities.RectZoom(rect, rect.GetCenter(), 1 / ratio);
|
||||
}
|
||||
|
||||
public static DataRect ZoomX(this DataRect rect, Point to, double ratio)
|
||||
{
|
||||
return CoordinateUtilities.RectZoomX(rect, to, ratio);
|
||||
}
|
||||
|
||||
public static DataRect ZoomY(this DataRect rect, Point to, double ratio)
|
||||
{
|
||||
return CoordinateUtilities.RectZoomY(rect, to, ratio);
|
||||
}
|
||||
|
||||
public static double GetSquare(this DataRect rect)
|
||||
{
|
||||
if (rect.IsEmpty)
|
||||
return 0;
|
||||
|
||||
return rect.Width * rect.Height;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Determines whether one DataRect is close to another DataRect.
|
||||
/// </summary>
|
||||
/// <param name="rect1">The rect1.</param>
|
||||
/// <param name="rect2">The rect2.</param>
|
||||
/// <param name="difference">The difference.</param>
|
||||
/// <returns>
|
||||
/// <c>true</c> if [is close to] [the specified rect1]; otherwise, <c>false</c>.
|
||||
/// </returns>
|
||||
public static bool IsCloseTo(this DataRect rect1, DataRect rect2, double difference)
|
||||
{
|
||||
DataRect intersection = DataRect.Intersect(rect1, rect2);
|
||||
double square1 = rect1.GetSquare();
|
||||
double square2 = rect2.GetSquare();
|
||||
double intersectionSquare = intersection.GetSquare();
|
||||
|
||||
bool areClose = MathHelper.AreClose(square1, intersectionSquare, difference) &&
|
||||
MathHelper.AreClose(square2, intersectionSquare, difference);
|
||||
return areClose;
|
||||
}
|
||||
}
|
||||
}
|
||||
95
Common/Auxiliary/DataSearch/GenericSearcher1d.cs
Normal file
95
Common/Auxiliary/DataSearch/GenericSearcher1d.cs
Normal file
@@ -0,0 +1,95 @@
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Linq;
|
||||
using System.Text;
|
||||
|
||||
namespace Microsoft.Research.DynamicDataDisplay.Common.DataSearch
|
||||
{
|
||||
internal sealed class GenericSearcher1d<TCollection, TMember> where TMember : IComparable<TMember>
|
||||
{
|
||||
private readonly Func<TCollection, TMember> selector;
|
||||
private readonly IList<TCollection> collection;
|
||||
public GenericSearcher1d(IList<TCollection> collection, Func<TCollection, TMember> selector)
|
||||
{
|
||||
if (collection == null)
|
||||
throw new ArgumentNullException("collection");
|
||||
if (selector == null)
|
||||
throw new ArgumentNullException("selector");
|
||||
|
||||
this.collection = collection;
|
||||
this.selector = selector;
|
||||
}
|
||||
|
||||
public SearchResult1d SearchBetween(TMember x)
|
||||
{
|
||||
return SearchBetween(x, SearchResult1d.Empty);
|
||||
}
|
||||
|
||||
public SearchResult1d SearchBetween(TMember x, SearchResult1d result)
|
||||
{
|
||||
if (collection.Count == 0)
|
||||
return SearchResult1d.Empty;
|
||||
|
||||
int lastIndex = collection.Count - 1;
|
||||
|
||||
if (x.CompareTo(selector(collection[0])) < 0)
|
||||
return SearchResult1d.Empty;
|
||||
else if (selector(collection[lastIndex]).CompareTo(x) < 0)
|
||||
return SearchResult1d.Empty;
|
||||
|
||||
int startIndex = !result.IsEmpty ? Math.Min(result.Index, lastIndex) : 0;
|
||||
|
||||
// searching ascending
|
||||
if (selector(collection[startIndex]).CompareTo(x) < 0)
|
||||
{
|
||||
for (int i = startIndex + 1; i <= lastIndex; i++)
|
||||
if (selector(collection[i]).CompareTo(x) >= 0)
|
||||
return new SearchResult1d { Index = i - 1 };
|
||||
}
|
||||
else // searching descending
|
||||
{
|
||||
for (int i = startIndex - 1; i >= 0; i--)
|
||||
if (selector(collection[i]).CompareTo(x) <= 0)
|
||||
return new SearchResult1d { Index = i };
|
||||
}
|
||||
|
||||
throw new InvalidOperationException("Should not appear here.");
|
||||
}
|
||||
|
||||
public SearchResult1d SearchFirstLess(TMember x)
|
||||
{
|
||||
if (collection.Count == 0)
|
||||
return SearchResult1d.Empty;
|
||||
|
||||
SearchResult1d result = SearchResult1d.Empty;
|
||||
for (int i = 0; i < collection.Count; i++)
|
||||
{
|
||||
if (selector(collection[i]).CompareTo(x) >= 0)
|
||||
{
|
||||
result.Index = i;
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
return result;
|
||||
}
|
||||
|
||||
public SearchResult1d SearchGreater(TMember x)
|
||||
{
|
||||
if (collection.Count == 0)
|
||||
return SearchResult1d.Empty;
|
||||
|
||||
SearchResult1d result = SearchResult1d.Empty;
|
||||
for (int i = collection.Count - 1; i >= 0; i--)
|
||||
{
|
||||
if (selector(collection[i]).CompareTo(x) <= 0)
|
||||
{
|
||||
result.Index = i;
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
return result;
|
||||
}
|
||||
}
|
||||
}
|
||||
30
Common/Auxiliary/DataSearch/SearchResult1d.cs
Normal file
30
Common/Auxiliary/DataSearch/SearchResult1d.cs
Normal file
@@ -0,0 +1,30 @@
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Linq;
|
||||
using System.Text;
|
||||
|
||||
namespace Microsoft.Research.DynamicDataDisplay.Common.DataSearch
|
||||
{
|
||||
internal struct SearchResult1d
|
||||
{
|
||||
public static SearchResult1d Empty
|
||||
{
|
||||
get { return new SearchResult1d { Index = -1 }; }
|
||||
}
|
||||
|
||||
public int Index { get; internal set; }
|
||||
|
||||
public bool IsEmpty
|
||||
{
|
||||
get { return Index == -1; }
|
||||
}
|
||||
|
||||
public override string ToString()
|
||||
{
|
||||
if (IsEmpty)
|
||||
return "Empty";
|
||||
|
||||
return String.Format("Index = {0}", Index);
|
||||
}
|
||||
}
|
||||
}
|
||||
56
Common/Auxiliary/DataSearch/SortedXSearcher1d.cs
Normal file
56
Common/Auxiliary/DataSearch/SortedXSearcher1d.cs
Normal file
@@ -0,0 +1,56 @@
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Linq;
|
||||
using System.Text;
|
||||
using System.Windows;
|
||||
|
||||
namespace Microsoft.Research.DynamicDataDisplay.Common.DataSearch
|
||||
{
|
||||
internal class SortedXSearcher1d
|
||||
{
|
||||
private readonly IList<Point> collection;
|
||||
public SortedXSearcher1d(IList<Point> collection)
|
||||
{
|
||||
if (collection == null)
|
||||
throw new ArgumentNullException("collection");
|
||||
|
||||
this.collection = collection;
|
||||
}
|
||||
|
||||
public SearchResult1d SearchXBetween(double x)
|
||||
{
|
||||
return SearchXBetween(x, SearchResult1d.Empty);
|
||||
}
|
||||
|
||||
public SearchResult1d SearchXBetween(double x, SearchResult1d result)
|
||||
{
|
||||
if (collection.Count == 0)
|
||||
return SearchResult1d.Empty;
|
||||
|
||||
int lastIndex = collection.Count - 1;
|
||||
|
||||
if (x < collection[0].X)
|
||||
return SearchResult1d.Empty;
|
||||
else if (collection[lastIndex].X < x)
|
||||
return SearchResult1d.Empty;
|
||||
|
||||
int startIndex = !result.IsEmpty ? Math.Min(result.Index, lastIndex) : 0;
|
||||
|
||||
// searching ascending
|
||||
if (collection[startIndex].X < x)
|
||||
{
|
||||
for (int i = startIndex + 1; i <= lastIndex; i++)
|
||||
if (collection[i].X >= x)
|
||||
return new SearchResult1d { Index = i - 1 };
|
||||
}
|
||||
else // searching descending
|
||||
{
|
||||
for (int i = startIndex - 1; i >= 0; i--)
|
||||
if (collection[i].X <= x)
|
||||
return new SearchResult1d { Index = i };
|
||||
}
|
||||
|
||||
throw new InvalidOperationException("Should not appear here.");
|
||||
}
|
||||
}
|
||||
}
|
||||
59
Common/Auxiliary/DebugVerify.cs
Normal file
59
Common/Auxiliary/DebugVerify.cs
Normal file
@@ -0,0 +1,59 @@
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Linq;
|
||||
using System.Text;
|
||||
using System.Diagnostics;
|
||||
using System.Windows;
|
||||
|
||||
namespace Microsoft.Research.DynamicDataDisplay.Common.Auxiliary
|
||||
{
|
||||
internal static class DebugVerify
|
||||
{
|
||||
[Conditional("DEBUG")]
|
||||
[DebuggerStepThrough]
|
||||
public static void Is(bool condition)
|
||||
{
|
||||
if (!condition)
|
||||
{
|
||||
throw new ArgumentException(Strings.Exceptions.AssertionFailed);
|
||||
}
|
||||
}
|
||||
|
||||
[Conditional("DEBUG")]
|
||||
[DebuggerStepThrough]
|
||||
public static void IsNotNaN(double d)
|
||||
{
|
||||
DebugVerify.Is(!Double.IsNaN(d));
|
||||
}
|
||||
|
||||
[Conditional("DEBUG")]
|
||||
[DebuggerStepThrough]
|
||||
public static void IsNotNaN(Vector vec)
|
||||
{
|
||||
DebugVerify.IsNotNaN(vec.X);
|
||||
DebugVerify.IsNotNaN(vec.Y);
|
||||
}
|
||||
|
||||
[Conditional("DEBUG")]
|
||||
[DebuggerStepThrough]
|
||||
public static void IsNotNaN(Point point)
|
||||
{
|
||||
DebugVerify.IsNotNaN(point.X);
|
||||
DebugVerify.IsNotNaN(point.Y);
|
||||
}
|
||||
|
||||
[Conditional("DEBUG")]
|
||||
[DebuggerStepThrough]
|
||||
public static void IsFinite(double d)
|
||||
{
|
||||
DebugVerify.Is(!Double.IsInfinity(d) && !(Double.IsNaN(d)));
|
||||
}
|
||||
|
||||
[Conditional("DEBUG")]
|
||||
[DebuggerStepThrough]
|
||||
public static void IsNotNull(object obj)
|
||||
{
|
||||
DebugVerify.Is(obj != null);
|
||||
}
|
||||
}
|
||||
}
|
||||
20
Common/Auxiliary/DependencyObjectExtensions.cs
Normal file
20
Common/Auxiliary/DependencyObjectExtensions.cs
Normal file
@@ -0,0 +1,20 @@
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Linq;
|
||||
using System.Text;
|
||||
using System.Windows;
|
||||
using System.Windows.Threading;
|
||||
|
||||
namespace Microsoft.Research.DynamicDataDisplay.Common.Auxiliary
|
||||
{
|
||||
public static class DependencyObjectExtensions
|
||||
{
|
||||
public static T GetValueSync<T>(this DependencyObject d, DependencyProperty property)
|
||||
{
|
||||
object value = null;
|
||||
d.Dispatcher.Invoke(() => { value = d.GetValue(property); }, DispatcherPriority.Send);
|
||||
|
||||
return (T)value;
|
||||
}
|
||||
}
|
||||
}
|
||||
27
Common/Auxiliary/DictionaryExtensions.cs
Normal file
27
Common/Auxiliary/DictionaryExtensions.cs
Normal file
@@ -0,0 +1,27 @@
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Linq;
|
||||
using System.Text;
|
||||
using Microsoft.Research.DynamicDataDisplay.Charts.Isolines;
|
||||
|
||||
namespace Microsoft.Research.DynamicDataDisplay.Common.Auxiliary
|
||||
{
|
||||
internal static class DictionaryExtensions
|
||||
{
|
||||
internal static void Add<TKey, TValue>(this Dictionary<TKey, TValue> dict, TValue value, params TKey[] keys)
|
||||
{
|
||||
foreach (var key in keys)
|
||||
{
|
||||
dict.Add(key, value);
|
||||
}
|
||||
}
|
||||
|
||||
internal static void Add(this Dictionary<int, Edge> dict, Edge value, params CellBitmask[] keys)
|
||||
{
|
||||
foreach (var key in keys)
|
||||
{
|
||||
dict.Add((int)key, value);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
26
Common/Auxiliary/DispatcherExtensions.cs
Normal file
26
Common/Auxiliary/DispatcherExtensions.cs
Normal file
@@ -0,0 +1,26 @@
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Linq;
|
||||
using System.Text;
|
||||
using System.Windows.Threading;
|
||||
|
||||
namespace Microsoft.Research.DynamicDataDisplay.Common.Auxiliary
|
||||
{
|
||||
public static class DispatcherExtensions
|
||||
{
|
||||
public static DispatcherOperation BeginInvoke(this Dispatcher dispatcher, Action action)
|
||||
{
|
||||
return dispatcher.BeginInvoke((Delegate)action);
|
||||
}
|
||||
|
||||
public static DispatcherOperation BeginInvoke(this Dispatcher dispatcher, Action action, DispatcherPriority priority)
|
||||
{
|
||||
return dispatcher.BeginInvoke(action, priority);
|
||||
}
|
||||
|
||||
public static void Invoke(this Dispatcher dispatcher, Action action, DispatcherPriority priority)
|
||||
{
|
||||
dispatcher.Invoke(action, priority);
|
||||
}
|
||||
}
|
||||
}
|
||||
43
Common/Auxiliary/DisposableTimer.cs
Normal file
43
Common/Auxiliary/DisposableTimer.cs
Normal file
@@ -0,0 +1,43 @@
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Linq;
|
||||
using System.Text;
|
||||
using System.Diagnostics;
|
||||
|
||||
namespace Microsoft.Research.DynamicDataDisplay.Common.Auxiliary
|
||||
{
|
||||
public sealed class DisposableTimer : IDisposable
|
||||
{
|
||||
private bool isActive = true;
|
||||
private readonly string name;
|
||||
Stopwatch timer;
|
||||
public DisposableTimer(string name) : this(name, true) { }
|
||||
|
||||
public DisposableTimer(string name, bool isActive)
|
||||
{
|
||||
this.name = name;
|
||||
this.isActive = isActive;
|
||||
if (isActive)
|
||||
{
|
||||
timer = Stopwatch.StartNew();
|
||||
Trace.WriteLine(name + ": started " + DateTime.Now.TimeOfDay);
|
||||
}
|
||||
}
|
||||
|
||||
#region IDisposable Members
|
||||
|
||||
public void Dispose()
|
||||
{
|
||||
//#if DEBUG
|
||||
if (isActive)
|
||||
{
|
||||
var duration = timer.ElapsedMilliseconds;
|
||||
Trace.WriteLine(name + ": elapsed " + duration + " ms.");
|
||||
timer.Stop();
|
||||
}
|
||||
//#endif
|
||||
}
|
||||
|
||||
#endregion
|
||||
}
|
||||
}
|
||||
16
Common/Auxiliary/DoubleCollectionHelper.cs
Normal file
16
Common/Auxiliary/DoubleCollectionHelper.cs
Normal file
@@ -0,0 +1,16 @@
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Linq;
|
||||
using System.Text;
|
||||
using System.Windows.Media;
|
||||
|
||||
namespace Microsoft.Research.DynamicDataDisplay.Common.Auxiliary
|
||||
{
|
||||
public static class DoubleCollectionHelper
|
||||
{
|
||||
public static DoubleCollection Create(params double[] collection)
|
||||
{
|
||||
return new DoubleCollection(collection);
|
||||
}
|
||||
}
|
||||
}
|
||||
140
Common/Auxiliary/EventExtensions.cs
Normal file
140
Common/Auxiliary/EventExtensions.cs
Normal file
@@ -0,0 +1,140 @@
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Linq;
|
||||
using System.Text;
|
||||
using System.Diagnostics;
|
||||
using System.ComponentModel;
|
||||
using System.Collections.Specialized;
|
||||
using System.Windows;
|
||||
using Microsoft.Research.DynamicDataDisplay.Common;
|
||||
|
||||
namespace Microsoft.Research.DynamicDataDisplay
|
||||
{
|
||||
public static class EventExtensions
|
||||
{
|
||||
[DebuggerStepThrough]
|
||||
[DebuggerHidden]
|
||||
public static void Raise<T>(this EventHandler<T> @event, object sender, T args) where T : EventArgs
|
||||
{
|
||||
if (@event != null)
|
||||
{
|
||||
@event(sender, args);
|
||||
}
|
||||
}
|
||||
|
||||
[DebuggerStepThrough]
|
||||
[DebuggerHidden]
|
||||
public static void Raise(this EventHandler @event, object sender)
|
||||
{
|
||||
if (@event != null)
|
||||
{
|
||||
@event(sender, EventArgs.Empty);
|
||||
}
|
||||
}
|
||||
|
||||
[DebuggerStepThrough]
|
||||
[DebuggerHidden]
|
||||
public static void Raise(this EventHandler @event, object sender, EventArgs args)
|
||||
{
|
||||
if (@event != null)
|
||||
{
|
||||
@event(sender, args);
|
||||
}
|
||||
}
|
||||
|
||||
[DebuggerStepThrough]
|
||||
[DebuggerHidden]
|
||||
public static void Raise(this PropertyChangedEventHandler @event, object sender, string propertyName)
|
||||
{
|
||||
if (@event != null)
|
||||
{
|
||||
@event(sender, new PropertyChangedEventArgs(propertyName));
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Raises the specified event with Reset action.
|
||||
/// </summary>
|
||||
/// <param name="event">The event.</param>
|
||||
/// <param name="sender">The sender.</param>
|
||||
[DebuggerStepThrough]
|
||||
[DebuggerHidden]
|
||||
public static void Raise(this NotifyCollectionChangedEventHandler @event, object sender)
|
||||
{
|
||||
if (@event != null)
|
||||
{
|
||||
@event(sender, new NotifyCollectionChangedEventArgs(NotifyCollectionChangedAction.Reset));
|
||||
}
|
||||
}
|
||||
|
||||
[DebuggerStepThrough]
|
||||
[DebuggerHidden]
|
||||
public static void Raise(this NotifyCollectionChangedEventHandler @event, object sender, NotifyCollectionChangedAction action)
|
||||
{
|
||||
if (@event != null)
|
||||
{
|
||||
@event(sender, new NotifyCollectionChangedEventArgs(action));
|
||||
}
|
||||
}
|
||||
|
||||
[DebuggerStepThrough]
|
||||
[DebuggerHidden]
|
||||
public static void Raise(this NotifyCollectionChangedEventHandler @event, object sender, NotifyCollectionChangedEventArgs e)
|
||||
{
|
||||
if (e == null)
|
||||
throw new ArgumentNullException("e");
|
||||
|
||||
if (@event != null)
|
||||
{
|
||||
@event(sender, e);
|
||||
}
|
||||
}
|
||||
|
||||
[DebuggerStepThrough]
|
||||
[DebuggerHidden]
|
||||
public static void RaiseRoutedEvent(this UIElement sender, RoutedEvent routedEvent)
|
||||
{
|
||||
sender.RaiseEvent(new RoutedEventArgs(routedEvent));
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Raises the specified value changed event.
|
||||
/// </summary>
|
||||
/// <typeparam name="T"></typeparam>
|
||||
/// <typeparam name="TValue">The type of the value.</typeparam>
|
||||
/// <param name="event">The event.</param>
|
||||
/// <param name="sender">The sender of event.</param>
|
||||
/// <param name="prevValue">The previous value.</param>
|
||||
/// <param name="currValue">The current value.</param>
|
||||
[DebuggerStepThrough]
|
||||
[DebuggerHidden]
|
||||
public static void Raise<TValue>(this EventHandler<ValueChangedEventArgs<TValue>> @event, object sender, TValue prevValue, TValue currValue)
|
||||
{
|
||||
if (@event != null)
|
||||
{
|
||||
ValueChangedEventArgs<TValue> args = new ValueChangedEventArgs<TValue>(prevValue, currValue);
|
||||
@event(sender, args);
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Raises the specified value changed event.
|
||||
/// </summary>
|
||||
/// <typeparam name="T"></typeparam>
|
||||
/// <typeparam name="TValue">The type of the value.</typeparam>
|
||||
/// <param name="event">The event.</param>
|
||||
/// <param name="sender">The sender of event.</param>
|
||||
/// <param name="prevValue">The previous value.</param>
|
||||
/// <param name="currValue">The current value.</param>
|
||||
[DebuggerStepThrough]
|
||||
[DebuggerHidden]
|
||||
public static void Raise<TValue>(this EventHandler<ValueChangedEventArgs<TValue>> @event, object sender, object prevValue, object currValue)
|
||||
{
|
||||
if (@event != null)
|
||||
{
|
||||
ValueChangedEventArgs<TValue> args = new ValueChangedEventArgs<TValue>((TValue)prevValue, (TValue)currValue);
|
||||
@event(sender, args);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
301
Common/Auxiliary/HsbColor.cs
Normal file
301
Common/Auxiliary/HsbColor.cs
Normal file
@@ -0,0 +1,301 @@
|
||||
using System;
|
||||
using System.Windows.Media;
|
||||
using System.Diagnostics;
|
||||
using System.Diagnostics.CodeAnalysis;
|
||||
|
||||
namespace Microsoft.Research.DynamicDataDisplay
|
||||
{
|
||||
/// <summary>
|
||||
/// Represents color in Hue Saturation Brightness color space.
|
||||
/// </summary>
|
||||
[SuppressMessage("Microsoft.Naming", "CA1704:IdentifiersShouldBeSpelledCorrectly", MessageId = "Hsb")]
|
||||
[DebuggerDisplay("HSBColor A={Alpha} H={Hue} S={Saturation} B={Brightness}")]
|
||||
public struct HsbColor
|
||||
{
|
||||
private double hue;
|
||||
private double saturation;
|
||||
private double brightness;
|
||||
private double alpha;
|
||||
|
||||
/// <summary>Hue; [0, 360]</summary>
|
||||
public double Hue
|
||||
{
|
||||
get { return hue; }
|
||||
set
|
||||
{
|
||||
if (value < 0)
|
||||
value = 360 - value;
|
||||
|
||||
hue = value % 360;
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>Saturation; [0, 1]</summary>
|
||||
public double Saturation
|
||||
{
|
||||
get { return saturation; }
|
||||
set { saturation = value; }
|
||||
}
|
||||
|
||||
/// <summary>Brightness; [0, 1]</summary>
|
||||
public double Brightness
|
||||
{
|
||||
get { return brightness; }
|
||||
set { brightness = value; }
|
||||
}
|
||||
|
||||
/// <summary>Alpha; [0, 1]</summary>
|
||||
public double Alpha
|
||||
{
|
||||
get { return alpha; }
|
||||
set { alpha = value; }
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Initializes a new instance of the <see cref="HSBColor"/> struct.
|
||||
/// </summary>
|
||||
/// <param name="hue">The hue; [0; 360]</param>
|
||||
/// <param name="saturation">The saturation; [0, 1]</param>
|
||||
/// <param name="brightness">The brightness; [0, 1]</param>
|
||||
public HsbColor(double hue, double saturation, double brightness)
|
||||
{
|
||||
this.hue = hue;
|
||||
this.saturation = saturation;
|
||||
this.brightness = brightness;
|
||||
alpha = 1;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Initializes a new instance of the <see cref="HSBColor"/> struct.
|
||||
/// </summary>
|
||||
/// <param name="hue">The hue; [0, 360]</param>
|
||||
/// <param name="saturation">The saturation; [0, 1]</param>
|
||||
/// <param name="brightness">The brightness; [0, 1]</param>
|
||||
/// <param name="alpha">The alpha; [0, 1]</param>
|
||||
public HsbColor(double hue, double saturation, double brightness, double alpha)
|
||||
{
|
||||
this.hue = hue;
|
||||
this.saturation = saturation;
|
||||
this.brightness = brightness;
|
||||
this.alpha = alpha;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Creates HSBColor from the ARGB color.
|
||||
/// </summary>
|
||||
/// <param name="color">The color.</param>
|
||||
/// <returns></returns>
|
||||
public static HsbColor FromArgbColor(Color color)
|
||||
{
|
||||
double limit255 = 255;
|
||||
|
||||
double r = color.R / limit255;
|
||||
double g = color.G / limit255;
|
||||
double b = color.B / limit255;
|
||||
|
||||
double max = Math.Max(Math.Max(r, g), b);
|
||||
double min = Math.Min(Math.Min(r, g), b);
|
||||
|
||||
double len = max - min;
|
||||
|
||||
double brightness = max; // 0.5 * (max + min);
|
||||
double sat;
|
||||
double hue;
|
||||
|
||||
|
||||
if (max == 0 || len == 0)
|
||||
{
|
||||
sat = hue = 0;
|
||||
}
|
||||
else
|
||||
{
|
||||
sat = len / max;
|
||||
if (r == max)
|
||||
{
|
||||
hue = (g - b) / len;
|
||||
}
|
||||
else if (g == max)
|
||||
{
|
||||
hue = 2 + (b - r) / len;
|
||||
}
|
||||
else
|
||||
{
|
||||
hue = 4 + (r - g) / len;
|
||||
}
|
||||
}
|
||||
|
||||
hue *= 60;
|
||||
if (hue < 0)
|
||||
hue += 360;
|
||||
|
||||
|
||||
HsbColor res = new HsbColor();
|
||||
res.hue = hue;
|
||||
res.saturation = sat;
|
||||
res.brightness = brightness;
|
||||
res.alpha = color.A / limit255;
|
||||
return res;
|
||||
}
|
||||
|
||||
public static HsbColor FromArgb(int argb)
|
||||
{
|
||||
byte a = (byte)(argb >> 24);
|
||||
byte r = (byte)((argb >> 16) & 0xFF);
|
||||
byte g = (byte)((argb >> 8) & 0xFF);
|
||||
byte b = (byte)(argb & 0xFF);
|
||||
return FromArgbColor(Color.FromArgb(a, r, g, b));
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Converts HSBColor to ARGB color space.
|
||||
/// </summary>
|
||||
/// <returns></returns>
|
||||
public Color ToArgbColor()
|
||||
{
|
||||
double r = 0.0;
|
||||
double g = 0.0;
|
||||
double b = 0.0;
|
||||
double hue = this.hue % 360.0;
|
||||
if (saturation == 0.0)
|
||||
{
|
||||
r = g = b = brightness;
|
||||
}
|
||||
else
|
||||
{
|
||||
double smallHue = hue / 60.0;
|
||||
int smallHueInt = (int)Math.Floor(smallHue);
|
||||
double smallHueFrac = smallHue - smallHueInt;
|
||||
double val1 = brightness * (1.0 - saturation);
|
||||
double val2 = brightness * (1.0 - (saturation * smallHueFrac));
|
||||
double val3 = brightness * (1.0 - (saturation * (1.0 - smallHueFrac)));
|
||||
switch (smallHueInt)
|
||||
{
|
||||
case 0:
|
||||
r = brightness;
|
||||
g = val3;
|
||||
b = val1;
|
||||
break;
|
||||
|
||||
case 1:
|
||||
r = val2;
|
||||
g = brightness;
|
||||
b = val1;
|
||||
break;
|
||||
|
||||
case 2:
|
||||
r = val1;
|
||||
g = brightness;
|
||||
b = val3;
|
||||
break;
|
||||
|
||||
case 3:
|
||||
r = val1;
|
||||
g = val2;
|
||||
b = brightness;
|
||||
break;
|
||||
|
||||
case 4:
|
||||
r = val3;
|
||||
g = val1;
|
||||
b = brightness;
|
||||
break;
|
||||
|
||||
case 5:
|
||||
r = brightness;
|
||||
g = val1;
|
||||
b = val2;
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
return Color.FromArgb(
|
||||
(byte)(Math.Round(alpha * 255)),
|
||||
(byte)(Math.Round(r * 255)),
|
||||
(byte)(Math.Round(g * 255)),
|
||||
(byte)(Math.Round(b * 255)));
|
||||
}
|
||||
|
||||
public int ToArgb()
|
||||
{
|
||||
return ToArgbColor().ToArgb();
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Determines whether the specified <see cref="System.Object"/> is equal to this instance.
|
||||
/// </summary>
|
||||
/// <param name="obj">The <see cref="System.Object"/> to compare with this instance.</param>
|
||||
/// <returns>
|
||||
/// <c>true</c> if the specified <see cref="System.Object"/> is equal to this instance; otherwise, <c>false</c>.
|
||||
/// </returns>
|
||||
public override bool Equals(object obj)
|
||||
{
|
||||
if (obj is HsbColor)
|
||||
{
|
||||
HsbColor c = (HsbColor)obj;
|
||||
return (c.alpha == alpha &&
|
||||
c.brightness == brightness &&
|
||||
c.hue == hue &&
|
||||
c.saturation == saturation);
|
||||
}
|
||||
else
|
||||
return false;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Returns a hash code for this instance.
|
||||
/// </summary>
|
||||
/// <returns>
|
||||
/// A hash code for this instance, suitable for use in hashing algorithms and data structures like a hash table.
|
||||
/// </returns>
|
||||
public override int GetHashCode()
|
||||
{
|
||||
return alpha.GetHashCode() ^
|
||||
brightness.GetHashCode() ^
|
||||
hue.GetHashCode() ^
|
||||
saturation.GetHashCode();
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Implements the operator ==.
|
||||
/// </summary>
|
||||
/// <param name="first">The first.</param>
|
||||
/// <param name="second">The second.</param>
|
||||
/// <returns>The result of the operator.</returns>
|
||||
public static bool operator ==(HsbColor first, HsbColor second)
|
||||
{
|
||||
return (first.alpha == second.alpha &&
|
||||
first.brightness == second.brightness &&
|
||||
first.hue == second.hue &&
|
||||
first.saturation == second.saturation);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Implements the operator !=.
|
||||
/// </summary>
|
||||
/// <param name="first">The first.</param>
|
||||
/// <param name="second">The second.</param>
|
||||
/// <returns>The result of the operator.</returns>
|
||||
public static bool operator !=(HsbColor first, HsbColor second)
|
||||
{
|
||||
return (first.alpha != second.alpha ||
|
||||
first.brightness != second.brightness ||
|
||||
first.hue != second.hue ||
|
||||
first.saturation != second.saturation);
|
||||
}
|
||||
}
|
||||
|
||||
public static class ColorExtensions
|
||||
{
|
||||
/// <summary>
|
||||
/// Converts the ARGB color to the HSB color.
|
||||
/// </summary>
|
||||
/// <param name="color">The color.</param>
|
||||
/// <returns></returns>
|
||||
[SuppressMessage("Microsoft.Naming", "CA1704:IdentifiersShouldBeSpelledCorrectly", MessageId = "Hsb")]
|
||||
public static HsbColor ToHsbColor(this Color color)
|
||||
{
|
||||
return HsbColor.FromArgbColor(color);
|
||||
}
|
||||
}
|
||||
}
|
||||
146
Common/Auxiliary/IDataSource2DExtensions.cs
Normal file
146
Common/Auxiliary/IDataSource2DExtensions.cs
Normal file
@@ -0,0 +1,146 @@
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Linq;
|
||||
using System.Text;
|
||||
using Microsoft.Research.DynamicDataDisplay.Charts;
|
||||
using Microsoft.Research.DynamicDataDisplay.DataSources;
|
||||
using System.Windows;
|
||||
using System.Diagnostics.CodeAnalysis;
|
||||
|
||||
namespace Microsoft.Research.DynamicDataDisplay.Common.Auxiliary
|
||||
{
|
||||
public static class IDataSource2DExtensions
|
||||
{
|
||||
public static Range<double> GetMinMax(this double[,] data)
|
||||
{
|
||||
data.VerifyNotNull("data");
|
||||
|
||||
int width = data.GetLength(0);
|
||||
int height = data.GetLength(1);
|
||||
Verify.IsTrueWithMessage(width > 0, Strings.Exceptions.ArrayWidthShouldBePositive);
|
||||
Verify.IsTrueWithMessage(height > 0, Strings.Exceptions.ArrayHeightShouldBePositive);
|
||||
|
||||
double min = data[0, 0];
|
||||
double max = data[0, 0];
|
||||
for (int x = 0; x < width; x++)
|
||||
{
|
||||
for (int y = 0; y < height; y++)
|
||||
{
|
||||
if (data[x, y] < min)
|
||||
min = data[x, y];
|
||||
if (data[x, y] > max)
|
||||
max = data[x, y];
|
||||
}
|
||||
}
|
||||
|
||||
Range<double> res = new Range<double>(min, max);
|
||||
return res;
|
||||
}
|
||||
|
||||
public static Range<double> GetMinMax(this double[,] data, double missingValue)
|
||||
{
|
||||
data.VerifyNotNull("data");
|
||||
|
||||
int width = data.GetLength(0);
|
||||
int height = data.GetLength(1);
|
||||
Verify.IsTrueWithMessage(width > 0, Strings.Exceptions.ArrayWidthShouldBePositive);
|
||||
Verify.IsTrueWithMessage(height > 0, Strings.Exceptions.ArrayHeightShouldBePositive);
|
||||
|
||||
double min = Double.MaxValue;
|
||||
double max = Double.MinValue;
|
||||
for (int x = 0; x < width; x++)
|
||||
{
|
||||
for (int y = 0; y < height; y++)
|
||||
{
|
||||
if (data[x, y] != missingValue && data[x, y] < min)
|
||||
min = data[x, y];
|
||||
if (data[x, y] != missingValue && data[x, y] > max)
|
||||
max = data[x, y];
|
||||
}
|
||||
}
|
||||
|
||||
Range<double> res = new Range<double>(min, max);
|
||||
return res;
|
||||
}
|
||||
|
||||
public static Range<double> GetMinMax(this IDataSource2D<double> dataSource)
|
||||
{
|
||||
dataSource.VerifyNotNull("dataSource");
|
||||
|
||||
return GetMinMax(dataSource.Data);
|
||||
}
|
||||
|
||||
public static Range<double> GetMinMax(this IDataSource2D<double> dataSource, double missingValue)
|
||||
{
|
||||
dataSource.VerifyNotNull("dataSource");
|
||||
|
||||
return GetMinMax(dataSource.Data, missingValue);
|
||||
}
|
||||
|
||||
public static Range<double> GetMinMax(this IDataSource2D<double> dataSource, DataRect area)
|
||||
{
|
||||
if (dataSource == null)
|
||||
throw new ArgumentNullException("dataSource");
|
||||
|
||||
double min = Double.PositiveInfinity;
|
||||
double max = Double.NegativeInfinity;
|
||||
int width = dataSource.Width;
|
||||
int height = dataSource.Height;
|
||||
var grid = dataSource.Grid;
|
||||
var data = dataSource.Data;
|
||||
for (int ix = 0; ix < width; ix++)
|
||||
{
|
||||
for (int iy = 0; iy < height; iy++)
|
||||
{
|
||||
if (area.Contains(grid[ix, iy]))
|
||||
{
|
||||
var value = data[ix, iy];
|
||||
if (value < min)
|
||||
min = value;
|
||||
if (value > max)
|
||||
max = value;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if (min < max)
|
||||
return new Range<double>(min, max);
|
||||
else
|
||||
return new Range<double>();
|
||||
}
|
||||
|
||||
|
||||
public static Rect GetGridBounds(this Point[,] grid)
|
||||
{
|
||||
double minX = grid[0, 0].X;
|
||||
double maxX = minX;
|
||||
double minY = grid[0, 0].Y;
|
||||
double maxY = minY;
|
||||
|
||||
int width = grid.GetLength(0);
|
||||
int height = grid.GetLength(1);
|
||||
for (int ix = 0; ix < width; ix++)
|
||||
{
|
||||
for (int iy = 0; iy < height; iy++)
|
||||
{
|
||||
Point pt = grid[ix, iy];
|
||||
|
||||
double x = pt.X;
|
||||
double y = pt.Y;
|
||||
if (x < minX) minX = x;
|
||||
if (x > maxX) maxX = x;
|
||||
|
||||
if (y < minY) minY = y;
|
||||
if (y > maxY) maxY = y;
|
||||
}
|
||||
}
|
||||
return new Rect(new Point(minX, minY), new Point(maxX, maxY));
|
||||
}
|
||||
|
||||
[SuppressMessage("Microsoft.Design", "CA1011:ConsiderPassingBaseTypesAsParameters")]
|
||||
public static Rect GetGridBounds<T>(this IDataSource2D<T> dataSource) where T : struct
|
||||
{
|
||||
return dataSource.Grid.GetGridBounds();
|
||||
}
|
||||
}
|
||||
}
|
||||
119
Common/Auxiliary/IEnumerableExtensions.cs
Normal file
119
Common/Auxiliary/IEnumerableExtensions.cs
Normal file
@@ -0,0 +1,119 @@
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Linq;
|
||||
using System.Text;
|
||||
using System.Collections;
|
||||
|
||||
namespace Microsoft.Research.DynamicDataDisplay.Common.Auxiliary
|
||||
{
|
||||
internal static class IEnumerableExtensions
|
||||
{
|
||||
public static bool CountGreaterOrEqual<T>(this IEnumerable<T> enumerable, int count)
|
||||
{
|
||||
int counter = 0;
|
||||
using (var enumerator = enumerable.GetEnumerator())
|
||||
{
|
||||
while (counter < count && enumerator.MoveNext())
|
||||
{
|
||||
counter++;
|
||||
}
|
||||
}
|
||||
|
||||
return counter == count;
|
||||
}
|
||||
|
||||
public static IEnumerable<IEnumerable<T>> Split<T>(this IEnumerable<T> source, int maxCount)
|
||||
{
|
||||
using (var enumerator = new FixedEnumeratorWrapper<T>(source.GetEnumerator()))
|
||||
{
|
||||
do
|
||||
{
|
||||
var enumerable = new FixedEnumerable<T>(enumerator);
|
||||
yield return enumerable.Take(maxCount);
|
||||
}
|
||||
while (enumerator.CanMoveNext);
|
||||
}
|
||||
}
|
||||
|
||||
private sealed class FixedEnumeratorWrapper<T> : IEnumerator<T>
|
||||
{
|
||||
private readonly IEnumerator<T> enumerator;
|
||||
|
||||
public FixedEnumeratorWrapper(IEnumerator<T> enumerator)
|
||||
{
|
||||
this.enumerator = enumerator;
|
||||
}
|
||||
|
||||
#region IEnumerator<T> Members
|
||||
|
||||
public T Current
|
||||
{
|
||||
get { return enumerator.Current; }
|
||||
}
|
||||
|
||||
#endregion
|
||||
|
||||
#region IDisposable Members
|
||||
|
||||
public void Dispose()
|
||||
{
|
||||
//enumerator.Dispose();
|
||||
}
|
||||
|
||||
#endregion
|
||||
|
||||
#region IEnumerator Members
|
||||
|
||||
object IEnumerator.Current
|
||||
{
|
||||
get { throw new NotImplementedException(); }
|
||||
}
|
||||
|
||||
private bool canMoveNext = false;
|
||||
public bool CanMoveNext
|
||||
{
|
||||
get { return canMoveNext; }
|
||||
}
|
||||
|
||||
public bool MoveNext()
|
||||
{
|
||||
canMoveNext = enumerator.MoveNext();
|
||||
return canMoveNext;
|
||||
}
|
||||
|
||||
public void Reset()
|
||||
{
|
||||
enumerator.Reset();
|
||||
}
|
||||
|
||||
#endregion
|
||||
}
|
||||
|
||||
private sealed class FixedEnumerable<T> : IEnumerable<T>
|
||||
{
|
||||
private readonly IEnumerator<T> enumerator;
|
||||
public FixedEnumerable(IEnumerator<T> enumerator)
|
||||
{
|
||||
this.enumerator = enumerator;
|
||||
}
|
||||
|
||||
#region IEnumerable<T> Members
|
||||
|
||||
public IEnumerator<T> GetEnumerator()
|
||||
{
|
||||
return enumerator;
|
||||
}
|
||||
|
||||
#endregion
|
||||
|
||||
#region IEnumerable Members
|
||||
|
||||
IEnumerator IEnumerable.GetEnumerator()
|
||||
{
|
||||
throw new NotSupportedException();
|
||||
}
|
||||
|
||||
#endregion
|
||||
}
|
||||
}
|
||||
}
|
||||
44
Common/Auxiliary/IListExtensions.cs
Normal file
44
Common/Auxiliary/IListExtensions.cs
Normal file
@@ -0,0 +1,44 @@
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Linq;
|
||||
using System.Text;
|
||||
|
||||
namespace Microsoft.Research.DynamicDataDisplay
|
||||
{
|
||||
public static class IListExtensions
|
||||
{
|
||||
public static void AddMany<T>(this IList<T> collection, IEnumerable<T> addingItems)
|
||||
{
|
||||
foreach (var item in addingItems)
|
||||
{
|
||||
collection.Add(item);
|
||||
}
|
||||
}
|
||||
|
||||
public static void AddMany<T>(this IList<T> collection, params T[] children)
|
||||
{
|
||||
foreach (var child in children)
|
||||
{
|
||||
collection.Add(child);
|
||||
}
|
||||
}
|
||||
|
||||
public static void RemoveAll<T>(this IList<T> collection, Type type)
|
||||
{
|
||||
var children = collection.Where(el => type.IsAssignableFrom(el.GetType())).ToArray();
|
||||
foreach (var child in children)
|
||||
{
|
||||
collection.Remove((T)child);
|
||||
}
|
||||
}
|
||||
|
||||
public static void RemoveAll<T, TDelete>(this IList<T> collection)
|
||||
{
|
||||
var children = collection.OfType<TDelete>().ToArray();
|
||||
foreach (var child in children)
|
||||
{
|
||||
collection.Remove((T)(object)child);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
32
Common/Auxiliary/IPlotterElementExtensions.cs
Normal file
32
Common/Auxiliary/IPlotterElementExtensions.cs
Normal file
@@ -0,0 +1,32 @@
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Linq;
|
||||
using System.Text;
|
||||
|
||||
namespace Microsoft.Research.DynamicDataDisplay
|
||||
{
|
||||
public static class IPlotterElementExtensions
|
||||
{
|
||||
public static void RemoveFromPlotter(this IPlotterElement element)
|
||||
{
|
||||
if (element == null)
|
||||
throw new ArgumentNullException("element");
|
||||
|
||||
if (element.Plotter != null)
|
||||
{
|
||||
element.Plotter.Children.Remove(element);
|
||||
}
|
||||
}
|
||||
|
||||
public static void AddToPlotter(this IPlotterElement element, Plotter plotter)
|
||||
{
|
||||
if (element == null)
|
||||
throw new ArgumentNullException("element");
|
||||
if (plotter == null)
|
||||
throw new ArgumentNullException("plotter");
|
||||
|
||||
|
||||
plotter.Children.Add(element);
|
||||
}
|
||||
}
|
||||
}
|
||||
21
Common/Auxiliary/IPointCollectionExtensions.cs
Normal file
21
Common/Auxiliary/IPointCollectionExtensions.cs
Normal file
@@ -0,0 +1,21 @@
|
||||
using System.Collections.Generic;
|
||||
using System.Windows;
|
||||
|
||||
namespace Microsoft.Research.DynamicDataDisplay
|
||||
{
|
||||
public static class IPointCollectionExtensions
|
||||
{
|
||||
public static DataRect GetBounds(this IEnumerable<Point> points)
|
||||
{
|
||||
return BoundsHelper.GetViewportBounds(points);
|
||||
}
|
||||
|
||||
public static IEnumerable<Point> Skip(this IList<Point> points, int skipCount)
|
||||
{
|
||||
for (int i = skipCount; i < points.Count; i++)
|
||||
{
|
||||
yield return points[i];
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
34
Common/Auxiliary/ListExtensions.cs
Normal file
34
Common/Auxiliary/ListExtensions.cs
Normal file
@@ -0,0 +1,34 @@
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
|
||||
namespace Microsoft.Research.DynamicDataDisplay
|
||||
{
|
||||
internal static class ListExtensions
|
||||
{
|
||||
/// <summary>
|
||||
/// Gets last element of list.
|
||||
/// </summary>
|
||||
/// <typeparam name="T"></typeparam>
|
||||
/// <param name="list"></param>
|
||||
/// <returns></returns>
|
||||
internal static T GetLast<T>(this List<T> list)
|
||||
{
|
||||
if (list == null) throw new ArgumentNullException("list");
|
||||
if (list.Count == 0) throw new InvalidOperationException(Strings.Exceptions.CannotGetLastElement);
|
||||
|
||||
return list[list.Count - 1];
|
||||
}
|
||||
|
||||
internal static void ForEach<T>(this IEnumerable<T> source, Action<T> action) {
|
||||
if (action == null)
|
||||
throw new ArgumentNullException("action");
|
||||
if (source == null)
|
||||
throw new ArgumentNullException("source");
|
||||
|
||||
foreach (var item in source)
|
||||
{
|
||||
action(item);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
26
Common/Auxiliary/ListGenerator.cs
Normal file
26
Common/Auxiliary/ListGenerator.cs
Normal file
@@ -0,0 +1,26 @@
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Windows;
|
||||
|
||||
namespace Microsoft.Research.DynamicDataDisplay
|
||||
{
|
||||
public static class ListGenerator {
|
||||
public static IEnumerable<Point> GeneratePoints(int length, Func<int, Point> generator) {
|
||||
for (int i = 0; i < length; i++) {
|
||||
yield return generator(i);
|
||||
}
|
||||
}
|
||||
|
||||
public static IEnumerable<Point> GeneratePoints(int length, Func<int, double> x, Func<int, double> y) {
|
||||
for (int i = 0; i < length; i++) {
|
||||
yield return new Point(x(i), y(i));
|
||||
}
|
||||
}
|
||||
|
||||
public static IEnumerable<T> Generate<T>(int length, Func<int, T> generator) {
|
||||
for (int i = 0; i < length; i++) {
|
||||
yield return generator(i);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
53
Common/Auxiliary/MarkupExtensions/ResourceExtension.cs
Normal file
53
Common/Auxiliary/MarkupExtensions/ResourceExtension.cs
Normal file
@@ -0,0 +1,53 @@
|
||||
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Linq;
|
||||
using System.Text;
|
||||
using System.Windows.Markup;
|
||||
using System.Resources;
|
||||
|
||||
namespace Microsoft.Research.DynamicDataDisplay.MarkupExtensions
|
||||
{
|
||||
/// <summary>
|
||||
/// Represents a markup extension, which allows to get an access to application resource files.
|
||||
/// </summary>
|
||||
[MarkupExtensionReturnType(typeof(string))]
|
||||
public class ResourceExtension : MarkupExtension
|
||||
{
|
||||
/// <summary>
|
||||
/// Initializes a new instance of the <see cref="ResourceExtension"/> class.
|
||||
/// </summary>
|
||||
public ResourceExtension() { }
|
||||
|
||||
private string resourceKey;
|
||||
//[ConstructorArgument("resourceKey")]
|
||||
public string ResourceKey
|
||||
{
|
||||
get { return resourceKey; }
|
||||
set
|
||||
{
|
||||
if (resourceKey == null)
|
||||
throw new ArgumentNullException("resourceKey");
|
||||
|
||||
resourceKey = value;
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Initializes a new instance of the <see cref="ResourceExtension"/> class.
|
||||
/// </summary>
|
||||
/// <param name="resourceKey">The resource key.</param>
|
||||
public ResourceExtension(string resourceKey)
|
||||
{
|
||||
if (resourceKey == null)
|
||||
throw new ArgumentNullException("resourceKey");
|
||||
|
||||
this.resourceKey = resourceKey;
|
||||
}
|
||||
|
||||
public override object ProvideValue(IServiceProvider serviceProvider)
|
||||
{
|
||||
return Strings.UIResources.ResourceManager.GetString(resourceKey);
|
||||
}
|
||||
}
|
||||
}
|
||||
23
Common/Auxiliary/MarkupExtensions/SelfBinding.cs
Normal file
23
Common/Auxiliary/MarkupExtensions/SelfBinding.cs
Normal file
@@ -0,0 +1,23 @@
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Linq;
|
||||
using System.Text;
|
||||
using System.Windows.Data;
|
||||
using System.Windows;
|
||||
|
||||
namespace Microsoft.Research.DynamicDataDisplay.MarkupExtensions
|
||||
{
|
||||
public class SelfBinding : Binding
|
||||
{
|
||||
public SelfBinding()
|
||||
{
|
||||
RelativeSource = new RelativeSource { Mode = RelativeSourceMode.Self };
|
||||
}
|
||||
|
||||
public SelfBinding(string propertyPath)
|
||||
: this()
|
||||
{
|
||||
Path = new PropertyPath(propertyPath);
|
||||
}
|
||||
}
|
||||
}
|
||||
22
Common/Auxiliary/MarkupExtensions/TemplateBinding.cs
Normal file
22
Common/Auxiliary/MarkupExtensions/TemplateBinding.cs
Normal file
@@ -0,0 +1,22 @@
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Linq;
|
||||
using System.Text;
|
||||
using System.Windows.Data;
|
||||
|
||||
namespace Microsoft.Research.DynamicDataDisplay.MarkupExtensions
|
||||
{
|
||||
public class TemplateBinding : Binding
|
||||
{
|
||||
public TemplateBinding()
|
||||
{
|
||||
RelativeSource = new RelativeSource { Mode = RelativeSourceMode.TemplatedParent };
|
||||
}
|
||||
|
||||
public TemplateBinding(string propertyPath)
|
||||
: this()
|
||||
{
|
||||
Path = new System.Windows.PropertyPath(propertyPath);
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,33 @@
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Linq;
|
||||
using System.Text;
|
||||
using System.Windows.Markup;
|
||||
using System.Windows;
|
||||
using System.ComponentModel;
|
||||
|
||||
namespace Microsoft.Research.DynamicDataDisplay.MarkupExtensions
|
||||
{
|
||||
[EditorBrowsable(EditorBrowsableState.Never)]
|
||||
public class XbapConditionalExpression : MarkupExtension
|
||||
{
|
||||
public XbapConditionalExpression() { }
|
||||
|
||||
public XbapConditionalExpression(object value)
|
||||
{
|
||||
this.Value = value;
|
||||
}
|
||||
|
||||
[ConstructorArgument("value")]
|
||||
public object Value { get; set; }
|
||||
|
||||
public override object ProvideValue(IServiceProvider serviceProvider)
|
||||
{
|
||||
#if RELEASEXBAP
|
||||
return null;
|
||||
#else
|
||||
return ((ResourceDictionary)Application.LoadComponent(new Uri("/DynamicDataDisplay;component/Themes/Generic.xaml", UriKind.Relative)))[Value];
|
||||
#endif
|
||||
}
|
||||
}
|
||||
}
|
||||
91
Common/Auxiliary/MathHelper.cs
Normal file
91
Common/Auxiliary/MathHelper.cs
Normal file
@@ -0,0 +1,91 @@
|
||||
using System;
|
||||
using System.Windows;
|
||||
|
||||
namespace Microsoft.Research.DynamicDataDisplay
|
||||
{
|
||||
public static class MathHelper
|
||||
{
|
||||
public static long Clamp(long value, long min, long max)
|
||||
{
|
||||
return Math.Max(min, Math.Min(value, max));
|
||||
}
|
||||
|
||||
public static double Clamp(double value, double min, double max)
|
||||
{
|
||||
return Math.Max(min, Math.Min(value, max));
|
||||
}
|
||||
|
||||
/// <summary>Clamps specified value to [0,1]</summary>
|
||||
/// <param name="d">Value to clamp</param>
|
||||
/// <returns>Value in range [0,1]</returns>
|
||||
public static double Clamp(double value)
|
||||
{
|
||||
return Math.Max(0, Math.Min(value, 1));
|
||||
}
|
||||
|
||||
public static int Clamp(int value, int min, int max)
|
||||
{
|
||||
return Math.Max(min, Math.Min(value, max));
|
||||
}
|
||||
|
||||
public static Rect CreateRectByPoints(double xMin, double yMin, double xMax, double yMax)
|
||||
{
|
||||
return new Rect(new Point(xMin, yMin), new Point(xMax, yMax));
|
||||
}
|
||||
|
||||
public static double Interpolate(double start, double end, double ratio)
|
||||
{
|
||||
return start * (1 - ratio) + end * ratio;
|
||||
}
|
||||
|
||||
public static double RadiansToDegrees(this double radians)
|
||||
{
|
||||
return radians * 180 / Math.PI;
|
||||
}
|
||||
|
||||
public static double DegreesToRadians(this double degrees)
|
||||
{
|
||||
return degrees / 180 * Math.PI;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Converts vector into angle.
|
||||
/// </summary>
|
||||
/// <param name="vector">The vector.</param>
|
||||
/// <returns>Angle in degrees.</returns>
|
||||
public static double ToAngle(this Vector vector)
|
||||
{
|
||||
return Math.Atan2(-vector.Y, vector.X).RadiansToDegrees();
|
||||
}
|
||||
|
||||
public static Point ToPoint(this Vector v)
|
||||
{
|
||||
return new Point(v.X, v.Y);
|
||||
}
|
||||
|
||||
public static bool IsNaN(this double d)
|
||||
{
|
||||
return Double.IsNaN(d);
|
||||
}
|
||||
|
||||
public static bool IsNotNaN(this double d)
|
||||
{
|
||||
return !Double.IsNaN(d);
|
||||
}
|
||||
|
||||
public static bool IsFinite(this double d)
|
||||
{
|
||||
return !Double.IsNaN(d) && !Double.IsInfinity(d);
|
||||
}
|
||||
|
||||
public static bool IsInfinite(this double d)
|
||||
{
|
||||
return Double.IsInfinity(d);
|
||||
}
|
||||
|
||||
public static bool AreClose(double d1, double d2, double diffRatio)
|
||||
{
|
||||
return Math.Abs(d1 / d2 - 1) < diffRatio;
|
||||
}
|
||||
}
|
||||
}
|
||||
16
Common/Auxiliary/MenuItemExtensions.cs
Normal file
16
Common/Auxiliary/MenuItemExtensions.cs
Normal file
@@ -0,0 +1,16 @@
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Linq;
|
||||
using System.Text;
|
||||
using System.Windows.Controls;
|
||||
|
||||
namespace Microsoft.Research.DynamicDataDisplay.Common.Auxiliary
|
||||
{
|
||||
internal static class MenuItemExtensions
|
||||
{
|
||||
public static MenuItem FindChildByHeader(this MenuItem parent, string header)
|
||||
{
|
||||
return parent.Items.OfType<MenuItem>().Where(subMenu => subMenu.Header.Equals(header)).FirstOrDefault();
|
||||
}
|
||||
}
|
||||
}
|
||||
35
Common/Auxiliary/ObservableCollectionHelper.cs
Normal file
35
Common/Auxiliary/ObservableCollectionHelper.cs
Normal file
@@ -0,0 +1,35 @@
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Linq;
|
||||
using System.Text;
|
||||
using System.Collections.ObjectModel;
|
||||
using System.Collections.Specialized;
|
||||
|
||||
namespace Microsoft.Research.DynamicDataDisplay.Common.Auxiliary
|
||||
{
|
||||
internal static class ObservableCollectionHelper
|
||||
{
|
||||
public static void ApplyChanges<T>(this ObservableCollection<T> collection, NotifyCollectionChangedEventArgs args)
|
||||
{
|
||||
if (args.NewItems != null)
|
||||
{
|
||||
int startingIndex = args.NewStartingIndex;
|
||||
var newItems = args.NewItems;
|
||||
|
||||
for (int i = 0; i < newItems.Count; i++)
|
||||
{
|
||||
T addedItem = (T)newItems[i];
|
||||
collection.Insert(startingIndex + i, addedItem);
|
||||
}
|
||||
}
|
||||
if (args.OldItems != null)
|
||||
{
|
||||
for (int i = 0; i < args.OldItems.Count; i++)
|
||||
{
|
||||
T removedItem = (T)args.OldItems[i];
|
||||
collection.Remove(removedItem);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
16
Common/Auxiliary/PlacementExtensions.cs
Normal file
16
Common/Auxiliary/PlacementExtensions.cs
Normal file
@@ -0,0 +1,16 @@
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Linq;
|
||||
using System.Text;
|
||||
using Microsoft.Research.DynamicDataDisplay.Charts;
|
||||
|
||||
namespace Microsoft.Research.DynamicDataDisplay.Common.Auxiliary
|
||||
{
|
||||
internal static class PlacementExtensions
|
||||
{
|
||||
public static bool IsBottomOrTop(this AxisPlacement placement)
|
||||
{
|
||||
return placement == AxisPlacement.Bottom || placement == AxisPlacement.Top;
|
||||
}
|
||||
}
|
||||
}
|
||||
32
Common/Auxiliary/PlotterChildrenCollectionExtensions.cs
Normal file
32
Common/Auxiliary/PlotterChildrenCollectionExtensions.cs
Normal file
@@ -0,0 +1,32 @@
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Linq;
|
||||
using System.Text;
|
||||
using Microsoft.Research.DynamicDataDisplay.Common;
|
||||
using System.Windows.Threading;
|
||||
|
||||
namespace Microsoft.Research.DynamicDataDisplay
|
||||
{
|
||||
public static class PlotterChildrenCollectionExtensions
|
||||
{
|
||||
public static void RemoveAll<T>(this PlotterChildrenCollection children)
|
||||
{
|
||||
var childrenToDelete = children.OfType<T>().ToList();
|
||||
|
||||
foreach (var child in childrenToDelete)
|
||||
{
|
||||
children.Remove(child as IPlotterElement);
|
||||
}
|
||||
}
|
||||
|
||||
public static void BeginAdd(this PlotterChildrenCollection children, IPlotterElement child)
|
||||
{
|
||||
children.Plotter.Dispatcher.BeginInvoke(((Action)(() => { children.Add(child); })), DispatcherPriority.Send);
|
||||
}
|
||||
|
||||
public static void BeginRemove(this PlotterChildrenCollection children, IPlotterElement child)
|
||||
{
|
||||
children.Plotter.Dispatcher.BeginInvoke(((Action)(() => { children.Remove(child); })), DispatcherPriority.Send);
|
||||
}
|
||||
}
|
||||
}
|
||||
15
Common/Auxiliary/PlotterExtensions.cs
Normal file
15
Common/Auxiliary/PlotterExtensions.cs
Normal file
@@ -0,0 +1,15 @@
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Linq;
|
||||
using System.Text;
|
||||
|
||||
namespace Microsoft.Research.DynamicDataDisplay.Common.Auxiliary
|
||||
{
|
||||
public static class PlotterExtensions
|
||||
{
|
||||
public static void AddChild(this Plotter plotter, IPlotterElement child)
|
||||
{
|
||||
plotter.Children.Add(child);
|
||||
}
|
||||
}
|
||||
}
|
||||
19
Common/Auxiliary/PointExtensions.cs
Normal file
19
Common/Auxiliary/PointExtensions.cs
Normal file
@@ -0,0 +1,19 @@
|
||||
using System.Windows;
|
||||
using System;
|
||||
using Microsoft.Research.DynamicDataDisplay.Common.Auxiliary;
|
||||
|
||||
namespace Microsoft.Research.DynamicDataDisplay
|
||||
{
|
||||
public static class PointExtensions
|
||||
{
|
||||
public static Vector ToVector(this Point pt)
|
||||
{
|
||||
return new Vector(pt.X, pt.Y);
|
||||
}
|
||||
|
||||
public static bool IsFinite(this Point pt)
|
||||
{
|
||||
return pt.X.IsFinite() && pt.Y.IsFinite();
|
||||
}
|
||||
}
|
||||
}
|
||||
15
Common/Auxiliary/RandomExtensions.cs
Normal file
15
Common/Auxiliary/RandomExtensions.cs
Normal file
@@ -0,0 +1,15 @@
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Linq;
|
||||
using System.Text;
|
||||
|
||||
namespace Microsoft.Research.DynamicDataDisplay.Common.Auxiliary
|
||||
{
|
||||
public static class RandomExtensions
|
||||
{
|
||||
public static double NextDouble(this Random rnd, double min, double max)
|
||||
{
|
||||
return min + (max - min) * rnd.NextDouble();
|
||||
}
|
||||
}
|
||||
}
|
||||
25
Common/Auxiliary/RangeExtensions.cs
Normal file
25
Common/Auxiliary/RangeExtensions.cs
Normal file
@@ -0,0 +1,25 @@
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Linq;
|
||||
using System.Text;
|
||||
using System.Windows;
|
||||
using Microsoft.Research.DynamicDataDisplay.Charts;
|
||||
|
||||
namespace Microsoft.Research.DynamicDataDisplay
|
||||
{
|
||||
public static class RangeExtensions
|
||||
{
|
||||
public static double GetLength(this Range<Point> range)
|
||||
{
|
||||
Point p1 = range.Min;
|
||||
Point p2 = range.Max;
|
||||
|
||||
return (p1 - p2).Length;
|
||||
}
|
||||
|
||||
public static double GetLength(this Range<double> range)
|
||||
{
|
||||
return range.Max - range.Min;
|
||||
}
|
||||
}
|
||||
}
|
||||
67
Common/Auxiliary/RectExtensions.cs
Normal file
67
Common/Auxiliary/RectExtensions.cs
Normal file
@@ -0,0 +1,67 @@
|
||||
using System.Windows;
|
||||
using Microsoft.Research.DynamicDataDisplay.Common;
|
||||
using System.Diagnostics;
|
||||
|
||||
namespace Microsoft.Research.DynamicDataDisplay
|
||||
{
|
||||
public static class RectExtensions
|
||||
{
|
||||
public static Point GetCenter(this Rect rect)
|
||||
{
|
||||
return new Point(rect.Left + rect.Width * 0.5, rect.Top + rect.Height * 0.5);
|
||||
}
|
||||
|
||||
public static Rect FromCenterSize(Point center, Size size)
|
||||
{
|
||||
return FromCenterSize(center, size.Width, size.Height);
|
||||
}
|
||||
|
||||
public static Rect FromCenterSize(Point center, double width, double height)
|
||||
{
|
||||
Rect res = new Rect(center.X - width / 2, center.Y - height / 2, width, height);
|
||||
return res;
|
||||
}
|
||||
|
||||
public static Rect Zoom(this Rect rect, Point to, double ratio)
|
||||
{
|
||||
return CoordinateUtilities.RectZoom(rect, to, ratio);
|
||||
}
|
||||
|
||||
public static Rect ZoomOutFromCenter(this Rect rect, double ratio)
|
||||
{
|
||||
return CoordinateUtilities.RectZoom(rect, rect.GetCenter(), ratio);
|
||||
}
|
||||
|
||||
public static Rect ZoomInToCenter(this Rect rect, double ratio)
|
||||
{
|
||||
return CoordinateUtilities.RectZoom(rect, rect.GetCenter(), 1 / ratio);
|
||||
}
|
||||
|
||||
public static Int32Rect ToInt32Rect(this Rect rect)
|
||||
{
|
||||
Int32Rect intRect = new Int32Rect(
|
||||
(int)rect.X,
|
||||
(int)rect.Y,
|
||||
(int)rect.Width,
|
||||
(int)rect.Height);
|
||||
|
||||
return intRect;
|
||||
}
|
||||
|
||||
[DebuggerStepThrough]
|
||||
public static DataRect ToDataRect(this Rect rect)
|
||||
{
|
||||
return new DataRect(rect);
|
||||
}
|
||||
|
||||
internal static bool IsNaN(this Rect rect)
|
||||
{
|
||||
return !rect.IsEmpty && (
|
||||
rect.X.IsNaN() ||
|
||||
rect.Y.IsNaN() ||
|
||||
rect.Width.IsNaN() ||
|
||||
rect.Height.IsNaN()
|
||||
);
|
||||
}
|
||||
}
|
||||
}
|
||||
22
Common/Auxiliary/ResourcePoolExtensions.cs
Normal file
22
Common/Auxiliary/ResourcePoolExtensions.cs
Normal file
@@ -0,0 +1,22 @@
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Linq;
|
||||
using System.Text;
|
||||
using System.Diagnostics;
|
||||
|
||||
namespace Microsoft.Research.DynamicDataDisplay.Common.Auxiliary
|
||||
{
|
||||
internal static class ResourcePoolExtensions
|
||||
{
|
||||
public static T GetOrCreate<T>(this ResourcePool<T> pool) where T : new()
|
||||
{
|
||||
T instance = pool.Get();
|
||||
if (instance == null)
|
||||
{
|
||||
instance = new T();
|
||||
}
|
||||
|
||||
return instance;
|
||||
}
|
||||
}
|
||||
}
|
||||
205
Common/Auxiliary/ScreenshotHelper.cs
Normal file
205
Common/Auxiliary/ScreenshotHelper.cs
Normal file
@@ -0,0 +1,205 @@
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Linq;
|
||||
using System.Text;
|
||||
using System.Windows.Media.Imaging;
|
||||
using System.Windows;
|
||||
using System.Windows.Media;
|
||||
using System.IO;
|
||||
using System.Diagnostics;
|
||||
using System.Windows.Threading;
|
||||
using System.Windows.Shapes;
|
||||
|
||||
namespace Microsoft.Research.DynamicDataDisplay.Common.Auxiliary
|
||||
{
|
||||
internal static class ScreenshotHelper
|
||||
{
|
||||
/// <summary>Gets the encoder by extension</summary>
|
||||
/// <param name="extension">The extension</param>
|
||||
/// <returns>BitmapEncoder object</returns>
|
||||
internal static BitmapEncoder GetEncoderByExtension(string extension)
|
||||
{
|
||||
switch (extension)
|
||||
{
|
||||
case "bmp":
|
||||
return new BmpBitmapEncoder();
|
||||
case "jpg":
|
||||
return new JpegBitmapEncoder();
|
||||
case "gif":
|
||||
return new GifBitmapEncoder();
|
||||
case "png":
|
||||
return new PngBitmapEncoder();
|
||||
case "tiff":
|
||||
return new TiffBitmapEncoder();
|
||||
case "wmp":
|
||||
return new WmpBitmapEncoder();
|
||||
default:
|
||||
throw new ArgumentException(Strings.Exceptions.CannotDetermineImageTypeByExtension, "extension");
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>Creates the screenshot of entire plotter element</summary>
|
||||
/// <returns></returns>
|
||||
internal static BitmapSource CreateScreenshot(UIElement uiElement, Int32Rect screenshotSource)
|
||||
{
|
||||
Window window = Window.GetWindow(uiElement);
|
||||
if (window == null)
|
||||
{
|
||||
return CreateElementScreenshot(uiElement);
|
||||
}
|
||||
Size size = window.RenderSize;
|
||||
|
||||
//double dpiCoeff = 32 / SystemParameters.CursorWidth;
|
||||
//int dpi = (int)(dpiCoeff * 96);
|
||||
double dpiCoeff = 1;
|
||||
int dpi = 96;
|
||||
|
||||
RenderTargetBitmap bmp = new RenderTargetBitmap(
|
||||
(int)(size.Width * dpiCoeff), (int)(size.Height * dpiCoeff),
|
||||
dpi, dpi, PixelFormats.Default);
|
||||
|
||||
// white background
|
||||
Rectangle whiteRect = new Rectangle { Width = size.Width, Height = size.Height, Fill = Brushes.White };
|
||||
whiteRect.Measure(size);
|
||||
whiteRect.Arrange(new Rect(size));
|
||||
bmp.Render(whiteRect);
|
||||
// the very element
|
||||
bmp.Render(uiElement);
|
||||
|
||||
CroppedBitmap croppedBmp = new CroppedBitmap(bmp, screenshotSource);
|
||||
return croppedBmp;
|
||||
}
|
||||
|
||||
private static BitmapSource CreateElementScreenshot(UIElement uiElement)
|
||||
{
|
||||
bool measureValid = uiElement.IsMeasureValid;
|
||||
|
||||
if (!measureValid)
|
||||
{
|
||||
double width = 300;
|
||||
double height = 300;
|
||||
|
||||
FrameworkElement frElement = uiElement as FrameworkElement;
|
||||
if (frElement != null)
|
||||
{
|
||||
if (!Double.IsNaN(frElement.Width))
|
||||
width = frElement.Width;
|
||||
if (!Double.IsNaN(frElement.Height))
|
||||
height = frElement.Height;
|
||||
}
|
||||
|
||||
Size size = new Size(width, height);
|
||||
uiElement.Measure(size);
|
||||
uiElement.Arrange(new Rect(size));
|
||||
}
|
||||
|
||||
RenderTargetBitmap bmp = new RenderTargetBitmap(
|
||||
(int)uiElement.RenderSize.Width, (int)uiElement.RenderSize.Height,
|
||||
96, 96, PixelFormats.Default);
|
||||
|
||||
// this is waiting for dispatcher to perform measure, arrange and render passes
|
||||
uiElement.Dispatcher.Invoke(((Action)(() => { })), DispatcherPriority.Background);
|
||||
|
||||
Size elementSize = uiElement.DesiredSize;
|
||||
// white background
|
||||
Rectangle whiteRect = new Rectangle { Width = elementSize.Width, Height = elementSize.Height, Fill = Brushes.White };
|
||||
whiteRect.Measure(elementSize);
|
||||
whiteRect.Arrange(new Rect(elementSize));
|
||||
bmp.Render(whiteRect);
|
||||
|
||||
bmp.Render(uiElement);
|
||||
|
||||
return bmp;
|
||||
}
|
||||
|
||||
private static Dictionary<BitmapSource, string> pendingBitmaps = new Dictionary<BitmapSource, string>();
|
||||
|
||||
internal static void SaveBitmapToStream(BitmapSource bitmap, Stream stream, string fileExtension)
|
||||
{
|
||||
if (bitmap == null)
|
||||
throw new ArgumentNullException("bitmap");
|
||||
if (stream == null)
|
||||
throw new ArgumentNullException("stream");
|
||||
if (String.IsNullOrEmpty(fileExtension))
|
||||
throw new ArgumentException(Strings.Exceptions.ExtensionCannotBeNullOrEmpty, fileExtension);
|
||||
|
||||
BitmapEncoder encoder = ScreenshotHelper.GetEncoderByExtension(fileExtension);
|
||||
encoder.Frames.Add(BitmapFrame.Create(bitmap, null, new BitmapMetadata(fileExtension.Trim('.')), null));
|
||||
encoder.Save(stream);
|
||||
}
|
||||
|
||||
internal static void SaveBitmapToFile(BitmapSource bitmap, string filePath)
|
||||
{
|
||||
if (String.IsNullOrEmpty(filePath))
|
||||
throw new ArgumentException(Strings.Exceptions.FilePathCannotbeNullOrEmpty, "filePath");
|
||||
|
||||
if (bitmap.IsDownloading)
|
||||
{
|
||||
pendingBitmaps[bitmap] = filePath;
|
||||
bitmap.DownloadCompleted += OnBitmapDownloadCompleted;
|
||||
return;
|
||||
}
|
||||
|
||||
string dirPath = System.IO.Path.GetDirectoryName(filePath);
|
||||
if (!String.IsNullOrEmpty(dirPath) && !Directory.Exists(dirPath))
|
||||
{
|
||||
Directory.CreateDirectory(dirPath);
|
||||
}
|
||||
|
||||
bool fileExistedBefore = File.Exists(filePath);
|
||||
try
|
||||
{
|
||||
using (FileStream fs = new FileStream(filePath, FileMode.Create, FileAccess.Write))
|
||||
{
|
||||
string extension = System.IO.Path.GetExtension(filePath).TrimStart('.');
|
||||
SaveBitmapToStream(bitmap, fs, extension);
|
||||
}
|
||||
}
|
||||
catch (ArgumentException)
|
||||
{
|
||||
if (!fileExistedBefore && File.Exists(filePath))
|
||||
{
|
||||
try
|
||||
{
|
||||
File.Delete(filePath);
|
||||
}
|
||||
catch { }
|
||||
}
|
||||
}
|
||||
catch (IOException exc)
|
||||
{
|
||||
Debug.WriteLine("Exception while saving bitmap to file: " + exc.Message);
|
||||
}
|
||||
}
|
||||
|
||||
public static void SaveStreamToFile(Stream stream, string filePath)
|
||||
{
|
||||
string dirPath = System.IO.Path.GetDirectoryName(filePath);
|
||||
if (!String.IsNullOrEmpty(dirPath) && !Directory.Exists(dirPath))
|
||||
{
|
||||
Directory.CreateDirectory(dirPath);
|
||||
}
|
||||
|
||||
using (FileStream fs = new FileStream(filePath, FileMode.Create, FileAccess.Write))
|
||||
{
|
||||
string extension = System.IO.Path.GetExtension(filePath).TrimStart('.');
|
||||
if (stream.CanSeek)
|
||||
stream.Seek(0, SeekOrigin.Begin);
|
||||
|
||||
stream.CopyTo(fs);
|
||||
}
|
||||
|
||||
stream.Dispose();
|
||||
}
|
||||
|
||||
private static void OnBitmapDownloadCompleted(object sender, EventArgs e)
|
||||
{
|
||||
BitmapSource bmp = (BitmapSource)sender;
|
||||
bmp.DownloadCompleted -= OnBitmapDownloadCompleted;
|
||||
string filePath = pendingBitmaps[bmp];
|
||||
pendingBitmaps.Remove(bmp);
|
||||
|
||||
SaveBitmapToFile(bmp, filePath);
|
||||
}
|
||||
}
|
||||
}
|
||||
20
Common/Auxiliary/SizeExtensions.cs
Normal file
20
Common/Auxiliary/SizeExtensions.cs
Normal file
@@ -0,0 +1,20 @@
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Linq;
|
||||
using System.Text;
|
||||
using System.Windows;
|
||||
|
||||
namespace Microsoft.Research.DynamicDataDisplay.Common.Auxiliary
|
||||
{
|
||||
internal static class SizeExtensions
|
||||
{
|
||||
private const double sizeRatio = 1e-7;
|
||||
public static bool EqualsApproximately(this Size size1, Size size2)
|
||||
{
|
||||
bool widthEquals = Math.Abs(size1.Width - size2.Width) / size1.Width < sizeRatio;
|
||||
bool heightEquals = Math.Abs(size1.Height - size2.Height) / size1.Height < sizeRatio;
|
||||
|
||||
return widthEquals && heightEquals;
|
||||
}
|
||||
}
|
||||
}
|
||||
16
Common/Auxiliary/SizeHelper.cs
Normal file
16
Common/Auxiliary/SizeHelper.cs
Normal file
@@ -0,0 +1,16 @@
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Linq;
|
||||
using System.Text;
|
||||
using System.Windows;
|
||||
|
||||
namespace Microsoft.Research.DynamicDataDisplay.Common.Auxiliary
|
||||
{
|
||||
internal static class SizeHelper
|
||||
{
|
||||
public static Size CreateInfiniteSize()
|
||||
{
|
||||
return new Size(Double.PositiveInfinity, Double.PositiveInfinity);
|
||||
}
|
||||
}
|
||||
}
|
||||
23
Common/Auxiliary/StreamExtensions.cs
Normal file
23
Common/Auxiliary/StreamExtensions.cs
Normal file
@@ -0,0 +1,23 @@
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Linq;
|
||||
using System.Text;
|
||||
using System.IO;
|
||||
|
||||
namespace Microsoft.Research.DynamicDataDisplay.Common.Auxiliary
|
||||
{
|
||||
public static class StreamExtensions
|
||||
{
|
||||
public static void CopyTo(this Stream input, Stream output)
|
||||
{
|
||||
byte[] buffer = new byte[32768];
|
||||
while (true)
|
||||
{
|
||||
int read = input.Read(buffer, 0, buffer.Length);
|
||||
if (read <= 0)
|
||||
return;
|
||||
output.Write(buffer, 0, read);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
20
Common/Auxiliary/StringExtensions.cs
Normal file
20
Common/Auxiliary/StringExtensions.cs
Normal file
@@ -0,0 +1,20 @@
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Linq;
|
||||
using System.Text;
|
||||
|
||||
namespace Microsoft.Research.DynamicDataDisplay.Common.Auxiliary
|
||||
{
|
||||
internal static class StringExtensions
|
||||
{
|
||||
public static string Format(this string formatString, object param)
|
||||
{
|
||||
return String.Format(formatString, param);
|
||||
}
|
||||
|
||||
public static string Format(this string formatString, object param1, object param2)
|
||||
{
|
||||
return String.Format(formatString, param1, param2);
|
||||
}
|
||||
}
|
||||
}
|
||||
50
Common/Auxiliary/TaskExtensions.cs
Normal file
50
Common/Auxiliary/TaskExtensions.cs
Normal file
@@ -0,0 +1,50 @@
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Linq;
|
||||
using System.Text;
|
||||
using System.Threading.Tasks;
|
||||
using System.Diagnostics;
|
||||
using System.Windows.Threading;
|
||||
|
||||
namespace Microsoft.Research.DynamicDataDisplay.Common.Auxiliary
|
||||
{
|
||||
public static class TaskExtensions
|
||||
{
|
||||
/// <summary>
|
||||
/// Logs exceptions that occur during task execution.
|
||||
/// </summary>
|
||||
/// <param name="task">The task.</param>
|
||||
/// <returns></returns>
|
||||
public static Task WithExceptionLogging(this Task task)
|
||||
{
|
||||
return task.ContinueWith(t =>
|
||||
{
|
||||
var exception = t.Exception;
|
||||
if (exception != null)
|
||||
{
|
||||
if (exception.InnerException != null)
|
||||
exception = (AggregateException)exception.InnerException;
|
||||
|
||||
Debug.WriteLine("Failure in async task: " + exception.Message);
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Rethrows exceptions thrown during task execution in thespecified dispatcher thread.
|
||||
/// </summary>
|
||||
/// <param name="task">The task.</param>
|
||||
/// <param name="dispatcher">The dispatcher.</param>
|
||||
/// <returns></returns>
|
||||
public static Task WithExceptionThrowingInDispatcher(this Task task, Dispatcher dispatcher)
|
||||
{
|
||||
return task.ContinueWith(t =>
|
||||
{
|
||||
dispatcher.BeginInvoke(() =>
|
||||
{
|
||||
throw t.Exception;
|
||||
}, DispatcherPriority.Send);
|
||||
});
|
||||
}
|
||||
}
|
||||
}
|
||||
73
Common/Auxiliary/TriangleMath.cs
Normal file
73
Common/Auxiliary/TriangleMath.cs
Normal file
@@ -0,0 +1,73 @@
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Linq;
|
||||
using System.Text;
|
||||
using System.Windows;
|
||||
using System.Windows.Media.Media3D;
|
||||
|
||||
namespace Microsoft.Research.DynamicDataDisplay.Common.Auxiliary
|
||||
{
|
||||
public static class TriangleMath
|
||||
{
|
||||
public static bool TriangleContains(Point a, Point b, Point c, Point m)
|
||||
{
|
||||
double a0 = a.X - c.X;
|
||||
double a1 = b.X - c.X;
|
||||
double a2 = a.Y - c.Y;
|
||||
double a3 = b.Y - c.Y;
|
||||
|
||||
if (AreClose(a0 * a3, a1 * a2))
|
||||
{
|
||||
// determinant is too close to zero => apexes are on one line
|
||||
Vector ab = a - b;
|
||||
Vector ac = a - c;
|
||||
Vector bc = b - c;
|
||||
Vector ax = a - m;
|
||||
Vector bx = b - m;
|
||||
bool res = AreClose(ab.X * ax.Y, ab.Y * ax.X) && !AreClose(ab.LengthSquared, 0) ||
|
||||
AreClose(ac.X * ax.Y, ac.Y * ax.X) && !AreClose(ac.LengthSquared, 0) ||
|
||||
AreClose(bc.X * bx.Y, bc.Y * bx.X) && !AreClose(bc.LengthSquared, 0);
|
||||
return res;
|
||||
}
|
||||
else
|
||||
{
|
||||
double b1 = m.X - c.X;
|
||||
double b2 = m.Y - c.Y;
|
||||
|
||||
// alpha, beta and gamma - are baricentric coordinates of v
|
||||
// in triangle with apexes a, b and c
|
||||
double beta = (b2 / a2 * a0 - b1) / (a3 / a2 * a0 - a1);
|
||||
double alpha = (b1 - a1 * beta) / a0;
|
||||
double gamma = 1 - beta - alpha;
|
||||
return alpha >= 0 && beta >= 0 && gamma >= 0;
|
||||
}
|
||||
}
|
||||
|
||||
private const double eps = 0.00001;
|
||||
private static bool AreClose(double x, double y)
|
||||
{
|
||||
return Math.Abs(x - y) < eps;
|
||||
}
|
||||
|
||||
public static Vector3D GetBaricentricCoordinates(Point a, Point b, Point c, Point m)
|
||||
{
|
||||
double Sac = GetSquare(a, c, m);
|
||||
double Sbc = GetSquare(b, c, m);
|
||||
double Sab = GetSquare(a, b, m);
|
||||
|
||||
double sum = (Sab + Sac + Sbc) / 3;
|
||||
|
||||
return new Vector3D(Sbc / sum, Sac / sum, Sab / sum);
|
||||
}
|
||||
|
||||
public static double GetSquare(Point a, Point b, Point c)
|
||||
{
|
||||
double ab = (a - b).Length;
|
||||
double ac = (a - c).Length;
|
||||
double bc = (b - c).Length;
|
||||
|
||||
double p = 0.5 * (ab + ac + bc); // half of perimeter
|
||||
return Math.Sqrt(p * (p - ab) * (p - ac) * (p - bc));
|
||||
}
|
||||
}
|
||||
}
|
||||
106
Common/Auxiliary/ValueStore.cs
Normal file
106
Common/Auxiliary/ValueStore.cs
Normal file
@@ -0,0 +1,106 @@
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Linq;
|
||||
using System.Text;
|
||||
using System.ComponentModel;
|
||||
using System.Diagnostics;
|
||||
|
||||
namespace Microsoft.Research.DynamicDataDisplay
|
||||
{
|
||||
public sealed class ValueStore : CustomTypeDescriptor, INotifyPropertyChanged
|
||||
{
|
||||
public ValueStore(params string[] propertiesNames)
|
||||
{
|
||||
foreach (var propertyName in propertiesNames)
|
||||
{
|
||||
this[propertyName] = "";
|
||||
}
|
||||
}
|
||||
|
||||
private Dictionary<string, object> cache = new Dictionary<string, object>();
|
||||
|
||||
public object this[string propertyName]
|
||||
{
|
||||
get { return cache[propertyName]; }
|
||||
set { SetValue(propertyName, value); }
|
||||
}
|
||||
|
||||
public ValueStore SetValue(string propertyName, object value)
|
||||
{
|
||||
cache[propertyName] = value;
|
||||
PropertyChanged.Raise(this, propertyName);
|
||||
|
||||
return this;
|
||||
}
|
||||
|
||||
private PropertyDescriptorCollection collection;
|
||||
public override PropertyDescriptorCollection GetProperties()
|
||||
{
|
||||
PropertyDescriptor[] propertyDescriptors = new PropertyDescriptor[cache.Count];
|
||||
var keys = cache.Keys.ToArray();
|
||||
for (int i = 0; i < keys.Length; i++)
|
||||
{
|
||||
propertyDescriptors[i] = new ValueStorePropertyDescriptor(keys[i]);
|
||||
}
|
||||
|
||||
collection = new PropertyDescriptorCollection(propertyDescriptors);
|
||||
return collection;
|
||||
}
|
||||
|
||||
private sealed class ValueStorePropertyDescriptor : PropertyDescriptor
|
||||
{
|
||||
private readonly string name;
|
||||
|
||||
public ValueStorePropertyDescriptor(string name)
|
||||
: base(name, null)
|
||||
{
|
||||
this.name = name;
|
||||
}
|
||||
|
||||
public override bool CanResetValue(object component)
|
||||
{
|
||||
return false;
|
||||
}
|
||||
|
||||
public override Type ComponentType
|
||||
{
|
||||
get { return typeof(ValueStore); }
|
||||
}
|
||||
|
||||
public override object GetValue(object component)
|
||||
{
|
||||
ValueStore store = (ValueStore)component;
|
||||
return store[name];
|
||||
}
|
||||
|
||||
public override bool IsReadOnly
|
||||
{
|
||||
get { return false; }
|
||||
}
|
||||
|
||||
public override Type PropertyType
|
||||
{
|
||||
get { return typeof(string); }
|
||||
}
|
||||
|
||||
public override void ResetValue(object component)
|
||||
{
|
||||
}
|
||||
|
||||
public override void SetValue(object component, object value)
|
||||
{
|
||||
}
|
||||
|
||||
public override bool ShouldSerializeValue(object component)
|
||||
{
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
#region INotifyPropertyChanged Members
|
||||
|
||||
public event PropertyChangedEventHandler PropertyChanged;
|
||||
|
||||
#endregion
|
||||
}
|
||||
}
|
||||
30
Common/Auxiliary/ValueStoreConverter.cs
Normal file
30
Common/Auxiliary/ValueStoreConverter.cs
Normal file
@@ -0,0 +1,30 @@
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Linq;
|
||||
using System.Text;
|
||||
using System.Windows.Data;
|
||||
using System.Globalization;
|
||||
|
||||
namespace Microsoft.Research.DynamicDataDisplay
|
||||
{
|
||||
public sealed class ValueStoreConverter : IValueConverter
|
||||
{
|
||||
|
||||
#region IValueConverter Members
|
||||
|
||||
public object Convert(object value, Type targetType, object parameter, CultureInfo culture)
|
||||
{
|
||||
ValueStore store = (ValueStore)value;
|
||||
string key = (string)parameter;
|
||||
|
||||
return store[key];
|
||||
}
|
||||
|
||||
public object ConvertBack(object value, Type targetType, object parameter, CultureInfo culture)
|
||||
{
|
||||
throw new NotSupportedException();
|
||||
}
|
||||
|
||||
#endregion
|
||||
}
|
||||
}
|
||||
16
Common/Auxiliary/VectorExtensions.cs
Normal file
16
Common/Auxiliary/VectorExtensions.cs
Normal file
@@ -0,0 +1,16 @@
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Linq;
|
||||
using System.Text;
|
||||
using System.Windows;
|
||||
|
||||
namespace Microsoft.Research.DynamicDataDisplay.Common.Auxiliary
|
||||
{
|
||||
internal static class VectorExtensions
|
||||
{
|
||||
public static Point ToPoint(this Vector vector)
|
||||
{
|
||||
return new Point(vector.X, vector.Y);
|
||||
}
|
||||
}
|
||||
}
|
||||
64
Common/Auxiliary/Verify.cs
Normal file
64
Common/Auxiliary/Verify.cs
Normal file
@@ -0,0 +1,64 @@
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Linq;
|
||||
using System.Text;
|
||||
using System.Diagnostics;
|
||||
|
||||
namespace Microsoft.Research.DynamicDataDisplay.Common.Auxiliary
|
||||
{
|
||||
internal static class Verify
|
||||
{
|
||||
[DebuggerStepThrough]
|
||||
public static void IsTrue(this bool condition)
|
||||
{
|
||||
if (!condition)
|
||||
{
|
||||
throw new ArgumentException(Strings.Exceptions.AssertionFailedSearch);
|
||||
}
|
||||
}
|
||||
|
||||
[DebuggerStepThrough]
|
||||
public static void IsTrue(this bool condition, string paramName)
|
||||
{
|
||||
if (!condition)
|
||||
{
|
||||
throw new ArgumentException(Strings.Exceptions.AssertionFailedSearch, paramName);
|
||||
}
|
||||
}
|
||||
|
||||
public static void IsTrueWithMessage(this bool condition, string message)
|
||||
{
|
||||
if (!condition)
|
||||
throw new ArgumentException(message);
|
||||
}
|
||||
|
||||
[DebuggerStepThrough]
|
||||
public static void AssertNotNull(object obj)
|
||||
{
|
||||
Verify.IsTrue(obj != null);
|
||||
}
|
||||
|
||||
public static void VerifyNotNull(this object obj, string paramName)
|
||||
{
|
||||
if (obj == null)
|
||||
throw new ArgumentNullException(paramName);
|
||||
}
|
||||
|
||||
public static void VerifyNotNull(this object obj)
|
||||
{
|
||||
VerifyNotNull(obj, "value");
|
||||
}
|
||||
|
||||
[DebuggerStepThrough]
|
||||
public static void AssertIsNotNaN(this double d)
|
||||
{
|
||||
Verify.IsTrue(!Double.IsNaN(d));
|
||||
}
|
||||
|
||||
[DebuggerStepThrough]
|
||||
public static void AssertIsFinite(this double d)
|
||||
{
|
||||
Verify.IsTrue(!Double.IsInfinity(d) && !(Double.IsNaN(d)));
|
||||
}
|
||||
}
|
||||
}
|
||||
27
Common/Auxiliary/VisualTreeHelperHelper.cs
Normal file
27
Common/Auxiliary/VisualTreeHelperHelper.cs
Normal file
@@ -0,0 +1,27 @@
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Linq;
|
||||
using System.Text;
|
||||
using System.Windows;
|
||||
using System.Windows.Media;
|
||||
|
||||
namespace Microsoft.Research.DynamicDataDisplay.Common.Auxiliary
|
||||
{
|
||||
internal static class VisualTreeHelperHelper
|
||||
{
|
||||
public static DependencyObject GetParent(DependencyObject target, int depth)
|
||||
{
|
||||
DependencyObject parent = target;
|
||||
do
|
||||
{
|
||||
parent = VisualTreeHelper.GetParent(parent);
|
||||
if (parent == null)
|
||||
{
|
||||
break;
|
||||
}
|
||||
} while (--depth > 0);
|
||||
|
||||
return parent;
|
||||
}
|
||||
}
|
||||
}
|
||||
Reference in New Issue
Block a user