# HG changeset patch # User moel.mich # Date 1370710402 0 # Node ID 5be8f27732373b285e7a9452b6bb5f08e44f65df # Parent 88d699a65cc2c1e571d455ea20b0dcc1ecc86b06 Added the source code of OxyPlot as of commit d190d7748a73 (6.5.2013). diff -r 88d699a65cc2 -r 5be8f2773237 External/OxyPlot/GlobalAssemblyInfo.cs --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/External/OxyPlot/GlobalAssemblyInfo.cs Sat Jun 08 16:53:22 2013 +0000 @@ -0,0 +1,38 @@ +//----------------------------------------------------------------------- +// +// The MIT License (MIT) +// +// Copyright (c) 2012 Oystein Bjorke +// +// Permission is hereby granted, free of charge, to any person obtaining a +// copy of this software and associated documentation files (the +// "Software"), to deal in the Software without restriction, including +// without limitation the rights to use, copy, modify, merge, publish, +// distribute, sublicense, and/or sell copies of the Software, and to +// permit persons to whom the Software is furnished to do so, subject to +// the following conditions: +// +// The above copyright notice and this permission notice shall be included +// in all copies or substantial portions of the Software. +// +// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS +// OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF +// MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. +// IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY +// CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, +// TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE +// SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. +// +//----------------------------------------------------------------------- + +using System.Reflection; + +[assembly: AssemblyConfiguration("")] +[assembly: AssemblyProduct("OxyPlot")] +[assembly: AssemblyCompany("OxyPlot")] +[assembly: AssemblyCopyright("Copyright (C) OxyPlot 2012.")] +[assembly: AssemblyTrademark("")] +[assembly: AssemblyCulture("")] + +[assembly: AssemblyVersion("2013.1.1.1")] +[assembly: AssemblyFileVersion("2013.1.1.1")] diff -r 88d699a65cc2 -r 5be8f2773237 External/OxyPlot/OxyPlot.WindowsForms/GraphicsRenderContext.cs --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/External/OxyPlot/OxyPlot.WindowsForms/GraphicsRenderContext.cs Sat Jun 08 16:53:22 2013 +0000 @@ -0,0 +1,558 @@ +// -------------------------------------------------------------------------------------------------------------------- +// +// The MIT License (MIT) +// +// Copyright (c) 2012 Oystein Bjorke +// +// Permission is hereby granted, free of charge, to any person obtaining a +// copy of this software and associated documentation files (the +// "Software"), to deal in the Software without restriction, including +// without limitation the rights to use, copy, modify, merge, publish, +// distribute, sublicense, and/or sell copies of the Software, and to +// permit persons to whom the Software is furnished to do so, subject to +// the following conditions: +// +// The above copyright notice and this permission notice shall be included +// in all copies or substantial portions of the Software. +// +// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS +// OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF +// MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. +// IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY +// CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, +// TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE +// SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. +// +// +// The graphics render context. +// +// -------------------------------------------------------------------------------------------------------------------- +namespace OxyPlot.WindowsForms +{ + using System; + using System.Collections.Generic; + using System.Drawing; + using System.Drawing.Drawing2D; + using System.Drawing.Imaging; + using System.IO; + using System.Linq; + + using OxyPlot; + + /// + /// The graphics render context. + /// + internal class GraphicsRenderContext : RenderContextBase + { + /// + /// The font size factor. + /// + private const float FontsizeFactor = 0.8f; + + /// + /// The GDI+ drawing surface. + /// + private Graphics g; + + /// + /// Initializes a new instance of the class. + /// + public GraphicsRenderContext() + { + } + + /// + /// Sets the graphics target. + /// + /// The graphics surface. + public void SetGraphicsTarget(Graphics graphics) + { + this.g = graphics; + } + + /// + /// Draws the ellipse. + /// + /// The rect. + /// The fill. + /// The stroke. + /// The thickness. + public override void DrawEllipse(OxyRect rect, OxyColor fill, OxyColor stroke, double thickness) + { + if (fill != null) + { + this.g.FillEllipse( + this.ToBrush(fill), (float)rect.Left, (float)rect.Top, (float)rect.Width, (float)rect.Height); + } + + if (stroke == null || thickness <= 0) + { + return; + } + + using (var pen = new Pen(this.ToColor(stroke), (float)thickness)) + { + this.g.SmoothingMode = SmoothingMode.HighQuality; + this.g.DrawEllipse(pen, (float)rect.Left, (float)rect.Top, (float)rect.Width, (float)rect.Height); + } + } + + /// + /// Draws the line. + /// + /// The points. + /// The stroke. + /// The thickness. + /// The dash array. + /// The line join. + /// if set to true [aliased]. + public override void DrawLine( + IList points, + OxyColor stroke, + double thickness, + double[] dashArray, + OxyPenLineJoin lineJoin, + bool aliased) + { + if (stroke == null || thickness <= 0 || points.Count < 2) + { + return; + } + + this.g.SmoothingMode = aliased ? SmoothingMode.None : SmoothingMode.HighQuality; + using (var pen = new Pen(this.ToColor(stroke), (float)thickness)) + { + + if (dashArray != null) + { + pen.DashPattern = this.ToFloatArray(dashArray); + } + + switch (lineJoin) + { + case OxyPenLineJoin.Round: + pen.LineJoin = LineJoin.Round; + break; + case OxyPenLineJoin.Bevel: + pen.LineJoin = LineJoin.Bevel; + break; + + // The default LineJoin is Miter + } + + this.g.DrawLines(pen, this.ToPoints(points)); + } + } + + /// + /// Draws the polygon. + /// + /// The points. + /// The fill. + /// The stroke. + /// The thickness. + /// The dash array. + /// The line join. + /// if set to true [aliased]. + public override void DrawPolygon( + IList points, + OxyColor fill, + OxyColor stroke, + double thickness, + double[] dashArray, + OxyPenLineJoin lineJoin, + bool aliased) + { + if (points.Count < 2) + { + return; + } + + this.g.SmoothingMode = aliased ? SmoothingMode.None : SmoothingMode.HighQuality; + + PointF[] pts = this.ToPoints(points); + if (fill != null) + { + this.g.FillPolygon(this.ToBrush(fill), pts); + } + + if (stroke != null && thickness > 0) + { + using (var pen = new Pen(this.ToColor(stroke), (float)thickness)) + { + + if (dashArray != null) + { + pen.DashPattern = this.ToFloatArray(dashArray); + } + + switch (lineJoin) + { + case OxyPenLineJoin.Round: + pen.LineJoin = LineJoin.Round; + break; + case OxyPenLineJoin.Bevel: + pen.LineJoin = LineJoin.Bevel; + break; + + // The default LineJoin is Miter + } + + this.g.DrawPolygon(pen, pts); + } + } + } + + /// + /// The draw rectangle. + /// + /// + /// The rect. + /// + /// + /// The fill. + /// + /// + /// The stroke. + /// + /// + /// The thickness. + /// + public override void DrawRectangle(OxyRect rect, OxyColor fill, OxyColor stroke, double thickness) + { + if (fill != null) + { + this.g.FillRectangle( + this.ToBrush(fill), (float)rect.Left, (float)rect.Top, (float)rect.Width, (float)rect.Height); + } + + if (stroke == null || thickness <= 0) + { + return; + } + + using (var pen = new Pen(this.ToColor(stroke), (float)thickness)) + { + this.g.DrawRectangle(pen, (float)rect.Left, (float)rect.Top, (float)rect.Width, (float)rect.Height); + } + } + + /// + /// The draw text. + /// + /// + /// The p. + /// + /// + /// The text. + /// + /// + /// The fill. + /// + /// + /// The font family. + /// + /// + /// The font size. + /// + /// + /// The font weight. + /// + /// + /// The rotate. + /// + /// + /// The halign. + /// + /// + /// The valign. + /// + /// + /// The maximum size of the text. + /// + public override void DrawText( + ScreenPoint p, + string text, + OxyColor fill, + string fontFamily, + double fontSize, + double fontWeight, + double rotate, + HorizontalAlignment halign, + VerticalAlignment valign, + OxySize? maxSize) + { + var fs = FontStyle.Regular; + if (fontWeight >= 700) + { + fs = FontStyle.Bold; + } + + using (var font = new Font(fontFamily, (float)fontSize * FontsizeFactor, fs)) + { + using (var sf = new StringFormat { Alignment = StringAlignment.Near }) + { + var size = this.g.MeasureString(text, font); + if (maxSize != null) + { + if (size.Width > maxSize.Value.Width) + { + size.Width = (float)maxSize.Value.Width; + } + + if (size.Height > maxSize.Value.Height) + { + size.Height = (float)maxSize.Value.Height; + } + } + + float dx = 0; + if (halign == HorizontalAlignment.Center) + { + dx = -size.Width / 2; + } + + if (halign == HorizontalAlignment.Right) + { + dx = -size.Width; + } + + float dy = 0; + sf.LineAlignment = StringAlignment.Near; + if (valign == VerticalAlignment.Middle) + { + dy = -size.Height / 2; + } + + if (valign == VerticalAlignment.Bottom) + { + dy = -size.Height; + } + + this.g.TranslateTransform((float)p.X, (float)p.Y); + if (Math.Abs(rotate) > double.Epsilon) + { + this.g.RotateTransform((float)rotate); + } + + this.g.TranslateTransform(dx, dy); + + var layoutRectangle = new RectangleF(0, 0, size.Width, size.Height); + this.g.DrawString(text, font, this.ToBrush(fill), layoutRectangle, sf); + + this.g.ResetTransform(); + } + } + } + + /// + /// The measure text. + /// + /// The text. + /// The font family. + /// The font size. + /// The font weight. + /// The size of the text. + public override OxySize MeasureText(string text, string fontFamily, double fontSize, double fontWeight) + { + if (text == null) + { + return OxySize.Empty; + } + + var fs = FontStyle.Regular; + if (fontWeight >= 700) + { + fs = FontStyle.Bold; + } + + using (var font = new Font(fontFamily, (float)fontSize * FontsizeFactor, fs)) + { + var size = this.g.MeasureString(text, font); + return new OxySize(size.Width, size.Height); + } + } + + /// + /// Converts a fill color to a System.Drawing.Brush. + /// + /// + /// The fill color. + /// + /// + /// The brush. + /// + private Brush ToBrush(OxyColor fill) + { + if (fill != null) + { + return new SolidBrush(this.ToColor(fill)); + } + + return null; + } + + /// + /// Converts a color to a System.Drawing.Color. + /// + /// + /// The color. + /// + /// + /// The System.Drawing.Color. + /// + private Color ToColor(OxyColor c) + { + return Color.FromArgb(c.A, c.R, c.G, c.B); + } + + /// + /// Converts a double array to a float array. + /// + /// + /// The a. + /// + /// + /// The float array. + /// + private float[] ToFloatArray(double[] a) + { + if (a == null) + { + return null; + } + + var r = new float[a.Length]; + for (int i = 0; i < a.Length; i++) + { + r[i] = (float)a[i]; + } + + return r; + } + + /// + /// Converts a list of point to an array of PointF. + /// + /// + /// The points. + /// + /// + /// An array of points. + /// + private PointF[] ToPoints(IList points) + { + if (points == null) + { + return null; + } + + var r = new PointF[points.Count()]; + int i = 0; + foreach (ScreenPoint p in points) + { + r[i++] = new PointF((float)p.X, (float)p.Y); + } + + return r; + } + + public override void CleanUp() + { + var imagesToRelease = imageCache.Keys.Where(i => !imagesInUse.Contains(i)); + foreach (var i in imagesToRelease) + { + var image = this.GetImage(i); + image.Dispose(); + imageCache.Remove(i); + } + + imagesInUse.Clear(); + } + + public override OxyImageInfo GetImageInfo(OxyImage source) + { + var image = this.GetImage(source); + return image == null ? null : new OxyImageInfo { Width = (uint)image.Width, Height = (uint)image.Height, DpiX = image.HorizontalResolution, DpiY = image.VerticalResolution }; + } + + public override void DrawImage(OxyImage source, uint srcX, uint srcY, uint srcWidth, uint srcHeight, double x, double y, double w, double h, double opacity, bool interpolate) + { + var image = this.GetImage(source); + if (image != null) + { + ImageAttributes ia = null; + if (opacity < 1) + { + var cm = new ColorMatrix + { + Matrix00 = 1f, + Matrix11 = 1f, + Matrix22 = 1f, + Matrix33 = 1f, + Matrix44 = (float)opacity + }; + + ia = new ImageAttributes(); + ia.SetColorMatrix(cm, ColorMatrixFlag.Default, ColorAdjustType.Bitmap); + } + + g.InterpolationMode = interpolate ? InterpolationMode.HighQualityBicubic : InterpolationMode.NearestNeighbor; + int sx = (int)Math.Round(x); + int sy = (int)Math.Round(y); + int sw = (int)Math.Round(x + w) - sx; + int sh = (int)Math.Round(y + h) - sy; + g.DrawImage(image, new Rectangle(sx, sy, sw, sh), srcX, srcY, srcWidth, srcHeight, GraphicsUnit.Pixel, ia); + } + } + + private HashSet imagesInUse = new HashSet(); + + private Dictionary imageCache = new Dictionary(); + + + private Image GetImage(OxyImage source) + { + if (source == null) + { + return null; + } + + if (!this.imagesInUse.Contains(source)) + { + this.imagesInUse.Add(source); + } + + Image src; + if (this.imageCache.TryGetValue(source, out src)) + { + return src; + } + + if (source != null) + { + Image btm; + using (var ms = new MemoryStream(source.GetData())) + { + btm = Image.FromStream(ms); + } + + this.imageCache.Add(source, btm); + return btm; + } + + return null; + } + + public override bool SetClip(OxyRect rect) + { + this.g.SetClip(rect.ToRect(false)); + return true; + } + + public override void ResetClip() + { + this.g.ResetClip(); + } + } +} \ No newline at end of file diff -r 88d699a65cc2 -r 5be8f2773237 External/OxyPlot/OxyPlot.WindowsForms/Helpers/ConverterExtensions.cs --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/External/OxyPlot/OxyPlot.WindowsForms/Helpers/ConverterExtensions.cs Sat Jun 08 16:53:22 2013 +0000 @@ -0,0 +1,251 @@ +// -------------------------------------------------------------------------------------------------------------------- +// +// The MIT License (MIT) +// +// Copyright (c) 2012 Oystein Bjorke +// +// Permission is hereby granted, free of charge, to any person obtaining a +// copy of this software and associated documentation files (the +// "Software"), to deal in the Software without restriction, including +// without limitation the rights to use, copy, modify, merge, publish, +// distribute, sublicense, and/or sell copies of the Software, and to +// permit persons to whom the Software is furnished to do so, subject to +// the following conditions: +// +// The above copyright notice and this permission notice shall be included +// in all copies or substantial portions of the Software. +// +// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS +// OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF +// MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. +// IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY +// CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, +// TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE +// SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. +// +// +// Extension method used to convert to/from Windows/Windows.Media classes. +// +// -------------------------------------------------------------------------------------------------------------------- +namespace OxyPlot.WindowsForms +{ + using System; + using System.Drawing; + using System.Windows.Forms; + + /// + /// Extension method used to convert to/from Windows/Windows.Media classes. + /// + public static class ConverterExtensions + { + /// + /// Calculate the distance between two points. + /// + /// + /// The first point. + /// + /// + /// The second point. + /// + /// + /// The distance. + /// + public static double DistanceTo(this Point p1, Point p2) + { + double dx = p1.X - p2.X; + double dy = p1.Y - p2.Y; + return Math.Sqrt((dx * dx) + (dy * dy)); + } + + /// + /// Converts a color to a Brush. + /// + /// + /// The color. + /// + /// + /// A SolidColorBrush. + /// + public static Brush ToBrush(this OxyColor c) + { + return new SolidBrush(c.ToColor()); + } + + /// + /// Converts an OxyColor to a Color. + /// + /// + /// The color. + /// + /// + /// A Color. + /// + public static Color ToColor(this OxyColor c) + { + return Color.FromArgb(c.A, c.R, c.G, c.B); + } + + /// + /// Converts a HorizontalAlignment to a HorizontalTextAlign. + /// + /// + /// The alignment. + /// + /// + /// A HorizontalTextAlign. + /// + public static OxyPlot.HorizontalAlignment ToHorizontalTextAlign(this HorizontalAlignment alignment) + { + switch (alignment) + { + case HorizontalAlignment.Center: + return OxyPlot.HorizontalAlignment.Center; + case HorizontalAlignment.Right: + return OxyPlot.HorizontalAlignment.Right; + default: + return OxyPlot.HorizontalAlignment.Left; + } + } + + /// + /// Converts a Color to an OxyColor. + /// + /// + /// The color. + /// + /// + /// An OxyColor. + /// + public static OxyColor ToOxyColor(this Color color) + { + return OxyColor.FromArgb(color.A, color.R, color.G, color.B); + } + + /// + /// Converts a nullable Color to an OxyColor. + /// + /// + /// The color. + /// + /// + /// An OxyColor. + /// + public static OxyColor ToOxyColor(this Color? color) + { + return color.HasValue ? color.Value.ToOxyColor() : null; + } + + /// + /// Converts a Brush to an OxyColor. + /// + /// + /// The brush. + /// + /// + /// An oxycolor. + /// + public static OxyColor ToOxyColor(this Brush brush) + { + var scb = brush as SolidBrush; + return scb != null ? scb.Color.ToOxyColor() : null; + } + + /// + /// Converts a Thickness to an OxyThickness. + /// + /// + /// An OxyPlot thickness. + /// + /// + /// Converts a ScreenPoint to a Point. + /// + /// + /// The screen point. + /// + /// + /// use pixel alignment conversion if set to true. + /// + /// + /// A point. + /// + public static Point ToPoint(this ScreenPoint pt, bool aliased) + { + // adding 0.5 to get pixel boundary alignment, seems to work + // http://weblogs.asp.net/mschwarz/archive/2008/01/04/silverlight-rectangles-paths-and-line-comparison.aspx + // http://www.wynapse.com/Silverlight/Tutor/Silverlight_Rectangles_Paths_And_Lines_Comparison.aspx + if (aliased) + { + return new Point((int)pt.X, (int)pt.Y); + } + + return new Point((int)Math.Round(pt.X), (int)Math.Round(pt.Y)); + } + + /// + /// Converts an OxyRect to a Rect. + /// + /// + /// The rectangle. + /// + /// + /// use pixel alignment if set to true. + /// + /// + /// A rect. + /// + public static Rectangle ToRect(this OxyRect r, bool aliased) + { + if (aliased) + { + var x = (int)r.Left; + var y = (int)r.Top; + var ri = (int)r.Right; + var bo = (int)r.Bottom; + return new Rectangle(x, y, ri - x, bo - y); + } + + return new Rectangle( + (int)Math.Round(r.Left), (int)Math.Round(r.Top), (int)Math.Round(r.Width), (int)Math.Round(r.Height)); + } + + /// + /// Converts a point to a ScreenPoint. + /// + /// + /// The point. + /// + /// + /// A screen point. + /// + public static ScreenPoint ToScreenPoint(this Point pt) + { + return new ScreenPoint(pt.X, pt.Y); + } + + /// + /// Converts a Point array to a ScreenPoint array. + /// + /// + /// The points. + /// + /// + /// A ScreenPoint array. + /// + public static ScreenPoint[] ToScreenPointArray(this Point[] points) + { + if (points == null) + { + return null; + } + + var pts = new ScreenPoint[points.Length]; + for (int i = 0; i < points.Length; i++) + { + pts[i] = points[i].ToScreenPoint(); + } + + return pts; + } + + } +} \ No newline at end of file diff -r 88d699a65cc2 -r 5be8f2773237 External/OxyPlot/OxyPlot.WindowsForms/NamespaceDoc.cs --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/External/OxyPlot/OxyPlot.WindowsForms/NamespaceDoc.cs Sat Jun 08 16:53:22 2013 +0000 @@ -0,0 +1,37 @@ +// -------------------------------------------------------------------------------------------------------------------- +// +// The MIT License (MIT) +// +// Copyright (c) 2012 Oystein Bjorke +// +// Permission is hereby granted, free of charge, to any person obtaining a +// copy of this software and associated documentation files (the +// "Software"), to deal in the Software without restriction, including +// without limitation the rights to use, copy, modify, merge, publish, +// distribute, sublicense, and/or sell copies of the Software, and to +// permit persons to whom the Software is furnished to do so, subject to +// the following conditions: +// +// The above copyright notice and this permission notice shall be included +// in all copies or substantial portions of the Software. +// +// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS +// OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF +// MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. +// IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY +// CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, +// TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE +// SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. +// +// -------------------------------------------------------------------------------------------------------------------- + +namespace OxyPlot.WindowsForms +{ + /// + /// The OxyPlot.WindowsForms namespace contains controls for Windows Forms and a bitmap exporter. + /// + [System.Runtime.CompilerServices.CompilerGenerated] + internal class NamespaceDoc + { + } +} \ No newline at end of file diff -r 88d699a65cc2 -r 5be8f2773237 External/OxyPlot/OxyPlot.WindowsForms/OxyPlot.WindowsForms.csproj --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/External/OxyPlot/OxyPlot.WindowsForms/OxyPlot.WindowsForms.csproj Sat Jun 08 16:53:22 2013 +0000 @@ -0,0 +1,79 @@ + + + + + Debug + AnyCPU + {D4554296-094E-4CAC-8EAE-44EB250666C6} + Library + Properties + OxyPlot.WindowsForms + OxyPlot.WindowsForms + v4.0 + Client + 512 + + + true + full + false + bin\Debug\NET40\ + obj\Debug\NET40\ + DEBUG;TRACE + prompt + 4 + + + pdbonly + true + ..\..\Output\NET40\ + obj\Release\NET40\ + TRACE + prompt + 4 + ..\..\Output\NET40\OxyPlot.WindowsForms.XML + + + true + + + OxyPlot.WindowsForms.snk + + + + + + + + + + Properties\GlobalAssemblyInfo.cs + + + + + + Component + + + + + + + + + + + {7a0b35c0-dd17-4964-8e9a-44d6cecdc692} + OxyPlot + + + + + \ No newline at end of file diff -r 88d699a65cc2 -r 5be8f2773237 External/OxyPlot/OxyPlot.WindowsForms/OxyPlot.WindowsForms.snk Binary file External/OxyPlot/OxyPlot.WindowsForms/OxyPlot.WindowsForms.snk has changed diff -r 88d699a65cc2 -r 5be8f2773237 External/OxyPlot/OxyPlot.WindowsForms/Plot.cs --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/External/OxyPlot/OxyPlot.WindowsForms/Plot.cs Sat Jun 08 16:53:22 2013 +0000 @@ -0,0 +1,897 @@ +// -------------------------------------------------------------------------------------------------------------------- +// +// The MIT License (MIT) +// +// Copyright (c) 2012 Oystein Bjorke +// +// Permission is hereby granted, free of charge, to any person obtaining a +// copy of this software and associated documentation files (the +// "Software"), to deal in the Software without restriction, including +// without limitation the rights to use, copy, modify, merge, publish, +// distribute, sublicense, and/or sell copies of the Software, and to +// permit persons to whom the Software is furnished to do so, subject to +// the following conditions: +// +// The above copyright notice and this permission notice shall be included +// in all copies or substantial portions of the Software. +// +// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS +// OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF +// MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. +// IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY +// CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, +// TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE +// SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. +// +// +// Represents a control that displays a plot. +// +// -------------------------------------------------------------------------------------------------------------------- +namespace OxyPlot.WindowsForms +{ + using System; + using System.ComponentModel; + using System.Diagnostics; + using System.Drawing; + using System.Runtime.InteropServices; + using System.Windows.Forms; + + using OxyPlot.Axes; + using OxyPlot.Series; + + /// + /// Represents a control that displays a plot. + /// + [Serializable] + public class Plot : Control, IPlotControl + { + /// + /// The category for the properties of this control. + /// + private const string OxyPlotCategory = "OxyPlot"; + + /// + /// The invalidate lock. + /// + private readonly object invalidateLock = new object(); + + /// + /// The model lock. + /// + private readonly object modelLock = new object(); + + /// + /// The rendering lock. + /// + private readonly object renderingLock = new object(); + + /// + /// The current model (holding a reference to this plot control). + /// + [NonSerialized] + private PlotModel currentModel; + + /// + /// The is model invalidated. + /// + private bool isModelInvalidated; + + /// + /// The model. + /// + private PlotModel model; + + /// + /// The mouse manipulator. + /// + [NonSerialized] + private ManipulatorBase mouseManipulator; + + /// + /// The update data flag. + /// + private bool updateDataFlag = true; + + /// + /// The zoom rectangle. + /// + private Rectangle zoomRectangle; + + /// + /// The render context. + /// + private GraphicsRenderContext renderContext; + + /// + /// Initializes a new instance of the class. + /// + public Plot() + { + this.renderContext = new GraphicsRenderContext(); + + // ReSharper disable DoNotCallOverridableMethodsInConstructor + this.DoubleBuffered = true; + // ReSharper restore DoNotCallOverridableMethodsInConstructor + this.KeyboardPanHorizontalStep = 0.1; + this.KeyboardPanVerticalStep = 0.1; + this.PanCursor = Cursors.Hand; + this.ZoomRectangleCursor = Cursors.SizeNWSE; + this.ZoomHorizontalCursor = Cursors.SizeWE; + this.ZoomVerticalCursor = Cursors.SizeNS; + } + + /// + /// Gets the actual model. + /// + /// The actual model. + public PlotModel ActualModel + { + get + { + return this.Model; + } + } + + /// + /// Gets or sets the keyboard pan horizontal step. + /// + /// The keyboard pan horizontal step. + [Category(OxyPlotCategory)] + public double KeyboardPanHorizontalStep { get; set; } + + /// + /// Gets or sets the keyboard pan vertical step. + /// + /// The keyboard pan vertical step. + [Category(OxyPlotCategory)] + public double KeyboardPanVerticalStep { get; set; } + + /// + /// Gets or sets the model. + /// + [Browsable(false)] + [DefaultValue(null)] + [Category(OxyPlotCategory)] + public PlotModel Model + { + get + { + return this.model; + } + + set + { + if (this.model != value) + { + this.model = value; + this.OnModelChanged(); + } + } + } + + /// + /// Gets or sets the pan cursor. + /// + [Category(OxyPlotCategory)] + public Cursor PanCursor { get; set; } + + /// + /// Gets or sets the horizontal zoom cursor. + /// + [Category(OxyPlotCategory)] + public Cursor ZoomHorizontalCursor { get; set; } + + /// + /// Gets or sets the rectangle zoom cursor. + /// + [Category(OxyPlotCategory)] + public Cursor ZoomRectangleCursor { get; set; } + + /// + /// Gets or sets vertical zoom cursor. + /// + [Category(OxyPlotCategory)] + public Cursor ZoomVerticalCursor { get; set; } + + /// + /// Get the axes from a point. + /// + /// + /// The point. + /// + /// + /// The x axis. + /// + /// + /// The y axis. + /// + public void GetAxesFromPoint(ScreenPoint pt, out Axis xaxis, out Axis yaxis) + { + if (this.Model == null) + { + xaxis = null; + yaxis = null; + return; + } + + this.Model.GetAxesFromPoint(pt, out xaxis, out yaxis); + } + + /// + /// Get the series from a point. + /// + /// + /// The point (screen coordinates). + /// + /// + /// The limit. + /// + /// + /// The series. + /// + public Series GetSeriesFromPoint(ScreenPoint pt, double limit) + { + if (this.Model == null) + { + return null; + } + + return this.Model.GetSeriesFromPoint(pt, limit); + } + + /// + /// The hide tracker. + /// + public void HideTracker() + { + } + + /// + /// The hide zoom rectangle. + /// + public void HideZoomRectangle() + { + this.zoomRectangle = Rectangle.Empty; + this.Invalidate(); + } + + /// + /// The invalidate plot. + /// + /// + /// The update data. + /// + public void InvalidatePlot(bool updateData) + { + lock (this.invalidateLock) + { + this.isModelInvalidated = true; + this.updateDataFlag = this.updateDataFlag || updateData; + } + + this.Invalidate(); + } + + /// + /// Called when the Model property has been changed. + /// + public void OnModelChanged() + { + lock (this.modelLock) + { + if (this.currentModel != null) + { + this.currentModel.AttachPlotControl(null); + } + + if (this.Model != null) + { + if (this.Model.PlotControl != null) + { + throw new InvalidOperationException( + "This PlotModel is already in use by some other plot control."); + } + + this.Model.AttachPlotControl(this); + this.currentModel = this.Model; + } + } + + this.InvalidatePlot(true); + } + + /// + /// The pan. + /// + /// + /// The axis. + /// + /// + /// The x 0. + /// + /// + /// The x 1. + /// + public void Pan(Axis axis, ScreenPoint x0, ScreenPoint x1) + { + axis.Pan(x0, x1); + this.InvalidatePlot(false); + } + + /// + /// Pans all axes. + /// + /// + /// The horizontal delta. + /// + /// + /// The vertical delta. + /// + public void PanAll(double deltax, double deltay) + { + foreach (var a in this.ActualModel.Axes) + { + a.Pan(a.IsHorizontal() ? deltax : deltay); + } + + this.InvalidatePlot(false); + } + + /// + /// The refresh plot. + /// + /// + /// The update data. + /// + public void RefreshPlot(bool updateData) + { + lock (this.invalidateLock) + { + this.isModelInvalidated = true; + this.updateDataFlag = this.updateDataFlag || updateData; + } + + this.Refresh(); + } + + /// + /// The reset. + /// + /// + /// The axis. + /// + public void Reset(Axis axis) + { + axis.Reset(); + this.InvalidatePlot(false); + } + + /// + /// Sets the cursor type. + /// + /// + /// The cursor type. + /// + public void SetCursorType(CursorType cursorType) + { + switch (cursorType) + { + case CursorType.Pan: + this.Cursor = this.PanCursor; + break; + case CursorType.ZoomRectangle: + this.Cursor = this.ZoomRectangleCursor; + break; + case CursorType.ZoomHorizontal: + this.Cursor = this.ZoomHorizontalCursor; + break; + case CursorType.ZoomVertical: + this.Cursor = this.ZoomVerticalCursor; + break; + default: + this.Cursor = Cursors.Arrow; + break; + } + } + + /// + /// The show tracker. + /// + /// + /// The data. + /// + public void ShowTracker(TrackerHitResult data) + { + // not implemented for WindowsForms + } + + /// + /// The show zoom rectangle. + /// + /// + /// The r. + /// + public void ShowZoomRectangle(OxyRect r) + { + this.zoomRectangle = new Rectangle((int)r.Left, (int)r.Top, (int)r.Width, (int)r.Height); + this.Invalidate(); + } + + /// + /// The zoom. + /// + /// + /// The axis. + /// + /// + /// The p 1. + /// + /// + /// The p 2. + /// + public void Zoom(Axis axis, double p1, double p2) + { + axis.Zoom(p1, p2); + this.InvalidatePlot(false); + } + + /// + /// The zoom all. + /// + public void ZoomAll() + { + foreach (var a in this.Model.Axes) + { + a.Reset(); + } + + this.InvalidatePlot(false); + } + + /// + /// Zooms all axes. + /// + /// + /// The delta. + /// + public void ZoomAllAxes(double delta) + { + foreach (var a in this.ActualModel.Axes) + { + this.ZoomAt(a, delta); + } + + this.RefreshPlot(false); + } + + /// + /// The zoom at. + /// + /// + /// The axis. + /// + /// + /// The factor. + /// + /// + /// The x. + /// + public void ZoomAt(Axis axis, double factor, double x = double.NaN) + { + if (double.IsNaN(x)) + { + double sx = (axis.Transform(axis.ActualMaximum) + axis.Transform(axis.ActualMinimum)) * 0.5; + x = axis.InverseTransform(sx); + } + + axis.ZoomAt(factor, x); + this.InvalidatePlot(false); + } + + /// + /// The on mouse down. + /// + /// + /// The e. + /// + protected override void OnMouseDown(MouseEventArgs e) + { + base.OnMouseDown(e); + + if (this.mouseManipulator != null) + { + return; + } + + this.Focus(); + this.Capture = true; + + if (this.ActualModel != null) + { + var args = this.CreateMouseEventArgs(e); + this.ActualModel.HandleMouseDown(this, args); + if (args.Handled) + { + return; + } + } + + this.mouseManipulator = this.GetManipulator(e); + + if (this.mouseManipulator != null) + { + this.mouseManipulator.Started(this.CreateManipulationEventArgs(e)); + } + } + + /// + /// The on mouse move. + /// + /// + /// The e. + /// + protected override void OnMouseMove(MouseEventArgs e) + { + base.OnMouseMove(e); + + if (this.ActualModel != null) + { + var args = this.CreateMouseEventArgs(e); + this.ActualModel.HandleMouseMove(this, args); + if (args.Handled) + { + return; + } + } + + if (this.mouseManipulator != null) + { + this.mouseManipulator.Delta(this.CreateManipulationEventArgs(e)); + } + } + + /// + /// Raises the event. + /// + /// + /// A that contains the event data. + /// + protected override void OnMouseUp(MouseEventArgs e) + { + base.OnMouseUp(e); + this.Capture = false; + + if (this.ActualModel != null) + { + var args = this.CreateMouseEventArgs(e); + this.ActualModel.HandleMouseUp(this, args); + if (args.Handled) + { + return; + } + } + + if (this.mouseManipulator != null) + { + this.mouseManipulator.Completed(this.CreateManipulationEventArgs(e)); + } + + this.mouseManipulator = null; + } + + /// + /// Raises the event. + /// + /// + /// A that contains the event data. + /// + protected override void OnMouseWheel(MouseEventArgs e) + { + base.OnMouseWheel(e); + bool isControlDown = ModifierKeys == Keys.Control; + var m = new ZoomStepManipulator(this, e.Delta * 0.001, isControlDown); + m.Started(new ManipulationEventArgs(e.Location.ToScreenPoint())); + } + + /// + /// Raises the event. + /// + /// + /// A that contains the event data. + /// + protected override void OnPaint(PaintEventArgs e) + { + base.OnPaint(e); + try + { + lock (this.invalidateLock) + { + if (this.isModelInvalidated) + { + if (this.model != null) + { + this.model.Update(this.updateDataFlag); + this.updateDataFlag = false; + } + + this.isModelInvalidated = false; + } + } + + lock (this.renderingLock) + { + this.renderContext.SetGraphicsTarget(e.Graphics); + if (this.model != null) + { + this.model.Render(this.renderContext, this.Width, this.Height); + } + + if (this.zoomRectangle != Rectangle.Empty) + { + using (var zoomBrush = new SolidBrush(Color.FromArgb(0x40, 0xFF, 0xFF, 0x00))) + using (var zoomPen = new Pen(Color.Black)) + { + zoomPen.DashPattern = new float[] { 3, 1 }; + e.Graphics.FillRectangle(zoomBrush, this.zoomRectangle); + e.Graphics.DrawRectangle(zoomPen, this.zoomRectangle); + } + } + } + } + catch (Exception paintException) + { + var trace = new StackTrace(paintException); + Debug.WriteLine(paintException); + Debug.WriteLine(trace); + using (var font = new Font("Arial", 10)) + { + e.Graphics.DrawString( + "OxyPlot paint exception: " + paintException.Message, font, Brushes.Red, 10, 10); + } + } + } + + /// + /// Raises the event. + /// + /// + /// A that contains the event data. + /// + protected override void OnPreviewKeyDown(PreviewKeyDownEventArgs e) + { + base.OnPreviewKeyDown(e); + if (e.KeyCode == Keys.A) + { + this.ZoomAll(); + } + + bool control = (e.Modifiers & Keys.Control) == Keys.Control; + bool alt = (e.Modifiers & Keys.Alt) == Keys.Alt; + + double deltax = 0; + double deltay = 0; + double zoom = 0; + switch (e.KeyCode) + { + case Keys.Up: + deltay = -1; + break; + case Keys.Down: + deltay = 1; + break; + case Keys.Left: + deltax = -1; + break; + case Keys.Right: + deltax = 1; + break; + case Keys.Add: + case Keys.Oemplus: + case Keys.PageUp: + zoom = 1; + break; + case Keys.Subtract: + case Keys.OemMinus: + case Keys.PageDown: + zoom = -1; + break; + } + + if ((deltax * deltax) + (deltay * deltay) > 0) + { + deltax = deltax * this.ActualModel.PlotArea.Width * this.KeyboardPanHorizontalStep; + deltay = deltay * this.ActualModel.PlotArea.Height * this.KeyboardPanVerticalStep; + + // small steps if the user is pressing control + if (control) + { + deltax *= 0.2; + deltay *= 0.2; + } + + this.PanAll(deltax, deltay); + + // e.Handled = true; + } + + if (Math.Abs(zoom) > 1e-8) + { + if (control) + { + zoom *= 0.2; + } + + this.ZoomAllAxes(1 + (zoom * 0.12)); + + // e.Handled = true; + } + + if (control && alt && this.ActualModel != null) + { + switch (e.KeyCode) + { + case Keys.R: + this.SetClipboardText(this.ActualModel.CreateTextReport()); + break; + case Keys.C: + this.SetClipboardText(this.ActualModel.ToCode()); + break; + case Keys.X: + + // this.SetClipboardText(this.ActualModel.ToXml()); + break; + } + } + } + + /// + /// Raises the event. + /// + /// + /// An that contains the event data. + /// + protected override void OnResize(EventArgs e) + { + base.OnResize(e); + this.InvalidatePlot(false); + } + + /// + /// Converts the changed button. + /// + /// + /// The instance containing the event data. + /// + /// + /// The mouse button. + /// + private static OxyMouseButton ConvertChangedButton(MouseEventArgs e) + { + switch (e.Button) + { + case MouseButtons.Left: + return OxyMouseButton.Left; + case MouseButtons.Middle: + return OxyMouseButton.Middle; + case MouseButtons.Right: + return OxyMouseButton.Right; + case MouseButtons.XButton1: + return OxyMouseButton.XButton1; + case MouseButtons.XButton2: + return OxyMouseButton.XButton2; + } + + return OxyMouseButton.Left; + } + + /// + /// Creates the mouse event arguments. + /// + /// + /// The instance containing the event data. + /// + /// + /// Mouse event arguments. + /// + private OxyMouseEventArgs CreateMouseEventArgs(MouseEventArgs e) + { + return new OxyMouseEventArgs + { + ChangedButton = ConvertChangedButton(e), + Position = new ScreenPoint(e.Location.X, e.Location.Y), + IsShiftDown = (ModifierKeys & Keys.Shift) == Keys.Shift, + IsControlDown = (ModifierKeys & Keys.Control) == Keys.Control, + IsAltDown = (ModifierKeys & Keys.Alt) == Keys.Alt, + }; + } + + /// + /// Creates the manipulation event args. + /// + /// + /// The MouseEventArgs instance containing the event data. + /// + /// + /// A manipulation event args object. + /// + private ManipulationEventArgs CreateManipulationEventArgs(MouseEventArgs e) + { + return new ManipulationEventArgs(e.Location.ToScreenPoint()); + } + + /// + /// Gets the manipulator for the current mouse button and modifier keys. + /// + /// + /// The event args. + /// + /// + /// A manipulator or null if no gesture was recognized. + /// + private ManipulatorBase GetManipulator(MouseEventArgs e) + { + bool control = (ModifierKeys & Keys.Control) == Keys.Control; + bool shift = (ModifierKeys & Keys.Shift) == Keys.Shift; + bool alt = (ModifierKeys & Keys.Alt) == Keys.Alt; + + bool lmb = e.Button == MouseButtons.Left; + bool rmb = e.Button == MouseButtons.Right; + bool mmb = e.Button == MouseButtons.Middle; + bool xb1 = e.Button == MouseButtons.XButton1; + bool xb2 = e.Button == MouseButtons.XButton2; + + // MMB / control RMB / control+alt LMB + if (mmb || (control && rmb) || (control && alt && lmb)) + { + if (e.Clicks == 2) + { + return new ResetManipulator(this); + } + + return new ZoomRectangleManipulator(this); + } + + // Right mouse button / alt+left mouse button + if (rmb || (lmb && alt)) + { + return new PanManipulator(this); + } + + // Left mouse button + if (lmb) + { + return new TrackerManipulator(this) { Snap = !control, PointsOnly = shift }; + } + + // XButtons are zoom-stepping + if (xb1 || xb2) + { + double d = xb1 ? 0.05 : -0.05; + return new ZoomStepManipulator(this, d, control); + } + + return null; + } + + /// + /// The set clipboard text. + /// + /// + /// The text. + /// + private void SetClipboardText(string text) + { + try + { + // todo: can't get the following solution to work + // http://stackoverflow.com/questions/5707990/requested-clipboard-operation-did-not-succeed + Clipboard.SetText(text); + } + catch (ExternalException ee) + { + // Requested Clipboard operation did not succeed. + MessageBox.Show(this, ee.Message, "OxyPlot"); + } + } + } +} \ No newline at end of file diff -r 88d699a65cc2 -r 5be8f2773237 External/OxyPlot/OxyPlot.WindowsForms/PlotControl.cs --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/External/OxyPlot/OxyPlot.WindowsForms/PlotControl.cs Sat Jun 08 16:53:22 2013 +0000 @@ -0,0 +1,237 @@ +// -------------------------------------------------------------------------------------------------------------------- +// +// The MIT License (MIT) +// +// Copyright (c) 2012 Oystein Bjorke +// +// Permission is hereby granted, free of charge, to any person obtaining a +// copy of this software and associated documentation files (the +// "Software"), to deal in the Software without restriction, including +// without limitation the rights to use, copy, modify, merge, publish, +// distribute, sublicense, and/or sell copies of the Software, and to +// permit persons to whom the Software is furnished to do so, subject to +// the following conditions: +// +// The above copyright notice and this permission notice shall be included +// in all copies or substantial portions of the Software. +// +// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS +// OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF +// MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. +// IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY +// CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, +// TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE +// SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. +// +// -------------------------------------------------------------------------------------------------------------------- +using System; +using System.Collections.Generic; +using System.ComponentModel; +using System.Drawing; +using System.Windows.Forms; +using OxyPlot; + +namespace Oxyplot.WindowsForms +{ + public class PlotControl : Control, IPlotControl + { + public List MouseActions { get; private set; } + + private readonly PanAction panAction; + private readonly SliderAction sliderAction; + private readonly ZoomAction zoomAction; + private Rectangle zoomRectangle; + + public PlotControl() + { + // InitializeComponent(); + DoubleBuffered = true; + Model = new PlotModel(); + + panAction = new PanAction(this); + zoomAction = new ZoomAction(this); + sliderAction = new SliderAction(this); + + MouseActions = new List(); + MouseActions.Add(panAction); + MouseActions.Add(zoomAction); + MouseActions.Add(sliderAction); + } + + private PlotModel model; + + [Browsable(false), DefaultValue(null)] + public PlotModel Model + { + get { return model; } + set + { + model = value; + Refresh(); + } + } + + public override void Refresh() + { + if (model != null) + model.UpdateData(); + base.Refresh(); + } + + protected override void OnResize(EventArgs e) + { + base.OnResize(e); + Invalidate(); + } + + protected override void OnPaint(PaintEventArgs e) + { + base.OnPaint(e); + + var rc = new GraphicsRenderContext(this, e.Graphics, e.ClipRectangle); + if (model != null) + model.Render(rc); + if (zoomRectangle != Rectangle.Empty) + { + using (var zoomBrush = new SolidBrush(Color.FromArgb(0x40, 0xFF, 0xFF, 0x00))) + using (var zoomPen = new Pen(Color.Black)) + { + zoomPen.DashPattern = new float[] { 3, 1 }; + e.Graphics.FillRectangle(zoomBrush, zoomRectangle); + e.Graphics.DrawRectangle(zoomPen, zoomRectangle); + } + } + } + + protected override void OnKeyDown(KeyEventArgs e) + { + base.OnKeyDown(e); + if (e.KeyCode == Keys.A) + { + ZoomAll(); + } + } + + public void ZoomAll() + { + foreach (var a in Model.Axes) + a.Reset(); + Refresh(); + } + + protected override void OnMouseDown(MouseEventArgs e) + { + base.OnMouseDown(e); + + Focus(); + Capture = true; + + bool control = Control.ModifierKeys == Keys.Control; + bool shift = Control.ModifierKeys == Keys.Shift; + + var button = OxyMouseButton.Left; + if (e.Button == MouseButtons.Middle) + button = OxyMouseButton.Middle; + if (e.Button == MouseButtons.Right) + button = OxyMouseButton.Right; + if (e.Button == MouseButtons.XButton1) + button = OxyMouseButton.XButton1; + if (e.Button == MouseButtons.XButton2) + button = OxyMouseButton.XButton2; + + var p = new ScreenPoint(e.X, e.Y); + foreach (var a in MouseActions) + a.OnMouseDown(p, button, e.Clicks, control, shift); + } + + protected override void OnMouseMove(MouseEventArgs e) + { + base.OnMouseMove(e); + bool control = Control.ModifierKeys == Keys.Control; + bool shift = Control.ModifierKeys == Keys.Shift; + var p = new ScreenPoint(e.X, e.Y); + foreach (var a in MouseActions) + a.OnMouseMove(p, control, shift); + } + + protected override void OnMouseUp(MouseEventArgs e) + { + base.OnMouseUp(e); + foreach (var a in MouseActions) + a.OnMouseUp(); + Capture = false; + } + + protected override void OnMouseWheel(MouseEventArgs e) + { + base.OnMouseWheel(e); + bool control = Control.ModifierKeys == Keys.Control; + bool shift = Control.ModifierKeys == Keys.Shift; + var p = new ScreenPoint(e.X, e.Y); + foreach (var a in MouseActions) + a.OnMouseWheel(p, e.Delta, control, shift); + } + + public void GetAxesFromPoint(ScreenPoint pt, out AxisBase xaxis, out AxisBase yaxis) + { + Model.GetAxesFromPoint(pt, out xaxis, out yaxis); + } + + public DataSeries GetSeriesFromPoint(ScreenPoint pt, double limit) + { + return Model.GetSeriesFromPoint(pt, limit); + } + + public void Refresh(bool refreshData) + { + if (refreshData) + Model.UpdateData(); + Invalidate(); + } + + public void Pan(AxisBase axis, double dx) + { + axis.Pan(dx); + } + + public void Reset(AxisBase axis) + { + axis.Reset(); + } + + public void Zoom(AxisBase axis, double p1, double p2) + { + axis.Zoom(p1, p2); + } + + public void ZoomAt(AxisBase axis, double factor, double x) + { + axis.ZoomAt(factor, x); + } + + public OxyRect GetPlotArea() + { + return Model.PlotArea; + } + + public void ShowSlider(DataSeries s, DataPoint dp) + { + } + + public void HideSlider() + { + } + + public void ShowZoomRectangle(OxyRect r) + { + zoomRectangle = new Rectangle((int)r.Left, (int)r.Top, (int)r.Width, (int)r.Height); + Invalidate(); + } + + public void HideZoomRectangle() + { + zoomRectangle = Rectangle.Empty; + Invalidate(); + } + } +} \ No newline at end of file diff -r 88d699a65cc2 -r 5be8f2773237 External/OxyPlot/OxyPlot.WindowsForms/PngExporter.cs --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/External/OxyPlot/OxyPlot.WindowsForms/PngExporter.cs Sat Jun 08 16:53:22 2013 +0000 @@ -0,0 +1,81 @@ +// -------------------------------------------------------------------------------------------------------------------- +// +// The MIT License (MIT) +// +// Copyright (c) 2012 Oystein Bjorke +// +// Permission is hereby granted, free of charge, to any person obtaining a +// copy of this software and associated documentation files (the +// "Software"), to deal in the Software without restriction, including +// without limitation the rights to use, copy, modify, merge, publish, +// distribute, sublicense, and/or sell copies of the Software, and to +// permit persons to whom the Software is furnished to do so, subject to +// the following conditions: +// +// The above copyright notice and this permission notice shall be included +// in all copies or substantial portions of the Software. +// +// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS +// OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF +// MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. +// IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY +// CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, +// TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE +// SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. +// +// +// The png exporter. +// +// -------------------------------------------------------------------------------------------------------------------- +namespace OxyPlot.WindowsForms +{ + using System.Drawing; + using System.Drawing.Imaging; + + using OxyPlot.WindowsForms; + + /// + /// The png exporter. + /// + public static class PngExporter + { + /// + /// The export. + /// + /// + /// The model. + /// + /// + /// The file name. + /// + /// + /// The width. + /// + /// + /// The height. + /// + /// + /// The background. + /// + public static void Export(PlotModel model, string fileName, int width, int height, Brush background = null) + { + using (var bm = new Bitmap(width, height)) + { + using (Graphics g = Graphics.FromImage(bm)) + { + if (background != null) + { + g.FillRectangle(background, 0, 0, width, height); + } + + var rc = new GraphicsRenderContext { RendersToScreen = false }; + rc.SetGraphicsTarget(g); + model.Update(); + model.Render(rc, width, height); + bm.Save(fileName, ImageFormat.Png); + } + } + } + + } +} \ No newline at end of file diff -r 88d699a65cc2 -r 5be8f2773237 External/OxyPlot/OxyPlot.WindowsForms/Properties/AssemblyInfo.cs --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/External/OxyPlot/OxyPlot.WindowsForms/Properties/AssemblyInfo.cs Sat Jun 08 16:53:22 2013 +0000 @@ -0,0 +1,10 @@ +//----------------------------------------------------------------------- +// +// http://oxyplot.codeplex.com, license: MIT +// +//----------------------------------------------------------------------- + +using System.Reflection; + +[assembly: AssemblyTitle("OxyPlot for Windows Forms")] +[assembly: AssemblyDescription("OxyPlot controls for Windows Forms.")] \ No newline at end of file diff -r 88d699a65cc2 -r 5be8f2773237 External/OxyPlot/OxyPlot.sln --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/External/OxyPlot/OxyPlot.sln Sat Jun 08 16:53:22 2013 +0000 @@ -0,0 +1,26 @@ + +Microsoft Visual Studio Solution File, Format Version 11.00 +# Visual Studio 2010 +Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "OxyPlot", "OxyPlot\OxyPlot.csproj", "{BCC43E58-E473-403E-A84D-63FEDC723040}" +EndProject +Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "OxyPlot.WindowsForms", "OxyPlot.WindowsForms\OxyPlot.WindowsForms.csproj", "{D4554296-094E-4CAC-8EAE-44EB250666C6}" +EndProject +Global + GlobalSection(SolutionConfigurationPlatforms) = preSolution + Debug|Any CPU = Debug|Any CPU + Release|Any CPU = Release|Any CPU + EndGlobalSection + GlobalSection(ProjectConfigurationPlatforms) = postSolution + {BCC43E58-E473-403E-A84D-63FEDC723040}.Debug|Any CPU.ActiveCfg = Debug|Any CPU + {BCC43E58-E473-403E-A84D-63FEDC723040}.Debug|Any CPU.Build.0 = Debug|Any CPU + {BCC43E58-E473-403E-A84D-63FEDC723040}.Release|Any CPU.ActiveCfg = Release|Any CPU + {BCC43E58-E473-403E-A84D-63FEDC723040}.Release|Any CPU.Build.0 = Release|Any CPU + {D4554296-094E-4CAC-8EAE-44EB250666C6}.Debug|Any CPU.ActiveCfg = Debug|Any CPU + {D4554296-094E-4CAC-8EAE-44EB250666C6}.Debug|Any CPU.Build.0 = Debug|Any CPU + {D4554296-094E-4CAC-8EAE-44EB250666C6}.Release|Any CPU.ActiveCfg = Release|Any CPU + {D4554296-094E-4CAC-8EAE-44EB250666C6}.Release|Any CPU.Build.0 = Release|Any CPU + EndGlobalSection + GlobalSection(SolutionProperties) = preSolution + HideSolutionNode = FALSE + EndGlobalSection +EndGlobal diff -r 88d699a65cc2 -r 5be8f2773237 External/OxyPlot/OxyPlot/Annotations/Annotation.cs --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/External/OxyPlot/OxyPlot/Annotations/Annotation.cs Sat Jun 08 16:53:22 2013 +0000 @@ -0,0 +1,181 @@ +// -------------------------------------------------------------------------------------------------------------------- +// +// The MIT License (MIT) +// +// Copyright (c) 2012 Oystein Bjorke +// +// Permission is hereby granted, free of charge, to any person obtaining a +// copy of this software and associated documentation files (the +// "Software"), to deal in the Software without restriction, including +// without limitation the rights to use, copy, modify, merge, publish, +// distribute, sublicense, and/or sell copies of the Software, and to +// permit persons to whom the Software is furnished to do so, subject to +// the following conditions: +// +// The above copyright notice and this permission notice shall be included +// in all copies or substantial portions of the Software. +// +// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS +// OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF +// MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. +// IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY +// CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, +// TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE +// SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. +// +// +// Annotation base class. +// +// -------------------------------------------------------------------------------------------------------------------- +namespace OxyPlot.Annotations +{ + using System; + using System.Globalization; + + using OxyPlot.Axes; + + /// + /// Provides an abstract base class for annotations. + /// + public abstract class Annotation : UIPlotElement + { + /// + /// Gets the actual culture. + /// + /// + /// The culture is defined in the parent PlotModel. + /// + public CultureInfo ActualCulture + { + get + { + return this.PlotModel != null ? this.PlotModel.ActualCulture : CultureInfo.CurrentCulture; + } + } + + /// + /// Gets or sets the layer. + /// + public AnnotationLayer Layer { get; set; } + + /// + /// Gets or sets the X axis. + /// + /// The X axis. + public Axis XAxis { get; set; } + + /// + /// Gets or sets the X axis key. + /// + /// The X axis key. + public string XAxisKey { get; set; } + + /// + /// Gets or sets the Y axis. + /// + /// The Y axis. + public Axis YAxis { get; set; } + + /// + /// Gets or sets the Y axis key. + /// + /// The Y axis key. + public string YAxisKey { get; set; } + + /// + /// Ensures that the annotation axes are set. + /// + public void EnsureAxes() + { + this.XAxis = this.PlotModel.GetAxisOrDefault(this.XAxisKey, this.PlotModel.DefaultXAxis); + this.YAxis = this.PlotModel.GetAxisOrDefault(this.YAxisKey, this.PlotModel.DefaultYAxis); + } + + /// + /// Renders the annotation on the specified context. + /// + /// + /// The render context. + /// + /// + /// The model. + /// + public virtual void Render(IRenderContext rc, PlotModel model) + { + } + + /// + /// Tests if the plot element is hit by the specified point. + /// + /// The point. + /// The tolerance. + /// + /// A hit test result. + /// + protected internal override HitTestResult HitTest(ScreenPoint point, double tolerance) + { + return null; + } + + /// + /// Transforms the specified coordinates to a screen point. + /// + /// + /// The x coordinate. + /// + /// + /// The y coordinate. + /// + /// + /// A screen point. + /// + public ScreenPoint Transform(double x, double y) + { + return this.XAxis.Transform(x, y, this.YAxis); + } + + /// + /// Transforms the specified data point to a screen point. + /// + /// + /// The point. + /// + /// + /// A screen point. + /// + public ScreenPoint Transform(IDataPoint p) + { + return this.XAxis.Transform(p.X, p.Y, this.YAxis); + } + + /// + /// Transforms the specified screen position to a data point. + /// + /// + /// The position. + /// + /// + /// A data point + /// + public DataPoint InverseTransform(ScreenPoint position) + { + return Axis.InverseTransform(position, this.XAxis, this.YAxis); + } + + /// + /// Gets the clipping rectangle. + /// + /// + /// The clipping rectangle. + /// + protected OxyRect GetClippingRect() + { + double minX = Math.Min(this.XAxis.ScreenMin.X, this.XAxis.ScreenMax.X); + double minY = Math.Min(this.YAxis.ScreenMin.Y, this.YAxis.ScreenMax.Y); + double maxX = Math.Max(this.XAxis.ScreenMin.X, this.XAxis.ScreenMax.X); + double maxY = Math.Max(this.YAxis.ScreenMin.Y, this.YAxis.ScreenMax.Y); + + return new OxyRect(minX, minY, maxX - minX, maxY - minY); + } + } +} \ No newline at end of file diff -r 88d699a65cc2 -r 5be8f2773237 External/OxyPlot/OxyPlot/Annotations/AnnotationLayer.cs --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/External/OxyPlot/OxyPlot/Annotations/AnnotationLayer.cs Sat Jun 08 16:53:22 2013 +0000 @@ -0,0 +1,52 @@ +// -------------------------------------------------------------------------------------------------------------------- +// +// The MIT License (MIT) +// +// Copyright (c) 2012 Oystein Bjorke +// +// Permission is hereby granted, free of charge, to any person obtaining a +// copy of this software and associated documentation files (the +// "Software"), to deal in the Software without restriction, including +// without limitation the rights to use, copy, modify, merge, publish, +// distribute, sublicense, and/or sell copies of the Software, and to +// permit persons to whom the Software is furnished to do so, subject to +// the following conditions: +// +// The above copyright notice and this permission notice shall be included +// in all copies or substantial portions of the Software. +// +// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS +// OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF +// MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. +// IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY +// CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, +// TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE +// SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. +// +// +// The annotation layer. +// +// -------------------------------------------------------------------------------------------------------------------- +namespace OxyPlot.Annotations +{ + /// + /// Specifies the layer for an . + /// + public enum AnnotationLayer + { + /// + /// Render the annotation below the gridlines of the axes. + /// + BelowAxes, + + /// + /// Render the annotation below the series. + /// + BelowSeries, + + /// + /// Render the annotation above the series. + /// + AboveSeries + } +} \ No newline at end of file diff -r 88d699a65cc2 -r 5be8f2773237 External/OxyPlot/OxyPlot/Annotations/ArrowAnnotation.cs --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/External/OxyPlot/OxyPlot/Annotations/ArrowAnnotation.cs Sat Jun 08 16:53:22 2013 +0000 @@ -0,0 +1,228 @@ +// -------------------------------------------------------------------------------------------------------------------- +// +// The MIT License (MIT) +// +// Copyright (c) 2012 Oystein Bjorke +// +// Permission is hereby granted, free of charge, to any person obtaining a +// copy of this software and associated documentation files (the +// "Software"), to deal in the Software without restriction, including +// without limitation the rights to use, copy, modify, merge, publish, +// distribute, sublicense, and/or sell copies of the Software, and to +// permit persons to whom the Software is furnished to do so, subject to +// the following conditions: +// +// The above copyright notice and this permission notice shall be included +// in all copies or substantial portions of the Software. +// +// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS +// OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF +// MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. +// IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY +// CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, +// TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE +// SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. +// +// +// Represents an arrow annotation. +// +// -------------------------------------------------------------------------------------------------------------------- +namespace OxyPlot.Annotations +{ + /// + /// Represents an arrow annotation. + /// + public class ArrowAnnotation : TextualAnnotation + { + /// + /// The end point in screen coordinates. + /// + private ScreenPoint screenEndPoint; + + /// + /// The start point in screen coordinates. + /// + private ScreenPoint screenStartPoint; + + /// + /// Initializes a new instance of the class. + /// + public ArrowAnnotation() + { + this.HeadLength = 10; + this.HeadWidth = 3; + this.Color = OxyColors.Blue; + this.StrokeThickness = 2; + this.LineStyle = LineStyle.Solid; + this.LineJoin = OxyPenLineJoin.Miter; + } + + /// + /// Gets or sets the arrow direction. + /// + /// + /// Setting this property overrides the StartPoint property. + /// + public ScreenVector ArrowDirection { get; set; } + + /// + /// Gets or sets the color of the arrow. + /// + public OxyColor Color { get; set; } + + /// + /// Gets or sets the end point. + /// + public DataPoint EndPoint { get; set; } + + /// + /// Gets or sets the length of the head (relative to the stroke thickness) (the default value is 10). + /// + /// The length of the head. + public double HeadLength { get; set; } + + /// + /// Gets or sets the width of the head (relative to the stroke thickness) (the default value is 3). + /// + /// The width of the head. + public double HeadWidth { get; set; } + + /// + /// Gets or sets the line join type. + /// + /// The line join type. + public OxyPenLineJoin LineJoin { get; set; } + + /// + /// Gets or sets the line style. + /// + /// The line style. + public LineStyle LineStyle { get; set; } + + /// + /// Gets or sets the start point. + /// + /// + /// This property is overridden by the ArrowDirection property, if set. + /// + public DataPoint StartPoint { get; set; } + + /// + /// Gets or sets the stroke thickness (the default value is 2). + /// + /// The stroke thickness. + public double StrokeThickness { get; set; } + + /// + /// Gets or sets the 'veeness' of the arrow head (relative to thickness) (the default value is 0). + /// + /// The 'veeness'. + public double Veeness { get; set; } + + /// + /// Renders the arrow annotation. + /// + /// + /// The render context. + /// + /// + /// The plot model. + /// + public override void Render(IRenderContext rc, PlotModel model) + { + base.Render(rc, model); + + this.screenEndPoint = this.Transform(this.EndPoint); + + if (!this.ArrowDirection.x.IsZero() || !this.ArrowDirection.y.IsZero()) + { + this.screenStartPoint = this.screenEndPoint - this.ArrowDirection; + } + else + { + this.screenStartPoint = this.Transform(this.StartPoint); + } + + var d = this.screenEndPoint - this.screenStartPoint; + d.Normalize(); + var n = new ScreenVector(d.Y, -d.X); + + var p1 = this.screenEndPoint - (d * this.HeadLength * this.StrokeThickness); + var p2 = p1 + (n * this.HeadWidth * this.StrokeThickness); + var p3 = p1 - (n * this.HeadWidth * this.StrokeThickness); + var p4 = p1 + (d * this.Veeness * this.StrokeThickness); + + OxyRect clippingRect = this.GetClippingRect(); + const double MinimumSegmentLength = 4; + + rc.DrawClippedLine( + new[] { this.screenStartPoint, p4 }, + clippingRect, + MinimumSegmentLength * MinimumSegmentLength, + this.GetSelectableColor(this.Color), + this.StrokeThickness, + this.LineStyle, + this.LineJoin, + false); + + rc.DrawClippedPolygon( + new[] { p3, this.screenEndPoint, p2, p4 }, + clippingRect, + MinimumSegmentLength * MinimumSegmentLength, + this.GetSelectableColor(this.Color), + null); + + if (!string.IsNullOrEmpty(this.Text)) + { + var ha = d.X < 0 ? HorizontalAlignment.Left : HorizontalAlignment.Right; + var va = d.Y < 0 ? VerticalAlignment.Top : VerticalAlignment.Bottom; + + var textPoint = this.screenStartPoint; + rc.DrawClippedText( + clippingRect, + textPoint, + this.Text, + this.ActualTextColor, + this.ActualFont, + this.ActualFontSize, + this.ActualFontWeight, + 0, + ha, + va); + } + } + + /// + /// Tests if the plot element is hit by the specified point. + /// + /// + /// The point. + /// + /// + /// The tolerance. + /// + /// + /// A hit test result. + /// + protected internal override HitTestResult HitTest(ScreenPoint point, double tolerance) + { + if ((point - this.screenStartPoint).Length < tolerance) + { + return new HitTestResult(this.screenStartPoint, null, 1); + } + + if ((point - this.screenEndPoint).Length < tolerance) + { + return new HitTestResult(this.screenEndPoint, null, 2); + } + + var p = ScreenPointHelper.FindPointOnLine(point, this.screenStartPoint, this.screenEndPoint); + if ((p - point).Length < tolerance) + { + return new HitTestResult(p); + } + + return null; + } + } +} \ No newline at end of file diff -r 88d699a65cc2 -r 5be8f2773237 External/OxyPlot/OxyPlot/Annotations/EllipseAnnotation.cs --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/External/OxyPlot/OxyPlot/Annotations/EllipseAnnotation.cs Sat Jun 08 16:53:22 2013 +0000 @@ -0,0 +1,152 @@ +// -------------------------------------------------------------------------------------------------------------------- +// +// The MIT License (MIT) +// +// Copyright (c) 2012 Oystein Bjorke +// +// Permission is hereby granted, free of charge, to any person obtaining a +// copy of this software and associated documentation files (the +// "Software"), to deal in the Software without restriction, including +// without limitation the rights to use, copy, modify, merge, publish, +// distribute, sublicense, and/or sell copies of the Software, and to +// permit persons to whom the Software is furnished to do so, subject to +// the following conditions: +// +// The above copyright notice and this permission notice shall be included +// in all copies or substantial portions of the Software. +// +// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS +// OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF +// MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. +// IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY +// CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, +// TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE +// SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. +// +// +// Represents a rectangle annotation. +// +// -------------------------------------------------------------------------------------------------------------------- +namespace OxyPlot.Annotations +{ + /// + /// Represents an ellipse annotation. + /// + public class EllipseAnnotation : TextualAnnotation + { + /// + /// The rectangle transformed to screen coordinates. + /// + private OxyRect screenRectangle; + + /// + /// Initializes a new instance of the class. + /// + public EllipseAnnotation() + { + this.Stroke = OxyColors.Black; + this.Fill = OxyColors.LightBlue; + } + + /// + /// Gets or sets the fill color. + /// + /// The fill. + public OxyColor Fill { get; set; } + + /// + /// Gets or sets the stroke color. + /// + public OxyColor Stroke { get; set; } + + /// + /// Gets or sets the stroke thickness. + /// + public double StrokeThickness { get; set; } + + /// + /// Gets or sets the x-coordinate of the center. + /// + public double X { get; set; } + + /// + /// Gets or sets the y-coordinate of the center. + /// + public double Y { get; set; } + + /// + /// Gets or sets the width of the ellipse. + /// + public double Width { get; set; } + + /// + /// Gets or sets the height of the ellipse. + /// + public double Height { get; set; } + + /// + /// Gets or sets the text rotation (degrees). + /// + /// The text rotation in degrees. + public double TextRotation { get; set; } + + /// + /// Renders the polygon annotation. + /// + /// + /// The render context. + /// + /// + /// The plot model. + /// + public override void Render(IRenderContext rc, PlotModel model) + { + base.Render(rc, model); + + this.screenRectangle = OxyRect.Create(this.Transform(this.X - (Width / 2), Y - (Height / 2)), this.Transform(X + (Width / 2), Y + (Height / 2))); + + // clip to the area defined by the axes + var clipping = this.GetClippingRect(); + + rc.DrawClippedEllipse(clipping, this.screenRectangle, this.Fill, this.Stroke, this.StrokeThickness); + + if (!string.IsNullOrEmpty(this.Text)) + { + var textPosition = this.screenRectangle.Center; + rc.DrawClippedText( + clipping, + textPosition, + this.Text, + this.ActualTextColor, + this.ActualFont, + this.ActualFontSize, + this.ActualFontWeight, + this.TextRotation, + HorizontalAlignment.Center, + VerticalAlignment.Middle); + } + } + + /// + /// Tests if the plot element is hit by the specified point. + /// + /// + /// The point. + /// + /// + /// The tolerance. + /// + /// + /// A hit test result. + /// + protected internal override HitTestResult HitTest(ScreenPoint point, double tolerance) + { + if (this.screenRectangle.Contains(point)) + { + return new HitTestResult(point); + } + + return null; + } + } +} \ No newline at end of file diff -r 88d699a65cc2 -r 5be8f2773237 External/OxyPlot/OxyPlot/Annotations/ImageAnnotation.cs --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/External/OxyPlot/OxyPlot/Annotations/ImageAnnotation.cs Sat Jun 08 16:53:22 2013 +0000 @@ -0,0 +1,451 @@ +// -------------------------------------------------------------------------------------------------------------------- +// +// The MIT License (MIT) +// +// Copyright (c) 2012 Oystein Bjorke +// +// Permission is hereby granted, free of charge, to any person obtaining a +// copy of this software and associated documentation files (the +// "Software"), to deal in the Software without restriction, including +// without limitation the rights to use, copy, modify, merge, publish, +// distribute, sublicense, and/or sell copies of the Software, and to +// permit persons to whom the Software is furnished to do so, subject to +// the following conditions: +// +// The above copyright notice and this permission notice shall be included +// in all copies or substantial portions of the Software. +// +// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS +// OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF +// MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. +// IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY +// CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, +// TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE +// SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. +// +// +// Represents a text object annotation. +// +// -------------------------------------------------------------------------------------------------------------------- +namespace OxyPlot.Annotations +{ + /// + /// Represents a text annotation. + /// + public class ImageAnnotation : Annotation + { + /// + /// The actual bounds of the rendered image. + /// + private OxyRect actualBounds; + + /// + /// Initializes a new instance of the class. + /// + public ImageAnnotation() + { + this.X = new PlotLength(0.5, PlotLengthUnit.RelativeToPlotArea); + this.Y = new PlotLength(0.5, PlotLengthUnit.RelativeToPlotArea); + this.OffsetX = new PlotLength(0, PlotLengthUnit.ScreenUnits); + this.OffsetY = new PlotLength(0, PlotLengthUnit.ScreenUnits); + this.Width = new PlotLength(double.NaN, PlotLengthUnit.ScreenUnits); + this.Height = new PlotLength(double.NaN, PlotLengthUnit.ScreenUnits); + this.Opacity = 1.0; + this.Interpolate = true; + this.HorizontalAlignment = OxyPlot.HorizontalAlignment.Center; + this.VerticalAlignment = OxyPlot.VerticalAlignment.Middle; + } + + /// + /// Initializes a new instance of the class. + /// + /// + /// The image. + /// + /// + /// The position in screen coordinates. + /// + /// + /// The horizontal alignment. + /// + /// + /// The vertical alignment. + /// + public ImageAnnotation( + OxyImage image, + ScreenPoint position, + HorizontalAlignment horizontalAlignment = OxyPlot.HorizontalAlignment.Center, + VerticalAlignment verticalAlignment = OxyPlot.VerticalAlignment.Middle) + : this() + { + this.ImageSource = image; + this.X = new PlotLength(position.X, PlotLengthUnit.ScreenUnits); + this.Y = new PlotLength(position.Y, PlotLengthUnit.ScreenUnits); + this.HorizontalAlignment = horizontalAlignment; + this.VerticalAlignment = verticalAlignment; + } + + /// + /// Initializes a new instance of the class. + /// + /// + /// The image. + /// + /// + /// The position in data coordinates. + /// + /// + /// The horizontal alignment. + /// + /// + /// The vertical alignment. + /// + public ImageAnnotation( + OxyImage image, + IDataPoint position, + HorizontalAlignment horizontalAlignment = OxyPlot.HorizontalAlignment.Center, + VerticalAlignment verticalAlignment = OxyPlot.VerticalAlignment.Middle) + : this() + { + this.ImageSource = image; + this.X = new PlotLength(position.X, PlotLengthUnit.Data); + this.Y = new PlotLength(position.Y, PlotLengthUnit.Data); + this.HorizontalAlignment = horizontalAlignment; + this.VerticalAlignment = verticalAlignment; + } + + /// + /// Initializes a new instance of the class. + /// + /// + /// The image. + /// + /// + /// The x-coordinate relative to the plot area (0-1). + /// + /// + /// The y-coordinate relative to the plot area (0-1). + /// + /// + /// The horizontal alignment. + /// + /// + /// The vertical alignment. + /// + public ImageAnnotation( + OxyImage image, + double relativeX, + double relativeY, + HorizontalAlignment horizontalAlignment = OxyPlot.HorizontalAlignment.Center, + VerticalAlignment verticalAlignment = OxyPlot.VerticalAlignment.Middle) + : this() + { + this.ImageSource = image; + this.X = new PlotLength(relativeX, PlotLengthUnit.RelativeToPlotArea); + this.Y = new PlotLength(relativeY, PlotLengthUnit.RelativeToPlotArea); + this.HorizontalAlignment = horizontalAlignment; + this.VerticalAlignment = verticalAlignment; + } + + /// + /// Gets or sets the image source. + /// + /// + /// The image source. + /// + public OxyImage ImageSource { get; set; } + + /// + /// Gets or sets the horizontal alignment. + /// + /// The horizontal alignment. + public HorizontalAlignment HorizontalAlignment { get; set; } + + /// + /// Gets or sets the X position of the image. + /// + /// + /// The X. + /// + public PlotLength X { get; set; } + + /// + /// Gets or sets the Y position of the image. + /// + /// + /// The Y. + /// + public PlotLength Y { get; set; } + + /// + /// Gets or sets the X offset. + /// + /// + /// The offset X. + /// + public PlotLength OffsetX { get; set; } + + /// + /// Gets or sets the Y offset. + /// + /// + /// The offset Y. + /// + public PlotLength OffsetY { get; set; } + + /// + /// Gets or sets the width. + /// + /// + /// The width. + /// + public PlotLength Width { get; set; } + + /// + /// Gets or sets the height. + /// + /// + /// The height. + /// + public PlotLength Height { get; set; } + + /// + /// Gets or sets the opacity (0-1). + /// + /// + /// The opacity value. + /// + public double Opacity { get; set; } + + /// + /// Gets or sets a value indicating whether to apply smooth interpolation to the image. + /// + /// + /// true if the image should be interpolated (using a high-quality bi-cubic interpolation); false if the nearest neighbor should be used. + /// + public bool Interpolate { get; set; } + + /// + /// Gets or sets the vertical alignment. + /// + /// The vertical alignment. + public VerticalAlignment VerticalAlignment { get; set; } + + /// + /// Renders the image annotation. + /// + /// + /// The render context. + /// + /// + /// The plot model. + /// + public override void Render(IRenderContext rc, PlotModel model) + { + base.Render(rc, model); + + var p = this.GetPoint(this.X, this.Y, rc, model); + var o = this.GetVector(this.OffsetX, this.OffsetY, rc, model); + var position = p + o; + + var clippingRect = this.GetClippingRect(); + + var imageInfo = rc.GetImageInfo(this.ImageSource); + if (imageInfo == null) + { + return; + } + + var s = this.GetVector(this.Width, this.Height, rc, model); + + var width = s.X; + var height = s.Y; + + if (double.IsNaN(width) && double.IsNaN(height)) + { + width = imageInfo.Width; + height = imageInfo.Height; + } + + if (double.IsNaN(width)) + { + width = height / imageInfo.Height * imageInfo.Width; + } + + if (double.IsNaN(height)) + { + height = width / imageInfo.Width * imageInfo.Height; + } + + double x = position.X; + double y = position.Y; + + if (this.HorizontalAlignment == HorizontalAlignment.Center) + { + x -= width * 0.5; + } + + if (this.HorizontalAlignment == HorizontalAlignment.Right) + { + x -= width; + } + + if (this.VerticalAlignment == VerticalAlignment.Middle) + { + y -= height * 0.5; + } + + if (this.VerticalAlignment == VerticalAlignment.Bottom) + { + y -= height; + } + + this.actualBounds = new OxyRect(x, y, width, height); + + if (this.X.Unit == PlotLengthUnit.Data || this.Y.Unit == PlotLengthUnit.Data) + { + rc.DrawClippedImage(clippingRect, this.ImageSource, x, y, width, height, this.Opacity, this.Interpolate); + } + else + { + rc.DrawImage(this.ImageSource, x, y, width, height, this.Opacity, this.Interpolate); + } + } + + /// + /// Tests if the plot element is hit by the specified point. + /// + /// + /// The point. + /// + /// + /// The tolerance. + /// + /// + /// A hit test result. + /// + protected internal override HitTestResult HitTest(ScreenPoint point, double tolerance) + { + if (this.actualBounds.Contains(point)) + { + return new HitTestResult(point); + } + + return null; + } + + /// + /// Gets the point. + /// + /// + /// The x. + /// + /// + /// The y. + /// + /// + /// The render context. + /// + /// + /// The model. + /// + /// + /// The point in screen coordinates. + /// + protected ScreenPoint GetPoint(PlotLength x, PlotLength y, IRenderContext rc, PlotModel model) + { + if (x.Unit == PlotLengthUnit.Data || y.Unit == PlotLengthUnit.Data) + { + return this.XAxis.Transform(x.Value, y.Value, this.YAxis); + } + + double sx; + double sy; + switch (x.Unit) + { + case PlotLengthUnit.RelativeToPlotArea: + sx = model.PlotArea.Left + (model.PlotArea.Width * x.Value); + break; + case PlotLengthUnit.RelativeToViewport: + sx = model.Width * x.Value; + break; + default: + sx = x.Value; + break; + } + + switch (y.Unit) + { + case PlotLengthUnit.RelativeToPlotArea: + sy = model.PlotArea.Top + (model.PlotArea.Height * y.Value); + break; + case PlotLengthUnit.RelativeToViewport: + sy = model.Height * y.Value; + break; + default: + sy = y.Value; + break; + } + + return new ScreenPoint(sx, sy); + } + + /// + /// Gets the vector. + /// + /// + /// The x component. + /// + /// + /// The y component. + /// + /// + /// The render context. + /// + /// + /// The model. + /// + /// + /// The vector in screen coordinates. + /// + protected ScreenVector GetVector(PlotLength x, PlotLength y, IRenderContext rc, PlotModel model) + { + double sx; + double sy; + + switch (x.Unit) + { + case PlotLengthUnit.Data: + sx = this.XAxis.Transform(x.Value) - this.XAxis.Transform(0); + break; + case PlotLengthUnit.RelativeToPlotArea: + sx = model.PlotArea.Width * x.Value; + break; + case PlotLengthUnit.RelativeToViewport: + sx = model.Width * x.Value; + break; + default: + sx = x.Value; + break; + } + + switch (y.Unit) + { + case PlotLengthUnit.Data: + sy = this.YAxis.Transform(y.Value) - this.YAxis.Transform(0); + break; + case PlotLengthUnit.RelativeToPlotArea: + sy = model.PlotArea.Height * y.Value; + break; + case PlotLengthUnit.RelativeToViewport: + sy = model.Height * y.Value; + break; + default: + sy = y.Value; + break; + } + + return new ScreenVector(sx, sy); + } + } +} \ No newline at end of file diff -r 88d699a65cc2 -r 5be8f2773237 External/OxyPlot/OxyPlot/Annotations/LineAnnotation.cs --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/External/OxyPlot/OxyPlot/Annotations/LineAnnotation.cs Sat Jun 08 16:53:22 2013 +0000 @@ -0,0 +1,528 @@ +// -------------------------------------------------------------------------------------------------------------------- +// +// The MIT License (MIT) +// +// Copyright (c) 2012 Oystein Bjorke +// +// Permission is hereby granted, free of charge, to any person obtaining a +// copy of this software and associated documentation files (the +// "Software"), to deal in the Software without restriction, including +// without limitation the rights to use, copy, modify, merge, publish, +// distribute, sublicense, and/or sell copies of the Software, and to +// permit persons to whom the Software is furnished to do so, subject to +// the following conditions: +// +// The above copyright notice and this permission notice shall be included +// in all copies or substantial portions of the Software. +// +// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS +// OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF +// MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. +// IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY +// CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, +// TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE +// SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. +// +// +// Specify the orientation of the annotation text +// +// -------------------------------------------------------------------------------------------------------------------- +namespace OxyPlot.Annotations +{ + using System; + using System.Collections.Generic; + using System.Linq; + + using OxyPlot.Axes; + + /// + /// Specifes the orientation of the annotation text + /// + public enum AnnotationTextOrientation + { + /// + /// Horizontal text. + /// + Horizontal, + + /// + /// Vertical text. + /// + Vertical, + + /// + /// Oriented along the line. + /// + AlongLine + } + + /// + /// Represents a line annotation. + /// + public class LineAnnotation : TextualAnnotation + { + /// + /// The points of the line, transformed to screen coordinates. + /// + private IList screenPoints; + + /// + /// Initializes a new instance of the class. + /// + public LineAnnotation() + { + this.Type = LineAnnotationType.LinearEquation; + this.MinimumX = double.MinValue; + this.MaximumX = double.MaxValue; + this.MinimumY = double.MinValue; + this.MaximumY = double.MaxValue; + this.Color = OxyColors.Blue; + this.StrokeThickness = 1; + this.LineStyle = LineStyle.Dash; + this.LineJoin = OxyPenLineJoin.Miter; + this.ClipByXAxis = true; + this.ClipByYAxis = true; + + this.TextPosition = 1; + this.TextOrientation = AnnotationTextOrientation.AlongLine; + this.TextMargin = 12; + this.TextHorizontalAlignment = HorizontalAlignment.Right; + this.TextVerticalAlignment = VerticalAlignment.Top; + } + + /// + /// Gets or sets the color of the line. + /// + public OxyColor Color { get; set; } + + /// + /// Gets or sets the y=f(x) equation when Type is Equation. + /// + public Func Equation { get; set; } + + /// + /// Gets or sets the y-intercept when Type is LinearEquation. + /// + /// The intercept value. + /// + /// Linear equation y-intercept (the b in y=mx+b). + /// http://en.wikipedia.org/wiki/Linear_equation + /// + public double Intercept { get; set; } + + /// + /// Gets or sets the line join. + /// + /// The line join. + public OxyPenLineJoin LineJoin { get; set; } + + /// + /// Gets or sets the line style. + /// + /// The line style. + public LineStyle LineStyle { get; set; } + + /// + /// Gets or sets the maximum X coordinate for the line. + /// + public double MaximumX { get; set; } + + /// + /// Gets or sets the maximum Y coordinate for the line. + /// + public double MaximumY { get; set; } + + /// + /// Gets or sets the minimum X coordinate for the line. + /// + public double MinimumX { get; set; } + + /// + /// Gets or sets the minimum Y coordinate for the line. + /// + public double MinimumY { get; set; } + + /// + /// Gets or sets the slope when Type is LinearEquation. + /// + /// The slope value. + /// + /// Linear equation slope (the m in y=mx+b) + /// http://en.wikipedia.org/wiki/Linear_equation + /// + public double Slope { get; set; } + + /// + /// Gets or sets the stroke thickness. + /// + /// The stroke thickness. + public double StrokeThickness { get; set; } + + /// + /// Gets or sets the text horizontal alignment. + /// + /// The text horizontal alignment. + public HorizontalAlignment TextHorizontalAlignment { get; set; } + + /// + /// Gets or sets the text margin (along the line). + /// + /// The text margin. + public double TextMargin { get; set; } + + /// + /// Gets or sets the text padding (in the direction of the text). + /// + /// The text padding. + public double TextPadding { get; set; } + + /// + /// Gets or sets the text orientation. + /// + /// The text orientation. + public AnnotationTextOrientation TextOrientation { get; set; } + + /// + /// Gets or sets the text position fraction. + /// + /// The text position in the interval [0,1]. + /// + /// Positions smaller than 0.25 are left aligned at the start of the line + /// Positions larger than 0.75 are right aligned at the end of the line + /// Other positions are center aligned at the specified position + /// + public double TextPosition { get; set; } + + /// + /// Gets or sets the vertical alignment of text (above or below the line). + /// + public VerticalAlignment TextVerticalAlignment { get; set; } + + /// + /// Gets or sets the type of line equation. + /// + public LineAnnotationType Type { get; set; } + + /// + /// Gets or sets the X position for vertical lines (only for Type==Vertical). + /// + public double X { get; set; } + + /// + /// Gets or sets the Y position for horizontal lines (only for Type==Horizontal) + /// + public double Y { get; set; } + + /// + /// Gets or sets a value indicating whether to clip the annotation line by the X axis range. + /// + /// true if clipping by the X axis is enabled; otherwise, false. + public bool ClipByXAxis { get; set; } + + /// + /// Gets or sets a value indicating whether to clip the annotation line by the Y axis range. + /// + /// true if clipping by the Y axis is enabled; otherwise, false. + public bool ClipByYAxis { get; set; } + + /// + /// Renders the line annotation. + /// + /// + /// The render context. + /// + /// + /// The plot model. + /// + public override void Render(IRenderContext rc, PlotModel model) + { + base.Render(rc, model); + + bool aliased = false; + + double actualMinimumX = Math.Max(this.MinimumX, this.XAxis.ActualMinimum); + double actualMaximumX = Math.Min(this.MaximumX, this.XAxis.ActualMaximum); + double actualMinimumY = Math.Max(this.MinimumY, this.YAxis.ActualMinimum); + double actualMaximumY = Math.Min(this.MaximumY, this.YAxis.ActualMaximum); + + if (!this.ClipByXAxis) + { + double right = XAxis.InverseTransform(PlotModel.PlotArea.Right); + double left = XAxis.InverseTransform(PlotModel.PlotArea.Left); + actualMaximumX = Math.Max(left, right); + actualMinimumX = Math.Min(left, right); + } + + if (!this.ClipByYAxis) + { + double bottom = YAxis.InverseTransform(PlotModel.PlotArea.Bottom); + double top = YAxis.InverseTransform(PlotModel.PlotArea.Top); + actualMaximumY = Math.Max(top, bottom); + actualMinimumY = Math.Min(top, bottom); + } + + // y=f(x) + Func fx = null; + + // x=f(y) + Func fy = null; + + switch (this.Type) + { + case LineAnnotationType.Horizontal: + fx = x => this.Y; + break; + case LineAnnotationType.Vertical: + fy = y => this.X; + break; + case LineAnnotationType.EquationY: + fx = this.Equation; + break; + case LineAnnotationType.EquationX: + fy = this.Equation; + break; + default: + fx = x => (this.Slope * x) + this.Intercept; + break; + } + + var points = new List(); + + bool isCurvedLine = !(this.XAxis is LinearAxis) || !(this.YAxis is LinearAxis) || this.Type == LineAnnotationType.EquationY; + + if (!isCurvedLine) + { + // we only need to calculate two points if it is a straight line + if (fx != null) + { + points.Add(new DataPoint(actualMinimumX, fx(actualMinimumX))); + points.Add(new DataPoint(actualMaximumX, fx(actualMaximumX))); + } + else if (fy != null) + { + points.Add(new DataPoint(fy(actualMinimumY), actualMinimumY)); + points.Add(new DataPoint(fy(actualMaximumY), actualMaximumY)); + } + + if (this.Type == LineAnnotationType.Horizontal || this.Type == LineAnnotationType.Vertical) + { + // use aliased line drawing for horizontal and vertical lines + aliased = true; + } + } + else + { + if (fx != null) + { + double x = actualMinimumX; + + // todo: the step size should be adaptive + double dx = (actualMaximumX - actualMinimumX) / 100; + while (true) + { + points.Add(new DataPoint(x, fx(x))); + if (x > actualMaximumX) + { + break; + } + + x += dx; + } + } + else if (fy != null) + { + double y = actualMinimumY; + + // todo: the step size should be adaptive + double dy = (actualMaximumY - actualMinimumY) / 100; + while (true) + { + points.Add(new DataPoint(fy(y), y)); + if (y > actualMaximumY) + { + break; + } + + y += dy; + } + } + } + + // transform to screen coordinates + this.screenPoints = points.Select(p => this.Transform(p)).ToList(); + + // clip to the area defined by the axes + var clippingRectangle = OxyRect.Create( + this.ClipByXAxis ? this.XAxis.ScreenMin.X : PlotModel.PlotArea.Left, + this.ClipByYAxis ? this.YAxis.ScreenMin.Y : PlotModel.PlotArea.Top, + this.ClipByXAxis ? this.XAxis.ScreenMax.X : PlotModel.PlotArea.Right, + this.ClipByYAxis ? this.YAxis.ScreenMax.Y : PlotModel.PlotArea.Bottom); + + const double MinimumSegmentLength = 4; + + IList clippedPoints = null; + + rc.DrawClippedLine( + this.screenPoints, + clippingRectangle, + MinimumSegmentLength * MinimumSegmentLength, + this.GetSelectableColor(this.Color), + this.StrokeThickness, + this.LineStyle, + this.LineJoin, + aliased, + pts => clippedPoints = pts); + + ScreenPoint position; + double angle; + double margin = this.TextMargin; + + if (this.TextHorizontalAlignment == HorizontalAlignment.Center) + { + margin = 0; + } + else + { + margin *= this.TextPosition < 0.5 ? 1 : -1; + } + + if (clippedPoints != null && GetPointAtRelativeDistance(clippedPoints, this.TextPosition, margin, out position, out angle)) + { + if (angle < -90) + { + angle += 180; + } + + if (angle > 90) + { + angle -= 180; + } + + switch (this.TextOrientation) + { + case AnnotationTextOrientation.Horizontal: + angle = 0; + break; + case AnnotationTextOrientation.Vertical: + angle = -90; + break; + } + + // Apply 'padding' to the position + var angleInRadians = angle / 180 * Math.PI; + var f = 1; + + if (this.TextHorizontalAlignment == HorizontalAlignment.Right) + { + f = -1; + } + + if (this.TextHorizontalAlignment == HorizontalAlignment.Center) + { + f = 0; + } + + position.X += f * this.TextPadding * Math.Cos(angleInRadians); + position.Y += f * this.TextPadding * Math.Sin(angleInRadians); + + var cs = new CohenSutherlandClipping(clippingRectangle); + if (!string.IsNullOrEmpty(this.Text) && cs.IsInside(position)) + { + rc.DrawClippedText( + clippingRectangle, + position, + this.Text, + this.ActualTextColor, + this.ActualFont, + this.ActualFontSize, + this.ActualFontWeight, + angle, + this.TextHorizontalAlignment, + this.TextVerticalAlignment); + } + } + } + + /// + /// Tests if the plot element is hit by the specified point. + /// + /// The point. + /// The tolerance. + /// + /// A hit test result. + /// + protected internal override HitTestResult HitTest(ScreenPoint point, double tolerance) + { + var nearestPoint = ScreenPointHelper.FindNearestPointOnPolyline(point, this.screenPoints); + double dist = (point - nearestPoint).Length; + if (dist < tolerance) + { + return new HitTestResult(nearestPoint); + } + + return null; + } + + /// + /// Gets the point on a curve at the specified relative distance along the curve. + /// + /// + /// The curve points. + /// + /// + /// The relative distance along the curve. + /// + /// + /// The margins. + /// + /// + /// The position. + /// + /// + /// The angle. + /// + /// + /// True if a position was found. + /// + private static bool GetPointAtRelativeDistance( + IList pts, double p, double margin, out ScreenPoint position, out double angle) + { + if (pts == null || pts.Count == 0) + { + position = new ScreenPoint(); + angle = 0; + return false; + } + + double length = 0; + for (int i = 1; i < pts.Count; i++) + { + length += (pts[i] - pts[i - 1]).Length; + } + + double l = (length * p) + margin; + length = 0; + for (int i = 1; i < pts.Count; i++) + { + double dl = (pts[i] - pts[i - 1]).Length; + if (l >= length && l <= length + dl) + { + double f = (l - length) / dl; + double x = (pts[i].X * f) + (pts[i - 1].X * (1 - f)); + double y = (pts[i].Y * f) + (pts[i - 1].Y * (1 - f)); + position = new ScreenPoint(x, y); + double dx = pts[i].X - pts[i - 1].X; + double dy = pts[i].Y - pts[i - 1].Y; + angle = Math.Atan2(dy, dx) / Math.PI * 180; + return true; + } + + length += dl; + } + + position = pts[0]; + angle = 0; + return false; + } + } +} \ No newline at end of file diff -r 88d699a65cc2 -r 5be8f2773237 External/OxyPlot/OxyPlot/Annotations/LineAnnotationType.cs --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/External/OxyPlot/OxyPlot/Annotations/LineAnnotationType.cs Sat Jun 08 16:53:22 2013 +0000 @@ -0,0 +1,62 @@ +// -------------------------------------------------------------------------------------------------------------------- +// +// The MIT License (MIT) +// +// Copyright (c) 2012 Oystein Bjorke +// +// Permission is hereby granted, free of charge, to any person obtaining a +// copy of this software and associated documentation files (the +// "Software"), to deal in the Software without restriction, including +// without limitation the rights to use, copy, modify, merge, publish, +// distribute, sublicense, and/or sell copies of the Software, and to +// permit persons to whom the Software is furnished to do so, subject to +// the following conditions: +// +// The above copyright notice and this permission notice shall be included +// in all copies or substantial portions of the Software. +// +// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS +// OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF +// MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. +// IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY +// CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, +// TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE +// SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. +// +// +// The line annotation type. +// +// -------------------------------------------------------------------------------------------------------------------- +namespace OxyPlot.Annotations +{ + /// + /// Specifies the definition of the line in a . + /// + public enum LineAnnotationType + { + /// + /// Horizontal line given by the Y property + /// + Horizontal, + + /// + /// Vertical line given by the X property + /// + Vertical, + + /// + /// Linear equation y=mx+b given by the Slope and Intercept properties + /// + LinearEquation, + + /// + /// Curve equation x=f(y) given by the Equation property + /// + EquationX, + + /// + /// Curve equation y=f(x) given by the Equation property + /// + EquationY + } +} \ No newline at end of file diff -r 88d699a65cc2 -r 5be8f2773237 External/OxyPlot/OxyPlot/Annotations/PolygonAnnotation.cs --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/External/OxyPlot/OxyPlot/Annotations/PolygonAnnotation.cs Sat Jun 08 16:53:22 2013 +0000 @@ -0,0 +1,166 @@ +// -------------------------------------------------------------------------------------------------------------------- +// +// The MIT License (MIT) +// +// Copyright (c) 2012 Oystein Bjorke +// +// Permission is hereby granted, free of charge, to any person obtaining a +// copy of this software and associated documentation files (the +// "Software"), to deal in the Software without restriction, including +// without limitation the rights to use, copy, modify, merge, publish, +// distribute, sublicense, and/or sell copies of the Software, and to +// permit persons to whom the Software is furnished to do so, subject to +// the following conditions: +// +// The above copyright notice and this permission notice shall be included +// in all copies or substantial portions of the Software. +// +// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS +// OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF +// MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. +// IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY +// CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, +// TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE +// SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. +// +// +// Represents a polygon annotation. +// +// -------------------------------------------------------------------------------------------------------------------- +namespace OxyPlot.Annotations +{ + using System.Collections.Generic; + using System.Linq; + + /// + /// Represents a polygon annotation. + /// + public class PolygonAnnotation : TextualAnnotation + { + /// + /// The polygon points transformed to screen coordinates. + /// + private IList screenPoints; + + /// + /// Initializes a new instance of the class. + /// + public PolygonAnnotation() + { + this.Color = OxyColors.Blue; + this.Fill = OxyColors.LightBlue; + this.StrokeThickness = 1; + this.LineStyle = LineStyle.Solid; + this.LineJoin = OxyPenLineJoin.Miter; + } + + /// + /// Gets or sets the color of the line. + /// + public OxyColor Color { get; set; } + + /// + /// Gets or sets the fill color. + /// + /// The fill. + public OxyColor Fill { get; set; } + + /// + /// Gets or sets the line join. + /// + /// The line join. + public OxyPenLineJoin LineJoin { get; set; } + + /// + /// Gets or sets the line style. + /// + /// The line style. + public LineStyle LineStyle { get; set; } + + /// + /// Gets or sets the points. + /// + /// The points. + public IList Points { get; set; } + + /// + /// Gets or sets the stroke thickness. + /// + /// The stroke thickness. + public double StrokeThickness { get; set; } + + /// + /// Renders the polygon annotation. + /// + /// + /// The render context. + /// + /// + /// The plot model. + /// + public override void Render(IRenderContext rc, PlotModel model) + { + base.Render(rc, model); + if (this.Points == null) + { + return; + } + + // transform to screen coordinates + this.screenPoints = this.Points.Select(p => this.Transform(p)).ToList(); + if (this.screenPoints.Count == 0) + { + return; + } + + // clip to the area defined by the axes + var clipping = this.GetClippingRect(); + + const double MinimumSegmentLength = 4; + + rc.DrawClippedPolygon( + this.screenPoints, + clipping, + MinimumSegmentLength * MinimumSegmentLength, + this.GetSelectableFillColor(this.Fill), + this.GetSelectableColor(this.Color), + this.StrokeThickness, + this.LineStyle, + this.LineJoin); + + if (!string.IsNullOrEmpty(this.Text)) + { + var textPosition = ScreenPointHelper.GetCentroid(this.screenPoints); + + rc.DrawClippedText( + clipping, + textPosition, + this.Text, + this.ActualTextColor, + this.ActualFont, + this.ActualFontSize, + this.ActualFontWeight, + 0, + HorizontalAlignment.Center, + VerticalAlignment.Middle); + } + } + + /// + /// Tests if the plot element is hit by the specified point. + /// + /// + /// The point. + /// + /// + /// The tolerance. + /// + /// + /// A hit test result. + /// + protected internal override HitTestResult HitTest(ScreenPoint point, double tolerance) + { + return ScreenPointHelper.IsPointInPolygon(point, this.screenPoints) ? new HitTestResult(point) : null; + } + } +} \ No newline at end of file diff -r 88d699a65cc2 -r 5be8f2773237 External/OxyPlot/OxyPlot/Annotations/RectangleAnnotation.cs --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/External/OxyPlot/OxyPlot/Annotations/RectangleAnnotation.cs Sat Jun 08 16:53:22 2013 +0000 @@ -0,0 +1,174 @@ +// -------------------------------------------------------------------------------------------------------------------- +// +// The MIT License (MIT) +// +// Copyright (c) 2012 Oystein Bjorke +// +// Permission is hereby granted, free of charge, to any person obtaining a +// copy of this software and associated documentation files (the +// "Software"), to deal in the Software without restriction, including +// without limitation the rights to use, copy, modify, merge, publish, +// distribute, sublicense, and/or sell copies of the Software, and to +// permit persons to whom the Software is furnished to do so, subject to +// the following conditions: +// +// The above copyright notice and this permission notice shall be included +// in all copies or substantial portions of the Software. +// +// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS +// OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF +// MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. +// IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY +// CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, +// TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE +// SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. +// +// +// Represents a rectangle annotation. +// +// -------------------------------------------------------------------------------------------------------------------- +namespace OxyPlot.Annotations +{ + /// + /// Represents a rectangle annotation. + /// + public class RectangleAnnotation : TextualAnnotation + { + /// + /// The rectangle transformed to screen coordinates. + /// + private OxyRect screenRectangle; + + /// + /// Initializes a new instance of the class. + /// + public RectangleAnnotation() + { + this.Stroke = OxyColors.Black; + this.Fill = OxyColors.LightBlue; + this.MinimumX = double.MinValue; + this.MaximumX = double.MaxValue; + this.MinimumY = double.MinValue; + this.MaximumY = double.MaxValue; + this.TextRotation = 0; + } + + /// + /// Gets or sets the fill color. + /// + /// The fill. + public OxyColor Fill { get; set; } + + /// + /// Gets or sets the stroke color. + /// + public OxyColor Stroke { get; set; } + + /// + /// Gets or sets the stroke thickness. + /// + public double StrokeThickness { get; set; } + + /// + /// Gets or sets the minimum X. + /// + /// The minimum X. + public double MinimumX { get; set; } + + /// + /// Gets or sets the maximum X. + /// + /// The maximum X. + public double MaximumX { get; set; } + + /// + /// Gets or sets the minimum Y. + /// + /// The minimum Y. + public double MinimumY { get; set; } + + /// + /// Gets or sets the maximum Y. + /// + /// The maximum Y. + public double MaximumY { get; set; } + + /// + /// Gets or sets the text rotation (degrees). + /// + /// The text rotation in degrees. + public double TextRotation { get; set; } + + /// + /// Renders the polygon annotation. + /// + /// + /// The render context. + /// + /// + /// The plot model. + /// + public override void Render(IRenderContext rc, PlotModel model) + { + base.Render(rc, model); + + double x0 = double.IsNaN(this.MinimumX) || this.MinimumX.Equals(double.MinValue) + ? this.XAxis.ActualMinimum + : this.MinimumX; + double x1 = double.IsNaN(this.MaximumX) || this.MaximumX.Equals(double.MaxValue) + ? this.XAxis.ActualMaximum + : this.MaximumX; + double y0 = double.IsNaN(this.MinimumY) || this.MinimumY.Equals(double.MinValue) + ? this.YAxis.ActualMinimum + : this.MinimumY; + double y1 = double.IsNaN(this.MaximumY) || this.MaximumY.Equals(double.MaxValue) + ? this.YAxis.ActualMaximum + : this.MaximumY; + + this.screenRectangle = OxyRect.Create(this.Transform(x0, y0), this.Transform(x1, y1)); + + // clip to the area defined by the axes + var clipping = this.GetClippingRect(); + + rc.DrawClippedRectangle(this.screenRectangle, clipping, this.Fill, this.Stroke, this.StrokeThickness); + + if (!string.IsNullOrEmpty(this.Text)) + { + var textPosition = this.screenRectangle.Center; + rc.DrawClippedText( + clipping, + textPosition, + this.Text, + this.ActualTextColor, + this.ActualFont, + this.ActualFontSize, + this.ActualFontWeight, + this.TextRotation, + HorizontalAlignment.Center, + VerticalAlignment.Middle); + } + } + + /// + /// Tests if the plot element is hit by the specified point. + /// + /// + /// The point. + /// + /// + /// The tolerance. + /// + /// + /// A hit test result. + /// + protected internal override HitTestResult HitTest(ScreenPoint point, double tolerance) + { + if (this.screenRectangle.Contains(point)) + { + return new HitTestResult(point); + } + + return null; + } + } +} \ No newline at end of file diff -r 88d699a65cc2 -r 5be8f2773237 External/OxyPlot/OxyPlot/Annotations/TextAnnotation.cs --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/External/OxyPlot/OxyPlot/Annotations/TextAnnotation.cs Sat Jun 08 16:53:22 2013 +0000 @@ -0,0 +1,254 @@ +// -------------------------------------------------------------------------------------------------------------------- +// +// The MIT License (MIT) +// +// Copyright (c) 2012 Oystein Bjorke +// +// Permission is hereby granted, free of charge, to any person obtaining a +// copy of this software and associated documentation files (the +// "Software"), to deal in the Software without restriction, including +// without limitation the rights to use, copy, modify, merge, publish, +// distribute, sublicense, and/or sell copies of the Software, and to +// permit persons to whom the Software is furnished to do so, subject to +// the following conditions: +// +// The above copyright notice and this permission notice shall be included +// in all copies or substantial portions of the Software. +// +// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS +// OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF +// MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. +// IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY +// CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, +// TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE +// SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. +// +// +// Represents a text object annotation. +// +// -------------------------------------------------------------------------------------------------------------------- +namespace OxyPlot.Annotations +{ + using System; + using System.Collections.Generic; + + /// + /// Represents a text annotation. + /// + public class TextAnnotation : TextualAnnotation + { + /// + /// The actual bounds of the text. + /// + private IList actualBounds; + + /// + /// Initializes a new instance of the class. + /// + public TextAnnotation() + { + this.TextColor = OxyColors.Blue; + this.Stroke = OxyColors.Black; + this.Background = null; + this.StrokeThickness = 1; + this.Rotation = 0; + this.HorizontalAlignment = OxyPlot.HorizontalAlignment.Center; + this.VerticalAlignment = OxyPlot.VerticalAlignment.Bottom; + this.Padding = new OxyThickness(4); + } + + /// + /// Gets or sets the fill color of the background rectangle. + /// + /// The background. + public OxyColor Background { get; set; } + + /// + /// Gets or sets the horizontal alignment. + /// + /// The horizontal alignment. + public HorizontalAlignment HorizontalAlignment { get; set; } + + /// + /// Gets or sets the position offset (screen coordinates). + /// + /// The offset. + public ScreenVector Offset { get; set; } + + /// + /// Gets or sets the padding of the background rectangle. + /// + /// The padding. + public OxyThickness Padding { get; set; } + + /// + /// Gets or sets the position of the text. + /// + public DataPoint Position { get; set; } + + /// + /// Gets or sets the rotation angle (degrees). + /// + /// The rotation. + public double Rotation { get; set; } + + /// + /// Gets or sets the stroke color of the background rectangle. + /// + /// The stroke color. + public OxyColor Stroke { get; set; } + + /// + /// Gets or sets the stroke thickness of the background rectangle. + /// + /// The stroke thickness. + public double StrokeThickness { get; set; } + + /// + /// Gets or sets the vertical alignment. + /// + /// The vertical alignment. + public VerticalAlignment VerticalAlignment { get; set; } + + /// + /// Renders the text annotation. + /// + /// + /// The render context. + /// + /// + /// The plot model. + /// + public override void Render(IRenderContext rc, PlotModel model) + { + base.Render(rc, model); + + var position = this.Transform(this.Position); + position.X += this.Offset.X; + position.Y += this.Offset.Y; + + var clippingRect = this.GetClippingRect(); + + var textSize = rc.MeasureText(this.Text, this.ActualFont, this.ActualFontSize, this.ActualFontWeight); + + const double MinDistSquared = 4; + + this.actualBounds = GetTextBounds( + position, textSize, this.Padding, this.Rotation, this.HorizontalAlignment, this.VerticalAlignment); + rc.DrawClippedPolygon( + this.actualBounds, clippingRect, MinDistSquared, this.Background, this.Stroke, this.StrokeThickness); + + rc.DrawClippedText( + clippingRect, + position, + this.Text, + this.GetSelectableFillColor(this.ActualTextColor), + this.ActualFont, + this.ActualFontSize, + this.ActualFontWeight, + this.Rotation, + this.HorizontalAlignment, + this.VerticalAlignment); + } + + /// + /// Tests if the plot element is hit by the specified point. + /// + /// + /// The point. + /// + /// + /// The tolerance. + /// + /// + /// A hit test result. + /// + protected internal override HitTestResult HitTest(ScreenPoint point, double tolerance) + { + if (this.actualBounds == null) + { + return null; + } + + // Todo: see if performance can be improved by checking rectangle (with rotation and alignment), not polygon + return ScreenPointHelper.IsPointInPolygon(point, this.actualBounds) ? new HitTestResult(point) : null; + } + + /// + /// Gets the coordinates of the (rotated) background rectangle. + /// + /// + /// The position. + /// + /// + /// The size. + /// + /// + /// The padding. + /// + /// + /// The rotation. + /// + /// + /// The horizontal alignment. + /// + /// + /// The vertical alignment. + /// + /// + /// The background rectangle coordinates. + /// + private static IList GetTextBounds( + ScreenPoint position, + OxySize size, + OxyThickness padding, + double rotation, + HorizontalAlignment horizontalAlignment, + VerticalAlignment verticalAlignment) + { + double left, right, top, bottom; + switch (horizontalAlignment) + { + case HorizontalAlignment.Center: + left = -size.Width * 0.5; + right = -left; + break; + case HorizontalAlignment.Right: + left = -size.Width; + right = 0; + break; + default: + left = 0; + right = size.Width; + break; + } + + switch (verticalAlignment) + { + case VerticalAlignment.Middle: + top = -size.Height * 0.5; + bottom = -top; + break; + case VerticalAlignment.Bottom: + top = -size.Height; + bottom = 0; + break; + default: + top = 0; + bottom = size.Height; + break; + } + + double cost = Math.Cos(rotation / 180 * Math.PI); + double sint = Math.Sin(rotation / 180 * Math.PI); + var u = new ScreenVector(cost, sint); + var v = new ScreenVector(-sint, cost); + var polygon = new ScreenPoint[4]; + polygon[0] = position + (u * (left - padding.Left)) + (v * (top - padding.Top)); + polygon[1] = position + (u * (right + padding.Right)) + (v * (top - padding.Top)); + polygon[2] = position + (u * (right + padding.Right)) + (v * (bottom + padding.Bottom)); + polygon[3] = position + (u * (left - padding.Left)) + (v * (bottom + padding.Bottom)); + return polygon; + } + } +} \ No newline at end of file diff -r 88d699a65cc2 -r 5be8f2773237 External/OxyPlot/OxyPlot/Annotations/TextualAnnotation.cs --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/External/OxyPlot/OxyPlot/Annotations/TextualAnnotation.cs Sat Jun 08 16:53:22 2013 +0000 @@ -0,0 +1,46 @@ +// -------------------------------------------------------------------------------------------------------------------- +// +// The MIT License (MIT) +// +// Copyright (c) 2012 Oystein Bjorke +// +// Permission is hereby granted, free of charge, to any person obtaining a +// copy of this software and associated documentation files (the +// "Software"), to deal in the Software without restriction, including +// without limitation the rights to use, copy, modify, merge, publish, +// distribute, sublicense, and/or sell copies of the Software, and to +// permit persons to whom the Software is furnished to do so, subject to +// the following conditions: +// +// The above copyright notice and this permission notice shall be included +// in all copies or substantial portions of the Software. +// +// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS +// OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF +// MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. +// IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY +// CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, +// TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE +// SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. +// +// +// Provides an abstract base class for annotations that contains text. +// +// -------------------------------------------------------------------------------------------------------------------- + +namespace OxyPlot.Annotations +{ + /// + /// Provides an abstract base class for annotations that contains text. + /// + public abstract class TextualAnnotation : Annotation + { + /// + /// Gets or sets the annotation text. + /// + /// + /// The text. + /// + public string Text { get; set; } + } +} \ No newline at end of file diff -r 88d699a65cc2 -r 5be8f2773237 External/OxyPlot/OxyPlot/Annotations/TileMapAnnotation.cs --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/External/OxyPlot/OxyPlot/Annotations/TileMapAnnotation.cs Sat Jun 08 16:53:22 2013 +0000 @@ -0,0 +1,457 @@ +// -------------------------------------------------------------------------------------------------------------------- +// +// The MIT License (MIT) +// +// Copyright (c) 2012 Oystein Bjorke +// +// Permission is hereby granted, free of charge, to any person obtaining a +// copy of this software and associated documentation files (the +// "Software"), to deal in the Software without restriction, including +// without limitation the rights to use, copy, modify, merge, publish, +// distribute, sublicense, and/or sell copies of the Software, and to +// permit persons to whom the Software is furnished to do so, subject to +// the following conditions: +// +// The above copyright notice and this permission notice shall be included +// in all copies or substantial portions of the Software. +// +// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS +// OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF +// MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. +// IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY +// CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, +// TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE +// SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. +// +// +// Provides a tile map annotation. +// +// -------------------------------------------------------------------------------------------------------------------- + +namespace OxyPlot.Annotations +{ + using System; + using System.Collections.Generic; + using System.Globalization; + using System.IO; + using System.Net; + using System.Threading; + + /// + /// Provides a tile map annotation. + /// + /// + /// The longitude and latitude range of the map is defined by the range of the x and y axis, respectively. + /// + public class TileMapAnnotation : Annotation + { + /// + /// The image cache. + /// + private readonly Dictionary images = new Dictionary(); + + /// + /// The download queue. + /// + private readonly Queue queue = new Queue(); + + /// + /// The current number of downloads + /// + private int numberOfDownloads; + + /// + /// Initializes a new instance of the class. + /// + public TileMapAnnotation() + { + this.TileSize = 256; + this.MinZoomLevel = 0; + this.MaxZoomLevel = 20; + this.Opacity = 1.0; + this.MaxNumberOfDownloads = 8; + } + + /// + /// Gets or sets the max number of simultaneous downloads. + /// + /// + /// The max number of downloads. + /// + public int MaxNumberOfDownloads { get; set; } + + /// + /// Gets or sets the URL. + /// + /// + /// The URL. + /// + public string Url { get; set; } + + /// + /// Gets or sets the copyright notice. + /// + /// + /// The copyright notice. + /// + public string CopyrightNotice { get; set; } + + /// + /// Gets or sets the size of the tiles. + /// + /// + /// The size of the tiles. + /// + public int TileSize { get; set; } + + /// + /// Gets or sets the min zoom level. + /// + /// + /// The min zoom level. + /// + public int MinZoomLevel { get; set; } + + /// + /// Gets or sets the max zoom level. + /// + /// + /// The max zoom level. + /// + public int MaxZoomLevel { get; set; } + + /// + /// Gets or sets the opacity. + /// + /// + /// The opacity. + /// + public double Opacity { get; set; } + + /// + /// Renders the annotation on the specified context. + /// + /// + /// The render context. + /// + /// + /// The model. + /// + public override void Render(IRenderContext rc, PlotModel model) + { + base.Render(rc, model); + var clippingRect = this.GetClippingRect(); + var lon0 = this.XAxis.ActualMinimum; + var lon1 = this.XAxis.ActualMaximum; + var lat0 = this.YAxis.ActualMinimum; + var lat1 = this.YAxis.ActualMaximum; + + // the desired number of tiles horizontally + double tilesx = model.Width / this.TileSize; + + // calculate the desired zoom level + var n = tilesx / (((lon1 + 180) / 360) - ((lon0 + 180) / 360)); + var zoom = (int)Math.Round(Math.Log(n) / Math.Log(2)); + if (zoom < this.MinZoomLevel) + { + zoom = this.MinZoomLevel; + } + + if (zoom > this.MaxZoomLevel) + { + zoom = this.MaxZoomLevel; + } + + // find tile coordinates for the corners + double x0, y0; + LatLonToTile(lat0, lon0, zoom, out x0, out y0); + double x1, y1; + LatLonToTile(lat1, lon1, zoom, out x1, out y1); + + double xmax = Math.Max(x0, x1); + double xmin = Math.Min(x0, x1); + double ymax = Math.Max(y0, y1); + double ymin = Math.Min(y0, y1); + + // Add the tiles + for (var x = (int)xmin; x < xmax; x++) + { + for (var y = (int)ymin; y < ymax; y++) + { + string uri = this.GetTileUri(x, y, zoom); + var img = this.GetImage(uri, rc.RendersToScreen); + + if (img == null) + { + continue; + } + + // transform from tile coordinates to lat/lon + double latitude0, latitude1, longitude0, longitude1; + TileToLatLon(x, y, zoom, out latitude0, out longitude0); + TileToLatLon(x + 1, y + 1, zoom, out latitude1, out longitude1); + + // transform from lat/lon to screen coordinates + var s00 = this.Transform(longitude0, latitude0); + var s11 = this.Transform(longitude1, latitude1); + + var r = OxyRect.Create(s00.X, s00.Y, s11.X, s11.Y); + + // draw the image + rc.DrawClippedImage(clippingRect, img, r.Left, r.Top, r.Width, r.Height, this.Opacity, true); + } + } + + // draw the copyright notice + var p = new ScreenPoint(clippingRect.Right - 5, clippingRect.Bottom - 5); + var textSize = rc.MeasureText(this.CopyrightNotice, null, 12); + rc.DrawRectangle(new OxyRect(p.X - textSize.Width - 2, p.Y - textSize.Height - 2, textSize.Width + 4, textSize.Height + 4), OxyColors.White.ChangeAlpha(200), null); + + rc.DrawText( + p, + this.CopyrightNotice, + OxyColors.Black, + null, + 12, + 500, + 0, + HorizontalAlignment.Right, + VerticalAlignment.Bottom); + } + + /// + /// Tests if the plot element is hit by the specified point. + /// + /// + /// The point. + /// + /// + /// The tolerance. + /// + /// + /// A hit test result. + /// + protected internal override HitTestResult HitTest(ScreenPoint point, double tolerance) + { + return null; + } + + /// + /// Transforms a position to a tile coordinate. + /// + /// The latitude. + /// The longitude. + /// The zoom. + /// The x. + /// The y. + private static void LatLonToTile(double latitude, double longitude, int zoom, out double x, out double y) + { + // http://wiki.openstreetmap.org/wiki/Slippy_map_tilenames + int n = 1 << zoom; + double lat = latitude / 180 * Math.PI; + x = (longitude + 180.0) / 360.0 * n; + y = (1.0 - Math.Log(Math.Tan(lat) + 1.0 / Math.Cos(lat)) / Math.PI) / 2.0 * n; + } + + /// + /// Transforms a tile coordinate (x,y) to a position. + /// + /// The x. + /// The y. + /// The zoom. + /// The latitude. + /// The longitude. + private static void TileToLatLon(double x, double y, int zoom, out double latitude, out double longitude) + { + int n = 1 << zoom; + longitude = (x / n * 360.0) - 180.0; + double lat = Math.Atan(Math.Sinh(Math.PI * (1 - (2 * y / n)))); + latitude = lat * 180.0 / Math.PI; + } + + /// + /// Gets the image from the specified uri. + /// + /// The URI. + /// Get the image asynchronously if set to true. The plot model will be invalidated when the image has been downloaded. + /// + /// The image. + /// + /// + /// This method gets the image from cache, or starts an async download. + /// + private OxyImage GetImage(string uri, bool async) + { + OxyImage img; + if (this.images.TryGetValue(uri, out img)) + { + return img; + } + + if (!async) + { + return this.Download(uri); + } + + lock (this.queue) + { + // 'reserve' an image (otherwise multiple downloads of the same uri may happen) + this.images[uri] = null; + this.queue.Enqueue(uri); + } + + this.BeginDownload(); + return null; + } + + /// + /// Downloads the image from the specified URI. + /// + /// The URI. + /// The image + private OxyImage Download(string uri) + { + OxyImage img = null; + var mre = new ManualResetEvent(false); + var request = (HttpWebRequest)WebRequest.Create(uri); + request.Method = "GET"; + request.BeginGetResponse( + r => + { + try + { + if (request.HaveResponse) + { + var response = request.EndGetResponse(r); + var stream = response.GetResponseStream(); + + var ms = new MemoryStream(); + stream.CopyTo(ms); + var buffer = ms.ToArray(); + + img = new OxyImage(buffer); + this.images[uri] = img; + } + + } + catch (Exception e) + { + var ie = e; + while (ie != null) + { + System.Diagnostics.Debug.WriteLine(ie.Message); + ie = ie.InnerException; + } + } + finally + { + mre.Set(); + } + }, + request); + + mre.WaitOne(); + return img; + } + + /// + /// Starts the next download in the queue. + /// + private void BeginDownload() + { + if (this.numberOfDownloads >= this.MaxNumberOfDownloads) + { + return; + } + + string uri = this.queue.Dequeue(); + var request = (HttpWebRequest)WebRequest.Create(uri); + request.Method = "GET"; + Interlocked.Increment(ref this.numberOfDownloads); + request.BeginGetResponse( + r => + { + Interlocked.Decrement(ref this.numberOfDownloads); + try + { + if (request.HaveResponse) + { + var response = request.EndGetResponse(r); + var stream = response.GetResponseStream(); + this.DownloadCompleted(uri, stream); + } + } + catch (Exception e) + { + var ie = e; + while (ie != null) + { + System.Diagnostics.Debug.WriteLine(ie.Message); + ie = ie.InnerException; + } + } + }, + request); + } + + /// + /// The download completed, set the image. + /// + /// The URI. + /// The result. + private void DownloadCompleted(string uri, Stream result) + { + if (result == null) + { + return; + } + + var ms = new MemoryStream(); + result.CopyTo(ms); + var buffer = ms.ToArray(); + + var img = new OxyImage(buffer); + this.images[uri] = img; + + lock (this.queue) + { + // Clear old items in the queue, new ones will be added when the plot is refreshed + foreach (var queuedUri in this.queue) + { + // Remove the 'reserved' image + this.images.Remove(queuedUri); + } + + this.queue.Clear(); + } + + this.PlotModel.InvalidatePlot(false); + if (this.queue.Count > 0) + { + this.BeginDownload(); + } + } + + /// + /// Gets the tile URI. + /// + /// + /// The tile x. + /// + /// + /// The tile y. + /// + /// + /// The zoom. + /// + /// + /// The uri. + /// + private string GetTileUri(int x, int y, int zoom) + { + string url = this.Url.Replace("{X}", x.ToString(CultureInfo.InvariantCulture)); + url = url.Replace("{Y}", y.ToString(CultureInfo.InvariantCulture)); + return url.Replace("{Z}", zoom.ToString(CultureInfo.InvariantCulture)); + } + } +} \ No newline at end of file diff -r 88d699a65cc2 -r 5be8f2773237 External/OxyPlot/OxyPlot/Axes/AngleAxis.cs --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/External/OxyPlot/OxyPlot/Axes/AngleAxis.cs Sat Jun 08 16:53:22 2013 +0000 @@ -0,0 +1,184 @@ +// -------------------------------------------------------------------------------------------------------------------- +// +// The MIT License (MIT) +// +// Copyright (c) 2012 Oystein Bjorke +// +// Permission is hereby granted, free of charge, to any person obtaining a +// copy of this software and associated documentation files (the +// "Software"), to deal in the Software without restriction, including +// without limitation the rights to use, copy, modify, merge, publish, +// distribute, sublicense, and/or sell copies of the Software, and to +// permit persons to whom the Software is furnished to do so, subject to +// the following conditions: +// +// The above copyright notice and this permission notice shall be included +// in all copies or substantial portions of the Software. +// +// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS +// OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF +// MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. +// IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY +// CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, +// TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE +// SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. +// +// +// Represents an angular axis for polar plots. +// +// -------------------------------------------------------------------------------------------------------------------- +namespace OxyPlot.Axes +{ + using System; + + /// + /// Represents an angular axis for polar plots. + /// + public class AngleAxis : LinearAxis + { + /// + /// Initializes a new instance of the class. + /// + public AngleAxis() + { + this.IsPanEnabled = false; + this.IsZoomEnabled = false; + this.MajorGridlineStyle = LineStyle.Solid; + this.MinorGridlineStyle = LineStyle.Solid; + this.StartAngle = 0; + this.EndAngle = 360; + } + + /// + /// Initializes a new instance of the class. + /// + /// + /// The minimum. + /// + /// + /// The maximum. + /// + /// + /// The major step. + /// + /// + /// The minor step. + /// + /// + /// The title. + /// + public AngleAxis( + double minimum = double.NaN, + double maximum = double.NaN, + double majorStep = double.NaN, + double minorStep = double.NaN, + string title = null) + : this() + { + this.Minimum = minimum; + this.Maximum = maximum; + this.MajorStep = majorStep; + this.MinorStep = minorStep; + this.Title = title; + this.StartAngle = 0; + this.EndAngle = 360; + } + + /// + /// Gets or sets the start angle (degrees). + /// + public double StartAngle { get; set; } + + /// + /// Gets or sets the end angle (degrees). + /// + public double EndAngle { get; set; } + + /// + /// Inverse transform the specified screen point. + /// + /// The x coordinate. + /// The y coordinate. + /// The y-axis. + /// + /// The data point. + /// + public override DataPoint InverseTransform(double x, double y, Axis yaxis) + { + throw new InvalidOperationException("Angle axis should always be the y-axis."); + } + + /// + /// Determines whether the axis is used for X/Y values. + /// + /// + /// true if it is an XY axis; otherwise, false . + /// + public override bool IsXyAxis() + { + return false; + } + + /// + /// Renders the axis on the specified render context. + /// + /// The render context. + /// The model. + /// The rendering order. + /// + public override void Render(IRenderContext rc, PlotModel model, AxisLayer axisLayer, int pass) + { + if (this.Layer != axisLayer) + { + return; + } + + var r = new AngleAxisRenderer(rc, model); + r.Render(this, pass); + } + + /// + /// Transforms the specified point to screen coordinates. + /// + /// + /// The x value (for the current axis). + /// + /// + /// The y value. + /// + /// + /// The y axis. + /// + /// + /// The transformed point. + /// + public override ScreenPoint Transform(double x, double y, Axis yaxis) + { + throw new InvalidOperationException("Angle axis should always be the y-axis."); + } + + /// + /// The update transform. + /// + /// + /// The bounds. + /// + internal override void UpdateTransform(OxyRect bounds) + { + double x0 = bounds.Left; + double x1 = bounds.Right; + double y0 = bounds.Bottom; + double y1 = bounds.Top; + + this.ScreenMin = new ScreenPoint(x0, y1); + this.ScreenMax = new ScreenPoint(x1, y0); + + double startAngle = this.StartAngle / 180 * Math.PI; + double endAngle = this.EndAngle / 180 * Math.PI; + + this.Scale = (endAngle - startAngle) / (this.ActualMaximum - this.ActualMinimum); + this.Offset = this.ActualMinimum - (startAngle / this.Scale); + } + + } +} \ No newline at end of file diff -r 88d699a65cc2 -r 5be8f2773237 External/OxyPlot/OxyPlot/Axes/Axis.cs --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/External/OxyPlot/OxyPlot/Axes/Axis.cs Sat Jun 08 16:53:22 2013 +0000 @@ -0,0 +1,1753 @@ +// -------------------------------------------------------------------------------------------------------------------- +// +// The MIT License (MIT) +// +// Copyright (c) 2012 Oystein Bjorke +// +// Permission is hereby granted, free of charge, to any person obtaining a +// copy of this software and associated documentation files (the +// "Software"), to deal in the Software without restriction, including +// without limitation the rights to use, copy, modify, merge, publish, +// distribute, sublicense, and/or sell copies of the Software, and to +// permit persons to whom the Software is furnished to do so, subject to +// the following conditions: +// +// The above copyright notice and this permission notice shall be included +// in all copies or substantial portions of the Software. +// +// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS +// OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF +// MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. +// IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY +// CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, +// TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE +// SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. +// +// +// Abstract base class for axes. +// +// -------------------------------------------------------------------------------------------------------------------- +namespace OxyPlot.Axes +{ + using System; + using System.Collections.Generic; + using System.Diagnostics.CodeAnalysis; + using System.Globalization; + + using OxyPlot.Series; + + /// + /// Provides an abstract base class for axes. + /// + public abstract class Axis : PlotElement + { + /// + /// Exponent function. + /// + protected static readonly Func Exponent = x => Math.Round(Math.Log(Math.Abs(x), 10)); + + /// + /// Mantissa function. http://en.wikipedia.org/wiki/Mantissa + /// + protected static readonly Func Mantissa = x => x / Math.Pow(10, Exponent(x)); + + /// + /// The offset. + /// + [SuppressMessage("StyleCop.CSharp.MaintainabilityRules", "SA1401:FieldsMustBePrivate", + Justification = "Reviewed. Suppression is OK here.")] + protected double offset; + + /// + /// The scale. + /// + [SuppressMessage("StyleCop.CSharp.MaintainabilityRules", "SA1401:FieldsMustBePrivate", + Justification = "Reviewed. Suppression is OK here.")] + protected double scale; + + /// + /// The position. + /// + private AxisPosition position; + + /// + /// Initializes a new instance of the class. + /// + protected Axis() + { + this.Position = AxisPosition.Left; + this.PositionTier = 0; + this.IsAxisVisible = true; + this.Layer = AxisLayer.BelowSeries; + + this.ViewMaximum = double.NaN; + this.ViewMinimum = double.NaN; + + this.AbsoluteMaximum = double.MaxValue; + this.AbsoluteMinimum = double.MinValue; + + this.Minimum = double.NaN; + this.Maximum = double.NaN; + this.MinorStep = double.NaN; + this.MajorStep = double.NaN; + + this.MinimumPadding = 0.01; + this.MaximumPadding = 0.01; + this.MinimumRange = 0; + + this.TickStyle = TickStyle.Outside; + this.TicklineColor = OxyColors.Black; + + this.AxislineStyle = LineStyle.None; + this.AxislineColor = OxyColors.Black; + this.AxislineThickness = 1.0; + + this.MajorGridlineStyle = LineStyle.None; + this.MajorGridlineColor = OxyColor.FromArgb(0x40, 0, 0, 0); + this.MajorGridlineThickness = 1; + + this.MinorGridlineStyle = LineStyle.None; + this.MinorGridlineColor = OxyColor.FromArgb(0x20, 0, 0, 0x00); + this.MinorGridlineThickness = 1; + + this.ExtraGridlineStyle = LineStyle.Solid; + this.ExtraGridlineColor = OxyColors.Black; + this.ExtraGridlineThickness = 1; + + this.ShowMinorTicks = true; + + this.MinorTickSize = 4; + this.MajorTickSize = 7; + + this.StartPosition = 0; + this.EndPosition = 1; + + this.TitlePosition = 0.5; + this.TitleFormatString = "{0} [{1}]"; + this.TitleClippingLength = 0.9; + this.TitleColor = null; + this.TitleFontSize = double.NaN; + this.TitleFontWeight = FontWeights.Normal; + this.ClipTitle = true; + + this.Angle = 0; + + this.IsZoomEnabled = true; + this.IsPanEnabled = true; + + this.FilterMinValue = double.MinValue; + this.FilterMaxValue = double.MaxValue; + this.FilterFunction = null; + + this.IntervalLength = 60; + + this.AxisTitleDistance = 4; + this.AxisTickToLabelDistance = 4; + } + + /// + /// Initializes a new instance of the class. + /// + /// + /// The position of the axis. + /// + /// + /// The minimum value. + /// + /// + /// The maximum value. + /// + /// + /// The axis title. + /// + protected Axis(AxisPosition pos, double minimum, double maximum, string title = null) + : this() + { + this.Position = pos; + this.Minimum = minimum; + this.Maximum = maximum; + + this.AbsoluteMaximum = double.NaN; + this.AbsoluteMinimum = double.NaN; + + this.Title = title; + } + + /// + /// Occurs when the axis has been changed (by zooming, panning or resetting). + /// + public event EventHandler AxisChanged; + + /// + /// Gets or sets the absolute maximum. This is only used for the UI control. It will not be possible to zoom/pan beyond this limit. + /// + /// The absolute maximum. + public double AbsoluteMaximum { get; set; } + + /// + /// Gets or sets the absolute minimum. This is only used for the UI control. It will not be possible to zoom/pan beyond this limit. + /// + /// The absolute minimum. + public double AbsoluteMinimum { get; set; } + + /// + /// Gets the actual culture. + /// + /// + /// The culture is defined in the parent PlotModel. + /// + public CultureInfo ActualCulture + { + get + { + return this.PlotModel != null ? this.PlotModel.ActualCulture : CultureInfo.CurrentCulture; + } + } + + /// + /// Gets or sets the actual major step. + /// + public double ActualMajorStep { get; protected set; } + + /// + /// Gets or sets the actual maximum value of the axis. + /// + /// + /// If ViewMaximum is not NaN, this value will be defined by ViewMaximum. + /// Otherwise, if Maximum is not NaN, this value will be defined by Maximum. + /// Otherwise, this value will be defined by the maximum (+padding) of the data. + /// + public double ActualMaximum { get; protected set; } + + /// + /// Gets or sets the actual minimum value of the axis. + /// + /// + /// If ViewMinimum is not NaN, this value will be defined by ViewMinimum. + /// Otherwise, if Minimum is not NaN, this value will be defined by Minimum. + /// Otherwise this value will be defined by the minimum (+padding) of the data. + /// + public double ActualMinimum { get; protected set; } + + /// + /// Gets or sets the maximum value of the data displayed on this axis. + /// + /// The data maximum. + public double DataMaximum { get; protected set; } + + /// + /// Gets or sets the minimum value of the data displayed on this axis. + /// + /// The data minimum. + public double DataMinimum { get; protected set; } + + /// + /// Gets or sets the actual minor step. + /// + public double ActualMinorStep { get; protected set; } + + /// + /// Gets or sets the actual string format being used. + /// + public string ActualStringFormat { get; protected set; } + + /// + /// Gets the actual title (including Unit if Unit is set). + /// + /// The actual title. + public string ActualTitle + { + get + { + if (this.Unit != null) + { + return string.Format(this.TitleFormatString, this.Title, this.Unit); + } + + return this.Title; + } + } + + /// + /// Gets or sets the angle for the axis values. + /// + public double Angle { get; set; } + + /// + /// Gets or sets the distance from axis tick to number label. + /// + /// The axis tick to label distance. + public double AxisTickToLabelDistance { get; set; } + + /// + /// Gets or sets the distance from axis number to axis title. + /// + /// The axis title distance. + public double AxisTitleDistance { get; set; } + + /// + /// Gets or sets the color of the axis line. + /// + public OxyColor AxislineColor { get; set; } + + /// + /// Gets or sets the axis line. + /// + public LineStyle AxislineStyle { get; set; } + + /// + /// Gets or sets the axis line. + /// + public double AxislineThickness { get; set; } + + /// + /// Gets or sets a value indicating whether to clip the axis title. + /// + /// + /// The default value is true. + /// + public bool ClipTitle { get; set; } + + /// + /// Gets or sets the end position of the axis on the plot area. This is a fraction from 0(bottom/left) to 1(top/right). + /// + public double EndPosition { get; set; } + + /// + /// Gets or sets the color of the extra gridlines. + /// + public OxyColor ExtraGridlineColor { get; set; } + + /// + /// Gets or sets the extra gridlines line style. + /// + public LineStyle ExtraGridlineStyle { get; set; } + + /// + /// Gets or sets the extra gridline thickness. + /// + public double ExtraGridlineThickness { get; set; } + + /// + /// Gets or sets the values for extra gridlines. + /// + public double[] ExtraGridlines { get; set; } + + /// + /// Gets or sets the filter function. + /// + /// The filter function. + public Func FilterFunction { get; set; } + + /// + /// Gets or sets the maximum value that can be shown using this axis. Values greater or equal to this value will not be shown. + /// + /// The filter max value. + public double FilterMaxValue { get; set; } + + /// + /// Gets or sets the minimum value that can be shown using this axis. Values smaller or equal to this value will not be shown. + /// + /// The filter min value. + public double FilterMinValue { get; set; } + + /// + /// Gets or sets the length of the interval (screen length). The available length of the axis will be divided by this length to get the approximate number of major intervals on the axis. The default value is 60. + /// + public double IntervalLength { get; set; } + + /// + /// Gets or sets a value indicating whether this axis is visible. + /// + public bool IsAxisVisible { get; set; } + + /// + /// Gets or sets a value indicating whether pan is enabled. + /// + public bool IsPanEnabled { get; set; } + + /// + /// Gets a value indicating whether this axis is reversed. It is reversed if StartPosition>EndPosition. + /// + public bool IsReversed + { + get + { + return this.StartPosition > this.EndPosition; + } + } + + /// + /// Gets or sets a value indicating whether zoom is enabled. + /// + public bool IsZoomEnabled { get; set; } + + /// + /// Gets or sets the key of the axis. This can be used to find an axis if you have defined multiple axes in a plot. + /// + public string Key { get; set; } + + /// + /// Gets or sets the layer. + /// + /// The layer. + public AxisLayer Layer { get; set; } + + /// + /// Gets or sets the color of the major gridline. + /// + public OxyColor MajorGridlineColor { get; set; } + + /// + /// Gets or sets the major gridline style. + /// + public LineStyle MajorGridlineStyle { get; set; } + + /// + /// Gets or sets the major gridline thickness. + /// + public double MajorGridlineThickness { get; set; } + + /// + /// Gets or sets the major step. (the interval between large ticks with numbers). + /// + public double MajorStep { get; set; } + + /// + /// Gets or sets the size of the major tick. + /// + public double MajorTickSize { get; set; } + + /// + /// Gets or sets the maximum value of the axis. + /// + public double Maximum { get; set; } + + /// + /// Gets or sets the 'padding' fraction of the maximum value. A value of 0.01 gives 1% more space on the maximum end of the axis. This property is not used if the Maximum property is set. + /// + public double MaximumPadding { get; set; } + + /// + /// Gets or sets the minimum value of the axis. + /// + public double Minimum { get; set; } + + /// + /// Gets or sets the 'padding' fraction of the minimum value. A value of 0.01 gives 1% more space on the minimum end of the axis. This property is not used if the Minimum property is set. + /// + public double MinimumPadding { get; set; } + + /// + /// Gets or sets the minimum range of the axis. Setting this property ensures that ActualMaximum-ActualMinimum > MinimumRange. + /// + public double MinimumRange { get; set; } + + /// + /// Gets or sets the color of the minor gridline. + /// + public OxyColor MinorGridlineColor { get; set; } + + /// + /// Gets or sets the minor gridline style. + /// + public LineStyle MinorGridlineStyle { get; set; } + + /// + /// Gets or sets the minor gridline thickness. + /// + public double MinorGridlineThickness { get; set; } + + /// + /// Gets or sets the minor step (the interval between small ticks without number). + /// + public double MinorStep { get; set; } + + /// + /// Gets or sets the size of the minor tick. + /// + public double MinorTickSize { get; set; } + + /// + /// Gets or sets the offset. This is used to transform between data and screen coordinates. + /// + public double Offset + { + get + { + return this.offset; + } + + protected set + { + this.offset = value; + } + } + + /// + /// Gets or sets the position of the axis. + /// + public AxisPosition Position + { + get + { + return this.position; + } + + set + { + this.position = value; + } + } + + /// + /// Gets or sets a value indicating whether the axis should be positioned on the zero-crossing of the related axis. + /// + public bool PositionAtZeroCrossing { get; set; } + + /// + /// Gets or sets the position tier which defines in which tier the axis is displayed. + /// + /// + /// The bigger the value the the further afar is the axis from the graph. + /// + public int PositionTier { get; set; } + + /// + /// Gets or sets the related axis. This is used for polar coordinate systems where the angle and magnitude axes are related. + /// + public Axis RelatedAxis { get; set; } + + /// + /// Gets or sets the scaling factor of the axis. This is used to transform between data and screen coordinates. + /// + public double Scale + { + get + { + return this.scale; + } + + protected set + { + this.scale = value; + } + } + + /// + /// Gets or sets the screen coordinate of the Maximum point on the axis. + /// + public ScreenPoint ScreenMax { get; protected set; } + + /// + /// Gets or sets the screen coordinate of the Minimum point on the axis. + /// + public ScreenPoint ScreenMin { get; protected set; } + + /// + /// Gets or sets a value indicating whether minor ticks should be shown. + /// + public bool ShowMinorTicks { get; set; } + + /// + /// Gets or sets the start position of the axis on the plot area. This is a fraction from 0(bottom/left) to 1(top/right). + /// + public double StartPosition { get; set; } + + /// + /// Gets or sets the string format used for formatting the axis values. + /// + public string StringFormat { get; set; } + + /// + /// Gets or sets the tick style (both for major and minor ticks). + /// + public TickStyle TickStyle { get; set; } + + /// + /// Gets or sets the color of the ticks (both major and minor ticks). + /// + public OxyColor TicklineColor { get; set; } + + /// + /// Gets or sets the title of the axis. + /// + public string Title { get; set; } + + /// + /// Gets or sets the length of the title clipping rectangle (fraction of the available length of the axis). + /// + /// + /// The default value is 0.9 + /// + public double TitleClippingLength { get; set; } + + /// + /// Gets or sets the color of the title. + /// + /// The color of the title. + /// + /// If TitleColor is null, the parent PlotModel's TextColor will be used. + /// + public OxyColor TitleColor { get; set; } + + /// + /// Gets or sets the title font. + /// + /// The title font. + public string TitleFont { get; set; } + + /// + /// Gets or sets the size of the title font. + /// + /// The size of the title font. + public double TitleFontSize { get; set; } + + /// + /// Gets or sets the title font weight. + /// + /// The title font weight. + public double TitleFontWeight { get; set; } + + /// + /// Gets or sets the format string used for formatting the title and unit when unit is defined. If unit is null, only Title is used. The default value is "{0} [{1}]", where {0} uses the Title and {1} uses the Unit. + /// + public string TitleFormatString { get; set; } + + /// + /// Gets or sets the position of the title (0.5 is in the middle). + /// + public double TitlePosition { get; set; } + + /// + /// Gets or sets the tool tip. + /// + /// The tool tip. + public string ToolTip { get; set; } + + /// + /// Gets or sets the unit of the axis. + /// + public string Unit { get; set; } + + /// + /// Gets or sets a value indicating whether to use superscript exponential format. This format will convert 1.5E+03 to 1.5·10^{3} and render the superscript properly If StringFormat is null, 1.0E+03 will be converted to 10^{3} + /// + public bool UseSuperExponentialFormat { get; set; } + + /// + /// Gets or sets the position tier max shift. + /// + /// The position tier max shift. + internal double PositionTierMaxShift { get; set; } + + /// + /// Gets or sets the position tier min shift. + /// + /// The position tier min shift. + internal double PositionTierMinShift { get; set; } + + /// + /// Gets or sets the size of the position tier. + /// + /// The size of the position tier. + internal double PositionTierSize { get; set; } + + /// + /// Gets the actual color of the title. + /// + /// The actual color of the title. + protected internal OxyColor ActualTitleColor + { + get + { + return this.TitleColor ?? this.PlotModel.TextColor; + } + } + + /// + /// Gets the actual title font. + /// + protected internal string ActualTitleFont + { + get + { + return this.TitleFont ?? this.PlotModel.DefaultFont; + } + } + + /// + /// Gets the actual size of the title font. + /// + /// The actual size of the title font. + protected internal double ActualTitleFontSize + { + get + { + return !double.IsNaN(this.TitleFontSize) ? this.TitleFontSize : this.ActualFontSize; + } + } + + /// + /// Gets the actual title font weight. + /// + protected internal double ActualTitleFontWeight + { + get + { + return !double.IsNaN(this.TitleFontWeight) ? this.TitleFontWeight : this.ActualFontWeight; + } + } + + /// + /// Gets or sets the current view's maximum. This value is used when the user zooms or pans. + /// + /// The view maximum. + protected double ViewMaximum { get; set; } + + /// + /// Gets or sets the current view's minimum. This value is used when the user zooms or pans. + /// + /// The view minimum. + protected double ViewMinimum { get; set; } + + /// + /// Transforms the specified point to screen coordinates. + /// + /// + /// The point. + /// + /// + /// The x axis. + /// + /// + /// The y axis. + /// + /// + /// The transformed point. + /// + public static ScreenPoint Transform(DataPoint p, Axis xaxis, Axis yaxis) + { + return xaxis.Transform(p.x, p.y, yaxis); + } + + /// + /// Transform the specified screen point to data coordinates. + /// + /// The point. + /// The x axis. + /// The y axis. + /// The data point. + public static DataPoint InverseTransform(ScreenPoint p, Axis xaxis, Axis yaxis) + { + return xaxis.InverseTransform(p.x, p.y, yaxis); + } + + /// + /// Transforms the specified point to screen coordinates. + /// + /// + /// The point. + /// + /// + /// The x axis. + /// + /// + /// The y axis. + /// + /// + /// The transformed point. + /// + public static ScreenPoint Transform(IDataPoint p, Axis xaxis, Axis yaxis) + { + return xaxis.Transform(p.X, p.Y, yaxis); + } + + /// + /// Coerces the actual maximum and minimum values. + /// + public virtual void CoerceActualMaxMin() + { + // Coerce actual minimum + if (double.IsNaN(this.ActualMinimum) || double.IsInfinity(this.ActualMinimum)) + { + this.ActualMinimum = 0; + } + + // Coerce actual maximum + if (double.IsNaN(this.ActualMaximum) || double.IsInfinity(this.ActualMaximum)) + { + this.ActualMaximum = 100; + } + + if (this.ActualMaximum <= this.ActualMinimum) + { + this.ActualMaximum = this.ActualMinimum + 100; + } + + // Coerce the minimum range + double range = this.ActualMaximum - this.ActualMinimum; + if (range < this.MinimumRange) + { + double avg = (this.ActualMaximum + this.ActualMinimum) * 0.5; + this.ActualMinimum = avg - (this.MinimumRange * 0.5); + this.ActualMaximum = avg + (this.MinimumRange * 0.5); + } + + if (this.AbsoluteMaximum <= this.AbsoluteMinimum) + { + throw new InvalidOperationException("AbsoluteMaximum should be larger than AbsoluteMinimum."); + } + } + + /// + /// Formats the value to be used on the axis. + /// + /// + /// The value. + /// + /// + /// The formatted value. + /// + public virtual string FormatValue(double x) + { + // The "SuperExponentialFormat" renders the number with superscript exponents. E.g. 10^2 + if (this.UseSuperExponentialFormat) + { + // if (x == 1 || x == 10 || x == -1 || x == -10) + // return x.ToString(); + double exp = Exponent(x); + double mantissa = Mantissa(x); + string fmt; + if (this.StringFormat == null) + { + fmt = Math.Abs(mantissa - 1.0) < 1e-6 ? "10^{{{1:0}}}" : "{0}·10^{{{1:0}}}"; + } + else + { + fmt = "{0:" + this.StringFormat + "}·10^{{{1:0}}}"; + } + + return string.Format(this.ActualCulture, fmt, mantissa, exp); + } + + string format = this.ActualStringFormat ?? this.StringFormat ?? string.Empty; + return x.ToString(format, this.ActualCulture); + } + + /// + /// Formats the value to be used by the tracker. + /// + /// + /// The value. + /// + /// + /// The formatted value. + /// + public virtual string FormatValueForTracker(double x) + { + return x.ToString(this.ActualCulture); + } + + /// + /// Gets the coordinates used to draw ticks and tick labels (numbers or category names). + /// + /// + /// The major label values. + /// + /// + /// The major tick values. + /// + /// + /// The minor tick values. + /// + public virtual void GetTickValues( + out IList majorLabelValues, out IList majorTickValues, out IList minorTickValues) + { + minorTickValues = CreateTickValues(this.ActualMinimum, this.ActualMaximum, this.ActualMinorStep); + majorTickValues = CreateTickValues(this.ActualMinimum, this.ActualMaximum, this.ActualMajorStep); + majorLabelValues = majorTickValues; + } + + /// + /// Gets the value from an axis coordinate, converts from double to the correct data type if necessary. e.g. DateTimeAxis returns the DateTime and CategoryAxis returns category strings. + /// + /// + /// The coordinate. + /// + /// + /// The value. + /// + public virtual object GetValue(double x) + { + return x; + } + + /// + /// Inverse transform the specified screen point. + /// + /// + /// The x coordinate. + /// + /// + /// The y coordinate. + /// + /// + /// The y-axis. + /// + /// + /// The data point. + /// + public virtual DataPoint InverseTransform(double x, double y, Axis yaxis) + { + return new DataPoint(this.InverseTransform(x), yaxis != null ? yaxis.InverseTransform(y) : 0); + } + + /// + /// Inverse transform the specified screen coordinate. This method can only be used with non-polar coordinate systems. + /// + /// + /// The screen coordinate. + /// + /// + /// The value. + /// + public virtual double InverseTransform(double sx) + { + return this.PostInverseTransform((sx / this.scale) + this.offset); + } + + /// + /// Determines whether this axis is horizontal. + /// + /// + /// true if this axis is horizontal; otherwise, false . + /// + public bool IsHorizontal() + { + return this.position == AxisPosition.Top || this.position == AxisPosition.Bottom; + } + + /// + /// Determines whether the specified value is valid. + /// + /// + /// The value. + /// + /// + /// true if the specified value is valid; otherwise, false . + /// + public virtual bool IsValidValue(double value) + { + return !double.IsNaN(value) && !double.IsInfinity(value) && value < this.FilterMaxValue + && value > this.FilterMinValue && (this.FilterFunction == null || this.FilterFunction(value)); + } + + /// + /// Determines whether this axis is vertical. + /// + /// + /// true if this axis is vertical; otherwise, false . + /// + public bool IsVertical() + { + return this.position == AxisPosition.Left || this.position == AxisPosition.Right; + } + + /// + /// Determines whether the axis is used for X/Y values. + /// + /// + /// true if it is an XY axis; otherwise, false . + /// + public abstract bool IsXyAxis(); + + /// + /// Measures the size of the axis (maximum axis label width/height). + /// + /// + /// The render context. + /// + /// + /// The size of the axis. + /// + public virtual OxySize Measure(IRenderContext rc) + { + IList majorTickValues; + IList minorTickValues; + IList majorLabelValues; + + this.GetTickValues(out majorLabelValues, out majorTickValues, out minorTickValues); + + var maximumTextSize = new OxySize(); + foreach (double v in majorLabelValues) + { + string s = this.FormatValue(v); + var size = rc.MeasureText(s, this.ActualFont, this.ActualFontSize, this.ActualFontWeight); + if (size.Width > maximumTextSize.Width) + { + maximumTextSize.Width = size.Width; + } + + if (size.Height > maximumTextSize.Height) + { + maximumTextSize.Height = size.Height; + } + } + + var labelTextSize = rc.MeasureText( + this.ActualTitle, this.ActualFont, this.ActualFontSize, this.ActualFontWeight); + + double width = 0; + double height = 0; + + if (this.IsHorizontal()) + { + switch (this.TickStyle) + { + case TickStyle.Outside: + height += this.MajorTickSize; + break; + case TickStyle.Crossing: + height += this.MajorTickSize * 0.75; + break; + } + + height += this.AxisTickToLabelDistance; + height += maximumTextSize.Height; + if (labelTextSize.Height > 0) + { + height += this.AxisTitleDistance; + height += labelTextSize.Height; + } + } + else + { + switch (this.TickStyle) + { + case TickStyle.Outside: + width += this.MajorTickSize; + break; + case TickStyle.Crossing: + width += this.MajorTickSize * 0.75; + break; + } + + width += this.AxisTickToLabelDistance; + width += maximumTextSize.Width; + if (labelTextSize.Height > 0) + { + width += this.AxisTitleDistance; + width += labelTextSize.Height; + } + } + + return new OxySize(width, height); + } + + /// + /// Pans the specified axis. + /// + /// + /// The previous point (screen coordinates). + /// + /// + /// The current point (screen coordinates). + /// + public virtual void Pan(ScreenPoint ppt, ScreenPoint cpt) + { + if (!this.IsPanEnabled) + { + return; + } + + bool isHorizontal = this.IsHorizontal(); + + double dsx = isHorizontal ? cpt.X - ppt.X : cpt.Y - ppt.Y; + this.Pan(dsx); + } + + /// + /// Pans the specified axis. + /// + /// + /// The delta. + /// + public virtual void Pan(double delta) + { + if (!this.IsPanEnabled) + { + return; + } + + double dx = delta / this.Scale; + + double newMinimum = this.ActualMinimum - dx; + double newMaximum = this.ActualMaximum - dx; + if (newMinimum < this.AbsoluteMinimum) + { + newMinimum = this.AbsoluteMinimum; + newMaximum = newMinimum + this.ActualMaximum - this.ActualMinimum; + } + + if (newMaximum > this.AbsoluteMaximum) + { + newMaximum = this.AbsoluteMaximum; + newMinimum = newMaximum - (this.ActualMaximum - this.ActualMinimum); + } + + this.ViewMinimum = newMinimum; + this.ViewMaximum = newMaximum; + this.UpdateActualMaxMin(); + + this.OnAxisChanged(new AxisChangedEventArgs(AxisChangeTypes.Pan)); + } + + /// + /// Renders the axis on the specified render context. + /// + /// The render context. + /// The model. + /// The rendering order. + /// The pass. + public virtual void Render(IRenderContext rc, PlotModel model, AxisLayer axisLayer, int pass) + { + var r = new HorizontalAndVerticalAxisRenderer(rc, model); + r.Render(this, pass); + } + + /// + /// Resets the user's modification (zooming/panning) to minimum and maximum of this axis. + /// + public virtual void Reset() + { + this.ViewMinimum = double.NaN; + this.ViewMaximum = double.NaN; + this.UpdateActualMaxMin(); + this.OnAxisChanged(new AxisChangedEventArgs(AxisChangeTypes.Reset)); + } + + /// + /// Returns a that represents this instance. + /// + /// + /// A that represents this instance. + /// + public override string ToString() + { + return string.Format( + CultureInfo.InvariantCulture, + "{0}({1}, {2}, {3}, {4})", + this.GetType().Name, + this.Position, + this.ActualMinimum, + this.ActualMaximum, + this.ActualMajorStep); + } + + /// + /// Transforms the specified point to screen coordinates. + /// + /// + /// The x value (for the current axis). + /// + /// + /// The y value. + /// + /// + /// The y axis. + /// + /// + /// The transformed point. + /// + public virtual ScreenPoint Transform(double x, double y, Axis yaxis) + { + if (yaxis == null) + { + throw new NullReferenceException("Y axis should not be null when transforming."); + } + + return new ScreenPoint(this.Transform(x), yaxis.Transform(y)); + } + + /// + /// Transforms the specified coordinate to screen coordinates. This method can only be used with non-polar coordinate systems. + /// + /// + /// The value. + /// + /// + /// The transformed value (screen coordinate). + /// + public virtual double Transform(double x) + { + return (x - this.offset) * this.scale; + + // return (this.PreTransform(x) - this.Offset) * this.Scale; + } + + /// + /// Zoom to the specified scale. + /// + /// + /// The new scale. + /// + public virtual void Zoom(double newScale) + { + double sx1 = this.Transform(this.ActualMaximum); + double sx0 = this.Transform(this.ActualMinimum); + + double sgn = Math.Sign(this.scale); + double mid = (this.ActualMaximum + this.ActualMinimum) / 2; + + double dx = (this.offset - mid) * this.scale; + this.scale = sgn * newScale; + this.offset = (dx / this.scale) + mid; + + double newMaximum = this.InverseTransform(sx1); + double newMinimum = this.InverseTransform(sx0); + + if (newMinimum < this.AbsoluteMinimum && newMaximum > this.AbsoluteMaximum) + { + newMinimum = this.AbsoluteMinimum; + newMaximum = this.AbsoluteMaximum; + } + else + { + if (newMinimum < this.AbsoluteMinimum) + { + double d = newMaximum - newMinimum; + newMinimum = this.AbsoluteMinimum; + newMaximum = this.AbsoluteMinimum + d; + if (newMaximum > this.AbsoluteMaximum) + { + newMaximum = this.AbsoluteMaximum; + } + } + else if (newMaximum > this.AbsoluteMaximum) + { + double d = newMaximum - newMinimum; + newMaximum = this.AbsoluteMaximum; + newMinimum = this.AbsoluteMaximum - d; + if (newMinimum < this.AbsoluteMinimum) + { + newMinimum = this.AbsoluteMinimum; + } + } + } + + this.ViewMaximum = newMaximum; + this.ViewMinimum = newMinimum; + this.UpdateActualMaxMin(); + } + + /// + /// Zooms the axis to the range [x0,x1]. + /// + /// + /// The new minimum. + /// + /// + /// The new maximum. + /// + public virtual void Zoom(double x0, double x1) + { + if (!this.IsZoomEnabled) + { + return; + } + + double newMinimum = Math.Max(Math.Min(x0, x1), this.AbsoluteMinimum); + double newMaximum = Math.Min(Math.Max(x0, x1), this.AbsoluteMaximum); + + this.ViewMinimum = newMinimum; + this.ViewMaximum = newMaximum; + this.UpdateActualMaxMin(); + + this.OnAxisChanged(new AxisChangedEventArgs(AxisChangeTypes.Zoom)); + } + + /// + /// Zooms the axis at the specified coordinate. + /// + /// + /// The zoom factor. + /// + /// + /// The coordinate to zoom at. + /// + public virtual void ZoomAt(double factor, double x) + { + if (!this.IsZoomEnabled) + { + return; + } + + double dx0 = (this.ActualMinimum - x) * this.scale; + double dx1 = (this.ActualMaximum - x) * this.scale; + this.scale *= factor; + + double newMinimum = Math.Max((dx0 / this.scale) + x, this.AbsoluteMinimum); + double newMaximum = Math.Min((dx1 / this.scale) + x, this.AbsoluteMaximum); + + this.ViewMinimum = newMinimum; + this.ViewMaximum = newMaximum; + this.UpdateActualMaxMin(); + + this.OnAxisChanged(new AxisChangedEventArgs(AxisChangeTypes.Zoom)); + } + + /// + /// Modifies the data range of the axis [DataMinimum,DataMaximum] to includes the specified value. + /// + /// + /// The value. + /// + public virtual void Include(double value) + { + if (!this.IsValidValue(value)) + { + return; + } + + this.DataMinimum = double.IsNaN(this.DataMinimum) ? value : Math.Min(this.DataMinimum, value); + this.DataMaximum = double.IsNaN(this.DataMaximum) ? value : Math.Max(this.DataMaximum, value); + } + + /// + /// Applies a transformation after the inverse transform of the value. This is used in logarithmic axis. + /// + /// + /// The value to transform. + /// + /// + /// The transformed value. + /// + internal virtual double PostInverseTransform(double x) + { + return x; + } + + /// + /// Applies a transformation before the transform the value. This is used in logarithmic axis. + /// + /// + /// The value to transform. + /// + /// + /// The transformed value. + /// + internal virtual double PreTransform(double x) + { + return x; + } + + /// + /// Resets the data maximum and minimum. + /// + internal virtual void ResetDataMaxMin() + { + this.DataMaximum = this.DataMinimum = double.NaN; + } + + /// + /// Updates the actual maximum and minimum values. If the user has zoomed/panned the axis, the internal ViewMaximum/ViewMinimum values will be used. If Maximum or Minimum have been set, these values will be used. Otherwise the maximum and minimum values of the series will be used, including the 'padding'. + /// + internal virtual void UpdateActualMaxMin() + { + // Use the minimum/maximum of the data as default + this.ActualMaximum = this.DataMaximum; + this.ActualMinimum = this.DataMinimum; + + double range = this.ActualMaximum - this.ActualMinimum; + double zeroRange = this.ActualMaximum > 0 ? this.ActualMaximum : 1; + + if (!double.IsNaN(this.ViewMaximum)) + { + // Override the ActualMaximum by the ViewMaximum value (from zoom/pan) + this.ActualMaximum = this.ViewMaximum; + } + else if (!double.IsNaN(this.Maximum)) + { + // Override the ActualMaximum by the Maximum value + this.ActualMaximum = this.Maximum; + } + else + { + if (range < double.Epsilon) + { + this.ActualMaximum += zeroRange * 0.5; + } + + if (!double.IsNaN(this.ActualMinimum) && !double.IsNaN(this.ActualMaximum)) + { + double x1 = this.PreTransform(this.ActualMaximum); + double x0 = this.PreTransform(this.ActualMinimum); + double dx = this.MaximumPadding * (x1 - x0); + this.ActualMaximum = this.PostInverseTransform(x1 + dx); + } + } + + if (!double.IsNaN(this.ViewMinimum)) + { + this.ActualMinimum = this.ViewMinimum; + } + else if (!double.IsNaN(this.Minimum)) + { + this.ActualMinimum = this.Minimum; + } + else + { + if (range < double.Epsilon) + { + this.ActualMinimum -= zeroRange * 0.5; + } + + if (!double.IsNaN(this.ActualMaximum) && !double.IsNaN(this.ActualMaximum)) + { + double x1 = this.PreTransform(this.ActualMaximum); + double x0 = this.PreTransform(this.ActualMinimum); + double dx = this.MinimumPadding * (x1 - x0); + this.ActualMinimum = this.PostInverseTransform(x0 - dx); + } + } + + this.CoerceActualMaxMin(); + } + + /// + /// Updates the axis with information from the plot series. + /// + /// + /// The series collection. + /// + /// + /// This is used by the category axis that need to know the number of series using the axis. + /// + internal virtual void UpdateFromSeries(IEnumerable series) + { + } + + /// + /// Updates the actual minor and major step intervals. + /// + /// + /// The plot area rectangle. + /// + internal virtual void UpdateIntervals(OxyRect plotArea) + { + double labelSize = this.IntervalLength; + double length = this.IsHorizontal() ? plotArea.Width : plotArea.Height; + length *= Math.Abs(this.EndPosition - this.StartPosition); + + this.ActualMajorStep = !double.IsNaN(this.MajorStep) + ? this.MajorStep + : this.CalculateActualInterval(length, labelSize); + + this.ActualMinorStep = !double.IsNaN(this.MinorStep) + ? this.MinorStep + : this.CalculateMinorInterval(this.ActualMajorStep); + + if (double.IsNaN(this.ActualMinorStep)) + { + this.ActualMinorStep = 2; + } + + if (double.IsNaN(this.ActualMajorStep)) + { + this.ActualMajorStep = 10; + } + + this.ActualStringFormat = this.StringFormat; + + // if (ActualStringFormat==null) + // { + // if (ActualMaximum > 1e6 || ActualMinimum < 1e-6) + // ActualStringFormat = "#.#e-0"; + // } + } + + /// + /// Updates the scale and offset properties of the transform from the specified boundary rectangle. + /// + /// + /// The bounds. + /// + internal virtual void UpdateTransform(OxyRect bounds) + { + double x0 = bounds.Left; + double x1 = bounds.Right; + double y0 = bounds.Bottom; + double y1 = bounds.Top; + + this.ScreenMin = new ScreenPoint(x0, y1); + this.ScreenMax = new ScreenPoint(x1, y0); + + // this.MidPoint = new ScreenPoint((x0 + x1) / 2, (y0 + y1) / 2); + + // if (this.Position == AxisPosition.Angle) + // { + // this.scale = 2 * Math.PI / (this.ActualMaximum - this.ActualMinimum); + // this.Offset = this.ActualMinimum; + // return; + // } + + // if (this.Position == AxisPosition.Magnitude) + // { + // this.ActualMinimum = 0; + // double r = Math.Min(Math.Abs(x1 - x0), Math.Abs(y1 - y0)); + // this.scale = 0.5 * r / (this.ActualMaximum - this.ActualMinimum); + // this.Offset = this.ActualMinimum; + // return; + // } + double a0 = this.IsHorizontal() ? x0 : y0; + double a1 = this.IsHorizontal() ? x1 : y1; + + double dx = a1 - a0; + a1 = a0 + (this.EndPosition * dx); + a0 = a0 + (this.StartPosition * dx); + this.ScreenMin = new ScreenPoint(a0, a1); + this.ScreenMax = new ScreenPoint(a1, a0); + + if (this.ActualMaximum - this.ActualMinimum < double.Epsilon) + { + this.ActualMaximum = this.ActualMinimum + 1; + } + + double max = this.PreTransform(this.ActualMaximum); + double min = this.PreTransform(this.ActualMinimum); + + double da = a0 - a1; + if (Math.Abs(da) > double.Epsilon) + { + this.offset = (a0 / da * max) - (a1 / da * min); + } + else + { + this.offset = 0; + } + + double range = max - min; + if (Math.Abs(range) > double.Epsilon) + { + this.scale = (a1 - a0) / range; + } + else + { + this.scale = 1; + } + } + + /// + /// Creates tick values at the specified interval. + /// + /// + /// The minimum coordinate. + /// + /// + /// The maximum coordinate. + /// + /// + /// The interval. + /// + /// + /// A list of tick values. + /// + protected static IList CreateTickValues(double min, double max, double step) + { + if (max <= min) + { + throw new ArgumentException("Axis: Maximum should be larger than minimum.", "max"); + } + + if (step <= 0) + { + throw new ArgumentException("Axis: Step cannot be zero or negative.", "step"); + } + + double x0 = Math.Round(min / step) * step; + int n = Math.Max((int)((max - min) / step), 1); + var values = new List(n); + + // Limit the maximum number of iterations (in case something is wrong with the step size) + int i = 0; + const int MaxIterations = 1000; + double x = x0; + double eps = step * 1e-3; + + while (x <= max + eps && i < MaxIterations) + { + x = x0 + (i * step); + i++; + if (x >= min - eps && x <= max + eps) + { + x = x.RemoveNoise(); + values.Add(x); + } + } + + return values; + } + + /// + /// Calculates the actual interval. + /// + /// + /// Size of the available area. + /// + /// + /// Maximum length of the intervals. + /// + /// + /// The calculate actual interval. + /// + protected virtual double CalculateActualInterval(double availableSize, double maxIntervalSize) + { + return this.CalculateActualInterval(availableSize, maxIntervalSize, this.ActualMaximum - this.ActualMinimum); + } + + // alternative algorithm not in use + /* private double CalculateActualIntervalOldAlgorithm(double availableSize, double maxIntervalSize) + { + const int minimumTags = 5; + const int maximumTags = 20; + var numberOfTags = (int) (availableSize/maxIntervalSize); + double range = ActualMaximum - ActualMinimum; + double interval = range/numberOfTags; + const int k1 = 10; + interval = Math.Log10(interval/k1); + interval = Math.Ceiling(interval); + interval = Math.Pow(10, interval)*k1; + + if (range/interval > maximumTags) interval *= 5; + if (range/interval < minimumTags) interval *= 0.5; + + if (interval <= 0) interval = 1; + return interval; + }*/ + + // === + // the following algorithm is from + // System.Windows.Controls.DataVisualization.Charting.LinearAxis.cs + + // (c) Copyright Microsoft Corporation. + // This source is subject to the Microsoft Public License (MIT). + // Please see http://go.microsoft.com/fwlink/?LinkID=131993 for details. + // All other rights reserved. + + /// + /// Returns the actual interval to use to determine which values are displayed in the axis. + /// + /// + /// The available size. + /// + /// + /// The maximum interval size. + /// + /// + /// The range. + /// + /// + /// Actual interval to use to determine which values are displayed in the axis. + /// + protected double CalculateActualInterval(double availableSize, double maxIntervalSize, double range) + { + if (availableSize <= 0) + { + return maxIntervalSize; + } + + Func exponent = x => Math.Ceiling(Math.Log(x, 10)); + Func mantissa = x => x / Math.Pow(10, exponent(x) - 1); + + // reduce intervals for horizontal axis. + // double maxIntervals = Orientation == AxisOrientation.x ? MaximumAxisIntervalsPer200Pixels * 0.8 : MaximumAxisIntervalsPer200Pixels; + // real maximum interval count + double maxIntervalCount = availableSize / maxIntervalSize; + + range = Math.Abs(range); + double interval = Math.Pow(10, exponent(range)); + double tempInterval = interval; + + // decrease interval until interval count becomes less than maxIntervalCount + while (true) + { + var m = (int)mantissa(tempInterval); + if (m == 5) + { + // reduce 5 to 2 + tempInterval = (tempInterval / 2.5).RemoveNoiseFromDoubleMath(); + } + else if (m == 2 || m == 1 || m == 10) + { + // reduce 2 to 1, 10 to 5, 1 to 0.5 + tempInterval = (tempInterval / 2.0).RemoveNoiseFromDoubleMath(); + } + else + { + tempInterval = (tempInterval / 2.0).RemoveNoiseFromDoubleMath(); + } + + if (range / tempInterval > maxIntervalCount) + { + break; + } + + if (double.IsNaN(tempInterval) || double.IsInfinity(tempInterval)) + { + break; + } + + interval = tempInterval; + } + + return interval; + } + + /// + /// The calculate minor interval. + /// + /// + /// The major interval. + /// + /// + /// The minor interval. + /// + protected double CalculateMinorInterval(double majorInterval) + { + // if major interval is 100, the minor interval will be 20. + return majorInterval / 5; + + // The following obsolete code divided major intervals into 4 minor intervals, unless the major interval's mantissa was 5. + // e.g. Major interval 100 => minor interval 25. + + // Func exponent = x => Math.Ceiling(Math.Log(x, 10)); + // Func mantissa = x => x / Math.Pow(10, exponent(x) - 1); + // var m = (int)mantissa(majorInterval); + // switch (m) + // { + // case 5: + // return majorInterval / 5; + // default: + // return majorInterval / 4; + // } + } + + /// + /// Raises the AxisChanged event. + /// + /// + /// The instance containing the event data. + /// + protected virtual void OnAxisChanged(AxisChangedEventArgs args) + { + this.UpdateActualMaxMin(); + + var handler = this.AxisChanged; + if (handler != null) + { + handler(this, args); + } + } + } +} \ No newline at end of file diff -r 88d699a65cc2 -r 5be8f2773237 External/OxyPlot/OxyPlot/Axes/AxisChangeTypes.cs --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/External/OxyPlot/OxyPlot/Axes/AxisChangeTypes.cs Sat Jun 08 16:53:22 2013 +0000 @@ -0,0 +1,52 @@ +// -------------------------------------------------------------------------------------------------------------------- +// +// The MIT License (MIT) +// +// Copyright (c) 2012 Oystein Bjorke +// +// Permission is hereby granted, free of charge, to any person obtaining a +// copy of this software and associated documentation files (the +// "Software"), to deal in the Software without restriction, including +// without limitation the rights to use, copy, modify, merge, publish, +// distribute, sublicense, and/or sell copies of the Software, and to +// permit persons to whom the Software is furnished to do so, subject to +// the following conditions: +// +// The above copyright notice and this permission notice shall be included +// in all copies or substantial portions of the Software. +// +// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS +// OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF +// MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. +// IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY +// CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, +// TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE +// SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. +// +// +// Change types of the Axis.AxisChanged event. +// +// -------------------------------------------------------------------------------------------------------------------- +namespace OxyPlot.Axes +{ + /// + /// Specifies change types for the event. + /// + public enum AxisChangeTypes + { + /// + /// The axis was zoomed by the user. + /// + Zoom, + + /// + /// The axis was panned by the user. + /// + Pan, + + /// + /// The axis zoom/pan was reset by the user. + /// + Reset + } +} \ No newline at end of file diff -r 88d699a65cc2 -r 5be8f2773237 External/OxyPlot/OxyPlot/Axes/AxisChangedEventArgs.cs --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/External/OxyPlot/OxyPlot/Axes/AxisChangedEventArgs.cs Sat Jun 08 16:53:22 2013 +0000 @@ -0,0 +1,57 @@ +// -------------------------------------------------------------------------------------------------------------------- +// +// The MIT License (MIT) +// +// Copyright (c) 2012 Oystein Bjorke +// +// Permission is hereby granted, free of charge, to any person obtaining a +// copy of this software and associated documentation files (the +// "Software"), to deal in the Software without restriction, including +// without limitation the rights to use, copy, modify, merge, publish, +// distribute, sublicense, and/or sell copies of the Software, and to +// permit persons to whom the Software is furnished to do so, subject to +// the following conditions: +// +// The above copyright notice and this permission notice shall be included +// in all copies or substantial portions of the Software. +// +// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS +// OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF +// MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. +// IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY +// CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, +// TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE +// SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. +// +// +// EventArgs for the Axis.AxisChanged event. +// +// -------------------------------------------------------------------------------------------------------------------- +namespace OxyPlot.Axes +{ + using System; + + /// + /// Provides additional data for the event. + /// + public class AxisChangedEventArgs : EventArgs + { + /// + /// Initializes a new instance of the class. + /// + /// + /// Type of the change. + /// + public AxisChangedEventArgs(AxisChangeTypes changeType) + { + this.ChangeType = changeType; + } + + /// + /// Gets or sets the type of the change. + /// + /// The type of the change. + public AxisChangeTypes ChangeType { get; set; } + + } +} \ No newline at end of file diff -r 88d699a65cc2 -r 5be8f2773237 External/OxyPlot/OxyPlot/Axes/AxisLayer.cs --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/External/OxyPlot/OxyPlot/Axes/AxisLayer.cs Sat Jun 08 16:53:22 2013 +0000 @@ -0,0 +1,47 @@ +// -------------------------------------------------------------------------------------------------------------------- +// +// The MIT License (MIT) +// +// Copyright (c) 2012 Oystein Bjorke +// +// Permission is hereby granted, free of charge, to any person obtaining a +// copy of this software and associated documentation files (the +// "Software"), to deal in the Software without restriction, including +// without limitation the rights to use, copy, modify, merge, publish, +// distribute, sublicense, and/or sell copies of the Software, and to +// permit persons to whom the Software is furnished to do so, subject to +// the following conditions: +// +// The above copyright notice and this permission notice shall be included +// in all copies or substantial portions of the Software. +// +// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS +// OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF +// MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. +// IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY +// CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, +// TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE +// SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. +// +// +// Axis layer position. +// +// -------------------------------------------------------------------------------------------------------------------- +namespace OxyPlot.Axes +{ + /// + /// Specifies the layer position of an . + /// + public enum AxisLayer + { + /// + /// Below all series. + /// + BelowSeries, + + /// + /// Above all series. + /// + AboveSeries + } +} \ No newline at end of file diff -r 88d699a65cc2 -r 5be8f2773237 External/OxyPlot/OxyPlot/Axes/AxisPosition.cs --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/External/OxyPlot/OxyPlot/Axes/AxisPosition.cs Sat Jun 08 16:53:22 2013 +0000 @@ -0,0 +1,62 @@ +// -------------------------------------------------------------------------------------------------------------------- +// +// The MIT License (MIT) +// +// Copyright (c) 2012 Oystein Bjorke +// +// Permission is hereby granted, free of charge, to any person obtaining a +// copy of this software and associated documentation files (the +// "Software"), to deal in the Software without restriction, including +// without limitation the rights to use, copy, modify, merge, publish, +// distribute, sublicense, and/or sell copies of the Software, and to +// permit persons to whom the Software is furnished to do so, subject to +// the following conditions: +// +// The above copyright notice and this permission notice shall be included +// in all copies or substantial portions of the Software. +// +// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS +// OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF +// MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. +// IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY +// CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, +// TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE +// SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. +// +// +// Axis positions. +// +// -------------------------------------------------------------------------------------------------------------------- +namespace OxyPlot.Axes +{ + /// + /// Specifies the position of an . + /// + public enum AxisPosition + { + /// + /// No position. + /// + None, + + /// + /// Left of the plot area. + /// + Left, + + /// + /// Right of the plot area. + /// + Right, + + /// + /// Top of the plot area. + /// + Top, + + /// + /// Bottom of the plot area. + /// + Bottom + } +} \ No newline at end of file diff -r 88d699a65cc2 -r 5be8f2773237 External/OxyPlot/OxyPlot/Axes/CategoryAxis.cs --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/External/OxyPlot/OxyPlot/Axes/CategoryAxis.cs Sat Jun 08 16:53:22 2013 +0000 @@ -0,0 +1,501 @@ +// -------------------------------------------------------------------------------------------------------------------- +// +// The MIT License (MIT) +// +// Copyright (c) 2012 Oystein Bjorke +// +// Permission is hereby granted, free of charge, to any person obtaining a +// copy of this software and associated documentation files (the +// "Software"), to deal in the Software without restriction, including +// without limitation the rights to use, copy, modify, merge, publish, +// distribute, sublicense, and/or sell copies of the Software, and to +// permit persons to whom the Software is furnished to do so, subject to +// the following conditions: +// +// The above copyright notice and this permission notice shall be included +// in all copies or substantial portions of the Software. +// +// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS +// OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF +// MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. +// IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY +// CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, +// TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE +// SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. +// +// +// Represents a category axes. +// +// -------------------------------------------------------------------------------------------------------------------- +namespace OxyPlot.Axes +{ + using System.Collections; + using System.Collections.Generic; + using System.Globalization; + using System.Linq; + + using OxyPlot.Series; + + /// + /// Represents a category axis. + /// + /// + /// The category axis is using the label collection indices as the coordinate. If you have 5 categories in the Labels collection, the categories will be placed at coordinates 0 to 4. The range of the axis will be from -0.5 to 4.5 (excl. padding). + /// + public class CategoryAxis : LinearAxis + { + /// + /// Initializes a new instance of the class. + /// + public CategoryAxis() + { + this.Labels = new List(); + this.TickStyle = TickStyle.Outside; + this.Position = AxisPosition.Bottom; + this.MinimumPadding = 0; + this.MaximumPadding = 0; + this.MajorStep = 1; + this.GapWidth = 1; + } + + /// + /// Initializes a new instance of the class. + /// + /// The position. + /// The title. + /// The categories. + public CategoryAxis(AxisPosition position, string title = null, params string[] categories) + : this(title, categories) + { + this.Position = position; + } + + /// + /// Initializes a new instance of the class. + /// + /// + /// The title. + /// + /// + /// The categories. + /// + public CategoryAxis(string title, params string[] categories) + : this() + { + this.Title = title; + if (categories != null) + { + foreach (var c in categories) + { + this.Labels.Add(c); + } + } + } + + /// + /// Gets or sets the gap width. + /// + /// + /// The default value is 1.0 (100%). The gap width is given as a fraction of the total width/height of the items in a category. + /// + public double GapWidth { get; set; } + + /// + /// Gets or sets a value indicating whether the ticks are centered. If this is false, ticks will be drawn between each category. If this is true, ticks will be drawn in the middle of each category. + /// + public bool IsTickCentered { get; set; } + + /// + /// Gets or sets the items source (used to update the Labels collection). + /// + /// + /// The items source. + /// + public IEnumerable ItemsSource { get; set; } + + /// + /// Gets or sets the data field for the labels. + /// + public string LabelField { get; set; } + + /// + /// Gets or sets the labels collection. + /// + public IList Labels { get; set; } + + /// + /// Gets or sets the current offset of the bars (not used for stacked bar series). + /// + internal double[] BarOffset { get; set; } + + /// + /// Gets or sets the max value per StackIndex and Label (only used for stacked bar series). + /// + internal double[,] MaxValue { get; set; } + + /// + /// Gets or sets the maximal width of all labels + /// + internal double MaxWidth { get; set; } + + /// + /// Gets or sets the min value per StackIndex and Label (only used for stacked bar series). + /// + internal double[,] MinValue { get; set; } + + /// + /// Gets or sets per StackIndex and Label the base value for negative values of stacked bar series. + /// + internal double[,] NegativeBaseValues { get; set; } + + /// + /// Gets or sets per StackIndex and Label the base value for positive values of stacked bar series. + /// + internal double[,] PositiveBaseValues { get; set; } + + /// + /// Gets or sets the StackIndexMapping. The mapping indicates to which rank a specific stack index belongs. + /// + internal Dictionary StackIndexMapping { get; set; } + + /// + /// Gets or sets the offset of the bars per StackIndex and Label (only used for stacked bar series). + /// + internal double[,] StackedBarOffset { get; set; } + + /// + /// Gets or sets sum of the widths of the single bars per label. This is used to find the bar width of BarSeries + /// + internal double[] TotalWidthPerCategory { get; set; } + + /// + /// Fills the specified array. + /// + /// + /// The array. + /// + /// + /// The value. + /// + public static void Fill(double[] array, double value) + { + for (var i = 0; i < array.Length; i++) + { + array[i] = value; + } + } + + /// + /// Fills the specified array. + /// + /// + /// The array. + /// + /// + /// The value. + /// + public static void Fill(double[,] array, double value) + { + for (var i = 0; i < array.GetLength(0); i++) + { + for (var j = 0; j < array.GetLength(1); j++) + { + array[i, j] = value; + } + } + } + + /// + /// Formats the value to be used on the axis. + /// + /// + /// The value. + /// + /// + /// The formatted value. + /// + public override string FormatValue(double x) + { + var index = (int)x; + if (this.Labels != null && index >= 0 && index < this.Labels.Count) + { + return this.Labels[index]; + } + + return null; + } + + /// + /// Formats the value to be used by the tracker. + /// + /// + /// The value. + /// + /// + /// The formatted value. + /// + public override string FormatValueForTracker(double x) + { + return this.FormatValue(x); + } + + /// + /// Gets the category value. + /// + /// + /// Index of the category. + /// + /// + /// Index of the stack. + /// + /// + /// Actual width of the bar. + /// + /// + /// The get category value. + /// + public double GetCategoryValue(int categoryIndex, int stackIndex, double actualBarWidth) + { + var offsetBegin = this.StackedBarOffset[stackIndex, categoryIndex]; + var offsetEnd = this.StackedBarOffset[stackIndex + 1, categoryIndex]; + return categoryIndex - 0.5 + ((offsetEnd + offsetBegin - actualBarWidth) * 0.5); + } + + /// + /// Gets the category value. + /// + /// + /// Index of the category. + /// + /// + /// The get category value. + /// + public double GetCategoryValue(int categoryIndex) + { + return categoryIndex - 0.5 + this.BarOffset[categoryIndex]; + } + + /// + /// Gets the coordinates used to draw ticks and tick labels (numbers or category names). + /// + /// + /// The major label values. + /// + /// + /// The major tick values. + /// + /// + /// The minor tick values. + /// + public override void GetTickValues( + out IList majorLabelValues, out IList majorTickValues, out IList minorTickValues) + { + base.GetTickValues(out majorLabelValues, out majorTickValues, out minorTickValues); + minorTickValues.Clear(); + + if (!this.IsTickCentered) + { + // Subtract 0.5 from the label values to get the tick values. + // Add one extra tick at the end. + var mv = new List(majorLabelValues.Count); + mv.AddRange(majorLabelValues.Select(v => v - 0.5)); + if (mv.Count > 0) + { + mv.Add(mv[mv.Count - 1] + 1); + } + + majorTickValues = mv; + } + } + + /// + /// Gets the value from an axis coordinate, converts from double to the correct data type if necessary. e.g. DateTimeAxis returns the DateTime and CategoryAxis returns category strings. + /// + /// + /// The coordinate. + /// + /// + /// The value. + /// + public override object GetValue(double x) + { + return this.FormatValue(x); + } + + /// + /// Updates the actual maximum and minimum values. If the user has zoomed/panned the axis, the internal ViewMaximum/ViewMinimum values will be used. If Maximum or Minimum have been set, these values will be used. Otherwise the maximum and minimum values of the series will be used, including the 'padding'. + /// + internal override void UpdateActualMaxMin() + { + // Update the DataMinimum/DataMaximum from the number of categories + this.Include(-0.5); + + if (this.Labels != null && this.Labels.Count > 0) + { + this.Include((this.Labels.Count - 1) + 0.5); + } + else + { + this.Include(0.5); + } + + base.UpdateActualMaxMin(); + + this.MinorStep = 1; + } + + /// + /// Updates the axis with information from the plot series. + /// + /// + /// The series collection. + /// + /// + /// This is used by the category axis that need to know the number of series using the axis. + /// + internal override void UpdateFromSeries(IEnumerable series) + { + if (this.Labels.Count == 0) + { + this.TotalWidthPerCategory = null; + this.MaxWidth = double.NaN; + this.BarOffset = null; + this.StackedBarOffset = null; + this.StackIndexMapping = null; + this.PositiveBaseValues = null; + this.NegativeBaseValues = null; + this.MaxValue = null; + this.MinValue = null; + + return; + } + + this.TotalWidthPerCategory = new double[this.Labels.Count]; + + var usedSeries = series.Where(s => s.IsUsing(this)).ToList(); + + // Add width of stacked series + var categorizedSeries = usedSeries.OfType().ToList(); + var stackedSeries = categorizedSeries.OfType().Where(s => s.IsStacked).ToList(); + var stackIndices = stackedSeries.Select(s => s.StackGroup).Distinct().ToList(); + var stackRankBarWidth = new Dictionary(); + for (var j = 0; j < stackIndices.Count; j++) + { + var maxBarWidth = + stackedSeries.Where(s => s.StackGroup == stackIndices[j]).Select( + s => ((CategorizedSeries)s).GetBarWidth()).Concat(new[] { 0.0 }).Max(); + for (var i = 0; i < this.Labels.Count; i++) + { + int k = 0; + if ( + stackedSeries.SelectMany(s => ((CategorizedSeries)s).GetItems()).Any( + item => item.GetCategoryIndex(k++) == i)) + { + this.TotalWidthPerCategory[i] += maxBarWidth; + } + } + + stackRankBarWidth[j] = maxBarWidth; + } + + // Add width of unstacked series + var unstackedBarSeries = + categorizedSeries.Where(s => !(s is IStackableSeries) || !((IStackableSeries)s).IsStacked).ToList(); + foreach (var s in unstackedBarSeries) + { + for (var i = 0; i < this.Labels.Count; i++) + { + int j = 0; + var numberOfItems = s.GetItems().Count(item => item.GetCategoryIndex(j++) == i); + this.TotalWidthPerCategory[i] += s.GetBarWidth() * numberOfItems; + } + } + + this.MaxWidth = this.TotalWidthPerCategory.Max(); + + // Calculate BarOffset and StackedBarOffset + this.BarOffset = new double[this.Labels.Count]; + this.StackedBarOffset = new double[stackIndices.Count + 1, this.Labels.Count]; + + var factor = 0.5 / (1 + this.GapWidth) / this.MaxWidth; + for (var i = 0; i < this.Labels.Count; i++) + { + this.BarOffset[i] = 0.5 - (this.TotalWidthPerCategory[i] * factor); + } + + for (var j = 0; j <= stackIndices.Count; j++) + { + for (var i = 0; i < this.Labels.Count; i++) + { + int k = 0; + if ( + stackedSeries.SelectMany(s => ((CategorizedSeries)s).GetItems()).All( + item => item.GetCategoryIndex(k++) != i)) + { + continue; + } + + this.StackedBarOffset[j, i] = this.BarOffset[i]; + if (j < stackIndices.Count) + { + this.BarOffset[i] += stackRankBarWidth[j] / (1 + this.GapWidth) / this.MaxWidth; + } + } + } + + stackIndices.Sort(); + this.StackIndexMapping = new Dictionary(); + for (var i = 0; i < stackIndices.Count; i++) + { + this.StackIndexMapping.Add(stackIndices[i], i); + } + + this.PositiveBaseValues = new double[stackIndices.Count, this.Labels.Count]; + Fill(this.PositiveBaseValues, double.NaN); + this.NegativeBaseValues = new double[stackIndices.Count, this.Labels.Count]; + Fill(this.NegativeBaseValues, double.NaN); + + this.MaxValue = new double[stackIndices.Count, this.Labels.Count]; + Fill(this.MaxValue, double.NaN); + this.MinValue = new double[stackIndices.Count, this.Labels.Count]; + Fill(this.MinValue, double.NaN); + } + + /// + /// Creates Labels list if no labels were set + /// + /// + /// The list of series which are rendered + /// + internal void UpdateLabels(IEnumerable series) + { + if (this.ItemsSource != null) + { + this.Labels.Clear(); + ReflectionHelper.FillList(this.ItemsSource, this.LabelField, this.Labels); + } + + if (this.Labels.Count == 0) + { + foreach (var s in series) + { + if (!s.IsUsing(this)) + { + continue; + } + + var bsb = s as CategorizedSeries; + if (bsb != null) + { + int max = bsb.GetItems().Count; + while (this.Labels.Count < max) + { + this.Labels.Add((this.Labels.Count + 1).ToString(CultureInfo.InvariantCulture)); + } + } + } + } + } + + } +} \ No newline at end of file diff -r 88d699a65cc2 -r 5be8f2773237 External/OxyPlot/OxyPlot/Axes/ColorAxis.cs --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/External/OxyPlot/OxyPlot/Axes/ColorAxis.cs Sat Jun 08 16:53:22 2013 +0000 @@ -0,0 +1,283 @@ +// -------------------------------------------------------------------------------------------------------------------- +// +// The MIT License (MIT) +// +// Copyright (c) 2012 Oystein Bjorke +// +// Permission is hereby granted, free of charge, to any person obtaining a +// copy of this software and associated documentation files (the +// "Software"), to deal in the Software without restriction, including +// without limitation the rights to use, copy, modify, merge, publish, +// distribute, sublicense, and/or sell copies of the Software, and to +// permit persons to whom the Software is furnished to do so, subject to +// the following conditions: +// +// The above copyright notice and this permission notice shall be included +// in all copies or substantial portions of the Software. +// +// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS +// OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF +// MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. +// IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY +// CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, +// TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE +// SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. +// +// +// The color axis. +// +// -------------------------------------------------------------------------------------------------------------------- +namespace OxyPlot.Axes +{ + using System; + using System.Collections.Generic; + + /// + /// Represents a color axis. + /// + public class ColorAxis : Axis + { + /// + /// Initializes a new instance of the class. + /// + public ColorAxis() + { + this.Position = AxisPosition.None; + this.IsPanEnabled = false; + this.IsZoomEnabled = false; + } + + /// + /// Gets or sets the color of values above the maximum value. + /// + /// The color of the high values. + public OxyColor HighColor { get; set; } + + /// + /// Gets or sets the color of values below the minimum value. + /// + /// The color of the low values. + public OxyColor LowColor { get; set; } + + /// + /// Gets or sets the palette. + /// + /// The palette. + public OxyPalette Palette { get; set; } + + /// + /// Gets the color. + /// + /// + /// The color map index (less than NumberOfEntries). + /// + /// + /// The color. + /// + public OxyColor GetColor(int paletteIndex) + { + if (paletteIndex == 0) + { + return this.LowColor; + } + + if (paletteIndex == this.Palette.Colors.Count + 1) + { + return this.HighColor; + } + + return this.Palette.Colors[paletteIndex - 1]; + } + + /// + /// Gets the color for the specified value. + /// + /// + /// The value. + /// + /// + /// The color. + /// + public OxyColor GetColor(double value) + { + return this.GetColor(this.GetPaletteIndex(value)); + } + + /// + /// Gets the colors. + /// + /// The colors. + public IEnumerable GetColors() + { + yield return this.LowColor; + foreach (var color in this.Palette.Colors) + { + yield return color; + } + + yield return this.HighColor; + } + + /// + /// Gets the palette index of the specified value. + /// + /// + /// The value. + /// + /// + /// The palette index. + /// + /// + /// If the value is less than minimum, 0 is returned. If the value is greater than maximum, Palette.Colors.Count+1 is returned. + /// + public int GetPaletteIndex(double value) + { + if (this.LowColor != null && value < this.Minimum) + { + return 0; + } + + if (this.HighColor != null && value > this.Maximum) + { + return this.Palette.Colors.Count + 1; + } + + int index = 1 + (int)((value - this.ActualMinimum) / (this.ActualMaximum - this.ActualMinimum) * this.Palette.Colors.Count); + + if (index < 1) + { + index = 1; + } + + if (index > this.Palette.Colors.Count) + { + index = this.Palette.Colors.Count; + } + + return index; + } + + /// + /// Determines whether the axis is used for X/Y values. + /// + /// + /// true if it is an XY axis; otherwise, false . + /// + public override bool IsXyAxis() + { + return false; + } + + /// + /// Renders the axis on the specified render context. + /// + /// The render context. + /// The model. + /// The rendering order. + /// The render pass. + public override void Render(IRenderContext rc, PlotModel model, AxisLayer axisLayer, int pass) + { + if (this.Position == AxisPosition.None) + { + return; + } + + if (pass == 0) + { + double left = model.PlotArea.Left; + double top = model.PlotArea.Top; + double width = this.MajorTickSize - 2; + double height = this.MajorTickSize - 2; + + switch (this.Position) + { + case AxisPosition.Left: + left = model.PlotArea.Left - this.PositionTierMinShift - width; + top = model.PlotArea.Top; + break; + case AxisPosition.Right: + left = model.PlotArea.Right + this.PositionTierMinShift; + top = model.PlotArea.Top; + break; + case AxisPosition.Top: + left = model.PlotArea.Left; + top = model.PlotArea.Top - this.PositionTierMinShift - height; + break; + case AxisPosition.Bottom: + left = model.PlotArea.Left; + top = model.PlotArea.Bottom + this.PositionTierMinShift; + break; + } + + Action drawColorRect = (ylow, yhigh, color) => + { + double ymin = Math.Min(ylow, yhigh); + double ymax = Math.Max(ylow, yhigh); + rc.DrawRectangle( + this.IsHorizontal() + ? new OxyRect(ymin, top, ymax - ymin, height) + : new OxyRect(left, ymin, width, ymax - ymin), + color, + null); + }; + + int n = this.Palette.Colors.Count; + for (int i = 0; i < n; i++) + { + double ylow = this.Transform(this.GetLowValue(i)); + double yhigh = this.Transform(this.GetHighValue(i)); + drawColorRect(ylow, yhigh, this.Palette.Colors[i]); + } + + double highLowLength = 10; + if (this.IsHorizontal()) + { + highLowLength *= -1; + } + + if (this.LowColor != null) + { + double ylow = this.Transform(this.ActualMinimum); + drawColorRect(ylow, ylow + highLowLength, this.LowColor); + } + + if (this.HighColor != null) + { + double yhigh = this.Transform(this.ActualMaximum); + drawColorRect(yhigh, yhigh - highLowLength, this.HighColor); + } + } + + base.Render(rc, model, axisLayer, pass); + } + + /// + /// Gets the high value of the specified palette index. + /// + /// + /// Index of the palette. + /// + /// + /// The value. + /// + protected double GetHighValue(int paletteIndex) + { + return this.GetLowValue(paletteIndex + 1); + } + + /// + /// Gets the low value of the specified palette index. + /// + /// + /// Index of the palette. + /// + /// + /// The value. + /// + protected double GetLowValue(int paletteIndex) + { + return ((double)paletteIndex / this.Palette.Colors.Count * (this.ActualMaximum - this.ActualMinimum)) + + this.ActualMinimum; + } + } +} \ No newline at end of file diff -r 88d699a65cc2 -r 5be8f2773237 External/OxyPlot/OxyPlot/Axes/DateTimeAxis.cs --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/External/OxyPlot/OxyPlot/Axes/DateTimeAxis.cs Sat Jun 08 16:53:22 2013 +0000 @@ -0,0 +1,679 @@ +// -------------------------------------------------------------------------------------------------------------------- +// +// The MIT License (MIT) +// +// Copyright (c) 2012 Oystein Bjorke +// +// Permission is hereby granted, free of charge, to any person obtaining a +// copy of this software and associated documentation files (the +// "Software"), to deal in the Software without restriction, including +// without limitation the rights to use, copy, modify, merge, publish, +// distribute, sublicense, and/or sell copies of the Software, and to +// permit persons to whom the Software is furnished to do so, subject to +// the following conditions: +// +// The above copyright notice and this permission notice shall be included +// in all copies or substantial portions of the Software. +// +// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS +// OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF +// MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. +// IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY +// CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, +// TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE +// SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. +// +// +// Represents a DateTime axis. +// +// -------------------------------------------------------------------------------------------------------------------- + +namespace OxyPlot.Axes +{ + using System; + using System.Collections.Generic; + using System.Collections.ObjectModel; + using System.Globalization; + using System.Linq; + + /// + /// Represents a axis presenting values. + /// + /// + /// The actual numeric values on the axis are days since 1900/01/01. + /// Use the static ToDouble and ToDateTime to convert numeric values to DateTimes. + /// The StringFormat value can be used to force formatting of the axis values + /// "yyyy-MM-dd" shows date + /// "w" or "ww" shows week number + /// "h:mm" shows hours and minutes + /// + public class DateTimeAxis : LinearAxis + { + /// + /// The time origin. + /// + /// + /// Same date values as Excel + /// + private static DateTime timeOrigin = new DateTime(1900, 1, 1, 0, 0, 0, DateTimeKind.Utc); + + /// + /// The actual interval type. + /// + private DateTimeIntervalType actualIntervalType; + + /// + /// The actual minor interval type. + /// + private DateTimeIntervalType actualMinorIntervalType; + + /// + /// Initializes a new instance of the class. + /// + public DateTimeAxis() + { + this.Position = AxisPosition.Bottom; + this.IntervalType = DateTimeIntervalType.Auto; + this.FirstDayOfWeek = DayOfWeek.Monday; + this.CalendarWeekRule = CalendarWeekRule.FirstFourDayWeek; + } + + /// + /// Initializes a new instance of the class. + /// + /// + /// The position. + /// + /// + /// The axis title. + /// + /// + /// The string format for the axis values. + /// + /// + /// The interval type. + /// + public DateTimeAxis( + AxisPosition pos = AxisPosition.Bottom, + string title = null, + string format = null, + DateTimeIntervalType intervalType = DateTimeIntervalType.Auto) + : base(pos, title) + { + this.FirstDayOfWeek = DayOfWeek.Monday; + this.CalendarWeekRule = CalendarWeekRule.FirstFourDayWeek; + + this.StringFormat = format; + this.IntervalType = intervalType; + } + + /// + /// Initializes a new instance of the class. + /// + /// + /// The first date/time on the axis. + /// + /// + /// The last date/time on the axis. + /// + /// + /// The position of the axis. + /// + /// + /// The axis title. + /// + /// + /// The string format for the axis values. + /// + /// + /// The interval type. + /// + [Obsolete] + public DateTimeAxis( + DateTime firstDateTime, + DateTime lastDateTime, + AxisPosition pos = AxisPosition.Bottom, + string title = null, + string format = null, + DateTimeIntervalType intervalType = DateTimeIntervalType.Auto) + : this(pos, title, format, intervalType) + { + this.Minimum = ToDouble(firstDateTime); + this.Maximum = ToDouble(lastDateTime); + } + + /// + /// Initializes a new instance of the class. + /// + /// The position of the axis. + /// The first date/time on the axis. + /// The last date/time on the axis. + /// The axis title. + /// The string format for the axis values. + /// The interval type. + public DateTimeAxis( + AxisPosition pos, + DateTime firstDateTime, + DateTime lastDateTime, + string title = null, + string format = null, + DateTimeIntervalType intervalType = DateTimeIntervalType.Auto) + : this(pos, title, format, intervalType) + { + this.Minimum = ToDouble(firstDateTime); + this.Maximum = ToDouble(lastDateTime); + } + + /// + /// Gets or sets CalendarWeekRule. + /// + public CalendarWeekRule CalendarWeekRule { get; set; } + + /// + /// Gets or sets FirstDayOfWeek. + /// + public DayOfWeek FirstDayOfWeek { get; set; } + + /// + /// Gets or sets IntervalType. + /// + public DateTimeIntervalType IntervalType { get; set; } + + /// + /// Gets or sets MinorIntervalType. + /// + public DateTimeIntervalType MinorIntervalType { get; set; } + + /// + /// Gets or sets the time zone (used when formatting date/time values). + /// + /// + /// No date/time conversion will be performed if this property is null. + /// + /// + /// The time zone info. + /// + public TimeZoneInfo TimeZone { get; set; } + + /// + /// Creates a data point. + /// + /// + /// The x value. + /// + /// + /// The y value. + /// + /// + /// A data point. + /// + public static DataPoint CreateDataPoint(DateTime x, double y) + { + return new DataPoint(ToDouble(x), y); + } + + /// + /// Creates a data point. + /// + /// + /// The x value. + /// + /// + /// The y value. + /// + /// + /// A data point. + /// + public static DataPoint CreateDataPoint(DateTime x, DateTime y) + { + return new DataPoint(ToDouble(x), ToDouble(y)); + } + + /// + /// Creates a data point. + /// + /// + /// The x value. + /// + /// + /// The y value. + /// + /// + /// A data point. + /// + public static DataPoint CreateDataPoint(double x, DateTime y) + { + return new DataPoint(x, ToDouble(y)); + } + + /// + /// Converts a numeric representation of the date (number of days after the time origin) to a DateTime structure. + /// + /// + /// The number of days after the time origin. + /// + /// + /// A date/time structure. + /// + public static DateTime ToDateTime(double value) + { + if (double.IsNaN(value)) + { + return new DateTime(); + } + + return timeOrigin.AddDays(value - 1); + } + + /// + /// Converts a DateTime to days after the time origin. + /// + /// + /// The date/time structure. + /// + /// + /// The number of days after the time origin. + /// + public static double ToDouble(DateTime value) + { + var span = value - timeOrigin; + return span.TotalDays + 1; + } + + /// + /// Formats the specified value by the axis' ActualStringFormat. + /// + /// + /// The x. + /// + /// + /// The formatted DateTime value + /// + public override string FormatValue(double x) + { + // convert the double value to a DateTime + var time = ToDateTime(x); + + // If a time zone is specified, convert the time + if (this.TimeZone != null) + { + time = TimeZoneInfo.ConvertTime(time, this.TimeZone); + } + + string fmt = this.ActualStringFormat; + if (fmt == null) + { + return time.ToString(CultureInfo.CurrentCulture.DateTimeFormat.ShortDatePattern); + } + + int week = this.GetWeek(time); + fmt = fmt.Replace("ww", week.ToString("00")); + fmt = fmt.Replace("w", week.ToString(CultureInfo.InvariantCulture)); + return time.ToString(fmt, this.ActualCulture); + } + + /// + /// Gets the tick values. + /// + /// + /// The major label values. + /// + /// + /// The major tick values. + /// + /// + /// The minor tick values. + /// + public override void GetTickValues( + out IList majorLabelValues, out IList majorTickValues, out IList minorTickValues) + { + minorTickValues = this.CreateDateTimeTickValues( + this.ActualMinimum, this.ActualMaximum, this.ActualMinorStep, this.actualMinorIntervalType); + majorTickValues = this.CreateDateTimeTickValues( + this.ActualMinimum, this.ActualMaximum, this.ActualMajorStep, this.actualIntervalType); + majorLabelValues = majorTickValues; + } + + /// + /// Gets the value from an axis coordinate, converts from double to the correct data type if necessary. + /// e.g. DateTimeAxis returns the DateTime and CategoryAxis returns category strings. + /// + /// + /// The coordinate. + /// + /// + /// The value. + /// + public override object GetValue(double x) + { + var time = ToDateTime(x); + + if (this.TimeZone != null) + { + time = TimeZoneInfo.ConvertTime(time, this.TimeZone); + } + + return time; + } + + /// + /// Updates the intervals. + /// + /// + /// The plot area. + /// + internal override void UpdateIntervals(OxyRect plotArea) + { + base.UpdateIntervals(plotArea); + switch (this.actualIntervalType) + { + case DateTimeIntervalType.Years: + this.ActualMinorStep = 31; + this.actualMinorIntervalType = DateTimeIntervalType.Years; + if (this.ActualStringFormat == null) + { + this.ActualStringFormat = "yyyy"; + } + + break; + case DateTimeIntervalType.Months: + this.actualMinorIntervalType = DateTimeIntervalType.Months; + if (this.ActualStringFormat == null) + { + this.ActualStringFormat = "yyyy-MM-dd"; + } + + break; + case DateTimeIntervalType.Weeks: + this.actualMinorIntervalType = DateTimeIntervalType.Days; + this.ActualMajorStep = 7; + this.ActualMinorStep = 1; + if (this.ActualStringFormat == null) + { + this.ActualStringFormat = "yyyy/ww"; + } + + break; + case DateTimeIntervalType.Days: + this.ActualMinorStep = this.ActualMajorStep; + if (this.ActualStringFormat == null) + { + this.ActualStringFormat = "yyyy-MM-dd"; + } + + break; + case DateTimeIntervalType.Hours: + this.ActualMinorStep = this.ActualMajorStep; + if (this.ActualStringFormat == null) + { + this.ActualStringFormat = "HH:mm"; + } + + break; + case DateTimeIntervalType.Minutes: + this.ActualMinorStep = this.ActualMajorStep; + if (this.ActualStringFormat == null) + { + this.ActualStringFormat = "HH:mm"; + } + + break; + case DateTimeIntervalType.Seconds: + this.ActualMinorStep = this.ActualMajorStep; + if (this.ActualStringFormat == null) + { + this.ActualStringFormat = "HH:mm:ss"; + } + + break; + case DateTimeIntervalType.Manual: + break; + case DateTimeIntervalType.Auto: + break; + } + } + + /// + /// Calculates the actual interval. + /// + /// + /// Size of the available area. + /// + /// + /// Maximum length of the intervals. + /// + /// + /// The calculate actual interval. + /// + protected override double CalculateActualInterval(double availableSize, double maxIntervalSize) + { + const double Year = 365.25; + const double Month = 30.5; + const double Week = 7; + const double Day = 1.0; + const double Hour = Day / 24; + const double Minute = Hour / 60; + const double Second = Minute / 60; + + double range = Math.Abs(this.ActualMinimum - this.ActualMaximum); + + var goodIntervals = new[] + { + Second, 2 * Second, 5 * Second, 10 * Second, 30 * Second, Minute, 2 * Minute, + 5 * Minute, 10 * Minute, 30 * Minute, Hour, 4 * Hour, 8 * Hour, 12 * Hour, Day, + 2 * Day, 5 * Day, Week, 2 * Week, Month, 2 * Month, 3 * Month, 4 * Month, + 6 * Month, Year + }; + + double interval = goodIntervals[0]; + + int maxNumberOfIntervals = Math.Max((int)(availableSize / maxIntervalSize), 2); + + while (true) + { + if (range / interval < maxNumberOfIntervals) + { + break; + } + + double nextInterval = goodIntervals.FirstOrDefault(i => i > interval); + if (Math.Abs(nextInterval) < double.Epsilon) + { + nextInterval = interval * 2; + } + + interval = nextInterval; + } + + this.actualIntervalType = this.IntervalType; + this.actualMinorIntervalType = this.MinorIntervalType; + + if (this.IntervalType == DateTimeIntervalType.Auto) + { + this.actualIntervalType = DateTimeIntervalType.Seconds; + if (interval >= 1.0 / 24 / 60) + { + this.actualIntervalType = DateTimeIntervalType.Minutes; + } + + if (interval >= 1.0 / 24) + { + this.actualIntervalType = DateTimeIntervalType.Hours; + } + + if (interval >= 1) + { + this.actualIntervalType = DateTimeIntervalType.Days; + } + + if (interval >= 30) + { + this.actualIntervalType = DateTimeIntervalType.Months; + } + + if (range >= 365.25) + { + this.actualIntervalType = DateTimeIntervalType.Years; + } + } + + if (this.actualIntervalType == DateTimeIntervalType.Months) + { + double monthsRange = range / 30.5; + interval = this.CalculateActualInterval(availableSize, maxIntervalSize, monthsRange); + } + + if (this.actualIntervalType == DateTimeIntervalType.Years) + { + double yearsRange = range / 365.25; + interval = this.CalculateActualInterval(availableSize, maxIntervalSize, yearsRange); + } + + if (this.actualMinorIntervalType == DateTimeIntervalType.Auto) + { + switch (this.actualIntervalType) + { + case DateTimeIntervalType.Years: + this.actualMinorIntervalType = DateTimeIntervalType.Months; + break; + case DateTimeIntervalType.Months: + this.actualMinorIntervalType = DateTimeIntervalType.Days; + break; + case DateTimeIntervalType.Weeks: + this.actualMinorIntervalType = DateTimeIntervalType.Days; + break; + case DateTimeIntervalType.Days: + this.actualMinorIntervalType = DateTimeIntervalType.Hours; + break; + case DateTimeIntervalType.Hours: + this.actualMinorIntervalType = DateTimeIntervalType.Minutes; + break; + default: + this.actualMinorIntervalType = DateTimeIntervalType.Days; + break; + } + } + + return interval; + } + + /// + /// Creates the date tick values. + /// + /// + /// The min. + /// + /// + /// The max. + /// + /// + /// The step. + /// + /// + /// Type of the interval. + /// + /// + /// Date tick values. + /// + private IList CreateDateTickValues( + double min, double max, double step, DateTimeIntervalType intervalType) + { + DateTime start = ToDateTime(min); + switch (intervalType) + { + case DateTimeIntervalType.Weeks: + + // make sure the first tick is at the 1st day of a week + start = start.AddDays(-(int)start.DayOfWeek + (int)this.FirstDayOfWeek); + break; + case DateTimeIntervalType.Months: + + // make sure the first tick is at the 1st of a month + start = new DateTime(start.Year, start.Month, 1); + break; + case DateTimeIntervalType.Years: + + // make sure the first tick is at Jan 1st + start = new DateTime(start.Year, 1, 1); + break; + } + + // Adds a tick to the end time to make sure the end DateTime is included. + DateTime end = ToDateTime(max).AddTicks(1); + + DateTime current = start; + var values = new Collection(); + double eps = step * 1e-3; + DateTime minDateTime = ToDateTime(min - eps); + DateTime maxDateTime = ToDateTime(max + eps); + while (current < end) + { + if (current > minDateTime && current < maxDateTime) + { + values.Add(ToDouble(current)); + } + + switch (intervalType) + { + case DateTimeIntervalType.Months: + current = current.AddMonths((int)Math.Ceiling(step)); + break; + case DateTimeIntervalType.Years: + current = current.AddYears((int)Math.Ceiling(step)); + break; + default: + current = current.AddDays(step); + break; + } + } + + return values; + } + + /// + /// Creates date/time tick values. + /// + /// + /// The min. + /// + /// + /// The max. + /// + /// + /// The interval. + /// + /// + /// The interval type. + /// + /// DateTime tick values. + /// + /// DateTime tick values. + /// + private IList CreateDateTimeTickValues( + double min, double max, double interval, DateTimeIntervalType intervalType) + { + // If the step size is more than 7 days (e.g. months or years) we use a specialized tick generation method that adds tick values with uneven spacing... + if (intervalType > DateTimeIntervalType.Days) + { + return this.CreateDateTickValues(min, max, interval, intervalType); + } + + // For shorter step sizes we use the method from Axis + return CreateTickValues(min, max, interval); + } + + /// + /// Gets the week number for the specified date. + /// + /// + /// The date. + /// + /// + /// The week number for the current culture. + /// + private int GetWeek(DateTime date) + { + return this.ActualCulture.Calendar.GetWeekOfYear(date, this.CalendarWeekRule, this.FirstDayOfWeek); + } + } +} \ No newline at end of file diff -r 88d699a65cc2 -r 5be8f2773237 External/OxyPlot/OxyPlot/Axes/DateTimeIntervalType.cs --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/External/OxyPlot/OxyPlot/Axes/DateTimeIntervalType.cs Sat Jun 08 16:53:22 2013 +0000 @@ -0,0 +1,87 @@ +// -------------------------------------------------------------------------------------------------------------------- +// +// The MIT License (MIT) +// +// Copyright (c) 2012 Oystein Bjorke +// +// Permission is hereby granted, free of charge, to any person obtaining a +// copy of this software and associated documentation files (the +// "Software"), to deal in the Software without restriction, including +// without limitation the rights to use, copy, modify, merge, publish, +// distribute, sublicense, and/or sell copies of the Software, and to +// permit persons to whom the Software is furnished to do so, subject to +// the following conditions: +// +// The above copyright notice and this permission notice shall be included +// in all copies or substantial portions of the Software. +// +// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS +// OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF +// MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. +// IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY +// CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, +// TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE +// SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. +// +// +// Defines the date time interval for DateTimeAxis. +// +// -------------------------------------------------------------------------------------------------------------------- +namespace OxyPlot.Axes +{ + /// + /// Specifies the date time interval for . + /// + public enum DateTimeIntervalType + { + /// + /// Automatically determine interval. + /// + Auto = 0, + + /// + /// Manual definition of intervals. + /// + Manual = 1, + + /// + /// Interval type is milliseconds. + /// + Milliseconds = 2, + + /// + /// Interval type is seconds. + /// + Seconds = 3, + + /// + /// Interval type is minutes. + /// + Minutes = 4, + + /// + /// Interval type is hours. + /// + Hours = 5, + + /// + /// Interval type is days. + /// + Days = 6, + + /// + /// Interval type is weeks. + /// + Weeks = 7, + + /// + /// Interval type is months. + /// + Months = 8, + + /// + /// Interval type is years. + /// + Years = 9, + } +} \ No newline at end of file diff -r 88d699a65cc2 -r 5be8f2773237 External/OxyPlot/OxyPlot/Axes/LinearAxis.cs --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/External/OxyPlot/OxyPlot/Axes/LinearAxis.cs Sat Jun 08 16:53:22 2013 +0000 @@ -0,0 +1,164 @@ +// -------------------------------------------------------------------------------------------------------------------- +// +// The MIT License (MIT) +// +// Copyright (c) 2012 Oystein Bjorke +// +// Permission is hereby granted, free of charge, to any person obtaining a +// copy of this software and associated documentation files (the +// "Software"), to deal in the Software without restriction, including +// without limitation the rights to use, copy, modify, merge, publish, +// distribute, sublicense, and/or sell copies of the Software, and to +// permit persons to whom the Software is furnished to do so, subject to +// the following conditions: +// +// The above copyright notice and this permission notice shall be included +// in all copies or substantial portions of the Software. +// +// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS +// OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF +// MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. +// IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY +// CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, +// TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE +// SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. +// +// +// Represents an axis with linear scale. +// +// -------------------------------------------------------------------------------------------------------------------- +namespace OxyPlot.Axes +{ + /// + /// Represents an axis with linear scale. + /// + public class LinearAxis : Axis + { + /// + /// Initializes a new instance of the class. + /// + public LinearAxis() + { + this.FractionUnit = 1.0; + this.FractionUnitSymbol = null; + this.FormatAsFractions = false; + } + + /// + /// Initializes a new instance of the class. + /// + /// + /// The pos. + /// + /// + /// The title. + /// + public LinearAxis(AxisPosition pos, string title) + : this() + { + this.Position = pos; + this.Title = title; + } + + /// + /// Initializes a new instance of the class. + /// + /// + /// The pos. + /// + /// + /// The minimum. + /// + /// + /// The maximum. + /// + /// + /// The title. + /// + public LinearAxis( + AxisPosition pos, double minimum = double.NaN, double maximum = double.NaN, string title = null) + : this(pos, minimum, maximum, double.NaN, double.NaN, title) + { + } + + /// + /// Initializes a new instance of the class. + /// + /// + /// The pos. + /// + /// + /// The minimum. + /// + /// + /// The maximum. + /// + /// + /// The major step. + /// + /// + /// The minor step. + /// + /// + /// The title. + /// + public LinearAxis( + AxisPosition pos, double minimum, double maximum, double majorStep, double minorStep, string title = null) + : this(pos, title) + { + this.Minimum = minimum; + this.Maximum = maximum; + this.MajorStep = majorStep; + this.MinorStep = minorStep; + } + + /// + /// Gets or sets a value indicating whether to format numbers as fractions. + /// + public bool FormatAsFractions { get; set; } + + /// + /// Gets or sets the fraction unit. Remember to set FormatAsFractions to true. + /// + /// The fraction unit. + public double FractionUnit { get; set; } + + /// + /// Gets or sets the fraction unit symbol. Use FractionUnit = Math.PI and FractionUnitSymbol = "π" if you want the axis to show "π/2,π,3π/2,2π" etc. Use FractionUnit = 1 and FractionUnitSymbol = "L" if you want the axis to show "0,L/2,L" etc. Remember to set FormatAsFractions to true. + /// + /// The fraction unit symbol. + public string FractionUnitSymbol { get; set; } + + /// + /// Formats the value to be used on the axis. + /// + /// + /// The value. + /// + /// + /// The formatted value. + /// + public override string FormatValue(double x) + { + if (this.FormatAsFractions) + { + return FractionHelper.ConvertToFractionString( + x, this.FractionUnit, this.FractionUnitSymbol, 1e-6, this.ActualCulture); + } + + return base.FormatValue(x); + } + + /// + /// Determines whether the axis is used for X/Y values. + /// + /// + /// true if it is an XY axis; otherwise, false . + /// + public override bool IsXyAxis() + { + return true; + } + + } +} \ No newline at end of file diff -r 88d699a65cc2 -r 5be8f2773237 External/OxyPlot/OxyPlot/Axes/LogarithmicAxis.cs --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/External/OxyPlot/OxyPlot/Axes/LogarithmicAxis.cs Sat Jun 08 16:53:22 2013 +0000 @@ -0,0 +1,406 @@ +// -------------------------------------------------------------------------------------------------------------------- +// +// The MIT License (MIT) +// +// Copyright (c) 2012 Oystein Bjorke +// +// Permission is hereby granted, free of charge, to any person obtaining a +// copy of this software and associated documentation files (the +// "Software"), to deal in the Software without restriction, including +// without limitation the rights to use, copy, modify, merge, publish, +// distribute, sublicense, and/or sell copies of the Software, and to +// permit persons to whom the Software is furnished to do so, subject to +// the following conditions: +// +// The above copyright notice and this permission notice shall be included +// in all copies or substantial portions of the Software. +// +// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS +// OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF +// MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. +// IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY +// CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, +// TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE +// SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. +// +// +// Represents an axis with logarithmic scale. +// +// -------------------------------------------------------------------------------------------------------------------- +namespace OxyPlot.Axes +{ + using System; + using System.Collections.Generic; + using System.Diagnostics; + + /// + /// Represents an axis with logarithmic scale. + /// + /// + /// See http://en.wikipedia.org/wiki/Logarithmic_scale. + /// + public class LogarithmicAxis : Axis + { + /// + /// Initializes a new instance of the class. + /// + public LogarithmicAxis() + { + this.PowerPadding = true; + this.Base = 10; + this.FilterMinValue = 0; + } + + /// + /// Initializes a new instance of the class. + /// + /// + /// The position. + /// + /// + /// The title. + /// + public LogarithmicAxis(AxisPosition pos, string title) + : this() + { + this.Position = pos; + this.Title = title; + } + + /// + /// Initializes a new instance of the class. + /// + /// + /// The position. + /// + /// + /// The minimum. + /// + /// + /// The maximum. + /// + /// + /// The title. + /// + public LogarithmicAxis( + AxisPosition position, double minimum = double.NaN, double maximum = double.NaN, string title = null) + : this() + { + this.Position = position; + this.Title = title; + this.Minimum = minimum; + this.Maximum = maximum; + } + + /// + /// Gets or sets the logarithmic base (normally 10). + /// + /// + /// See http://en.wikipedia.org/wiki/Logarithm. + /// + /// The logarithmic base. + public double Base { get; set; } + + /// + /// Gets or sets a value indicating whether the ActualMaximum and ActualMinimum values should be padded to the nearest power of the Base. + /// + public bool PowerPadding { get; set; } + + /// + /// Coerces the actual maximum and minimum values. + /// + public override void CoerceActualMaxMin() + { + if (double.IsNaN(this.ActualMinimum) || double.IsInfinity(this.ActualMinimum)) + { + this.ActualMinimum = 1; + } + + if (this.ActualMinimum <= 0) + { + this.ActualMinimum = 1; + } + + if (this.ActualMaximum <= this.ActualMinimum) + { + this.ActualMaximum = this.ActualMinimum * 100; + } + + base.CoerceActualMaxMin(); + } + + /// + /// Gets the coordinates used to draw ticks and tick labels (numbers or category names). + /// + /// + /// The major label values. + /// + /// + /// The major tick values. + /// + /// + /// The minor tick values. + /// + public override void GetTickValues( + out IList majorLabelValues, out IList majorTickValues, out IList minorTickValues) + { + if (this.ActualMinimum <= 0) + { + this.ActualMinimum = 0.1; + } + + double logBase = Math.Log(this.Base); + var e0 = (int)Math.Floor(Math.Log(this.ActualMinimum) / logBase); + var e1 = (int)Math.Ceiling(Math.Log(this.ActualMaximum) / logBase); + + // find the min & max values for the specified base + // round to max 10 digits + double p0 = Math.Pow(this.Base, e0); + double p1 = Math.Pow(this.Base, e1); + double d0 = Math.Round(p0, 10); + double d1 = Math.Round(p1, 10); + if (d0 <= 0) + { + d0 = p0; + } + + double d = d0; + majorTickValues = new List(); + minorTickValues = new List(); + + double epsMin = this.ActualMinimum * 1e-6; + double epsMax = this.ActualMaximum * 1e-6; + + while (d <= d1 + epsMax) + { + // d = RemoveNoiseFromDoubleMath(d); + if (d >= this.ActualMinimum - epsMin && d <= this.ActualMaximum + epsMax) + { + majorTickValues.Add(d); + } + + for (int i = 1; i < this.Base; i++) + { + double d2 = d * (i + 1); + if (d2 > d1 + double.Epsilon) + { + break; + } + + if (d2 > this.ActualMaximum) + { + break; + } + + if (d2 >= this.ActualMinimum && d2 <= this.ActualMaximum) + { + minorTickValues.Add(d2); + } + } + + d *= this.Base; + if (double.IsInfinity(d)) + { + break; + } + + if (d < double.Epsilon) + { + break; + } + + if (double.IsNaN(d)) + { + break; + } + } + + if (majorTickValues.Count < 2) + { + base.GetTickValues(out majorLabelValues, out majorTickValues, out minorTickValues); + } + else + { + majorLabelValues = majorTickValues; + } + } + + /// + /// Determines whether the specified value is valid. + /// + /// + /// The value. + /// + /// + /// true if the specified value is valid; otherwise, false. + /// + public override bool IsValidValue(double value) + { + return value > 0 && base.IsValidValue(value); + } + + /// + /// Determines whether the axis is used for X/Y values. + /// + /// + /// true if it is an XY axis; otherwise, false . + /// + public override bool IsXyAxis() + { + return true; + } + + /// + /// Pans the specified axis. + /// + /// + /// The previous point (screen coordinates). + /// + /// + /// The current point (screen coordinates). + /// + public override void Pan(ScreenPoint ppt, ScreenPoint cpt) + { + if (!this.IsPanEnabled) + { + return; + } + + bool isHorizontal = this.IsHorizontal(); + + double x0 = this.InverseTransform(isHorizontal ? ppt.X : ppt.Y); + double x1 = this.InverseTransform(isHorizontal ? cpt.X : cpt.Y); + + if (Math.Abs(x1) < double.Epsilon) + { + return; + } + + double dx = x0 / x1; + + double newMinimum = this.ActualMinimum * dx; + double newMaximum = this.ActualMaximum * dx; + if (newMinimum < this.AbsoluteMinimum) + { + newMinimum = this.AbsoluteMinimum; + newMaximum = newMinimum * this.ActualMaximum / this.ActualMinimum; + } + + if (newMaximum > this.AbsoluteMaximum) + { + newMaximum = this.AbsoluteMaximum; + newMinimum = newMaximum * this.ActualMaximum / this.ActualMinimum; + } + + this.ViewMinimum = newMinimum; + this.ViewMaximum = newMaximum; + + this.OnAxisChanged(new AxisChangedEventArgs(AxisChangeTypes.Pan)); + } + + /// + /// Transforms the specified coordinate to screen coordinates. + /// + /// + /// The value. + /// + /// + /// The transformed value (screen coordinate). + /// + public override double Transform(double x) + { + Debug.Assert(x > 0, "Value should be positive."); + if (x <= 0) + { + return -1; + } + + return (Math.Log(x) - this.offset) * this.scale; + } + + /// + /// Zooms the axis at the specified coordinate. + /// + /// + /// The zoom factor. + /// + /// + /// The coordinate to zoom at. + /// + public override void ZoomAt(double factor, double x) + { + if (!this.IsZoomEnabled) + { + return; + } + + double px = this.PreTransform(x); + double dx0 = this.PreTransform(this.ActualMinimum) - px; + double dx1 = this.PreTransform(this.ActualMaximum) - px; + double newViewMinimum = this.PostInverseTransform((dx0 / factor) + px); + double newViewMaximum = this.PostInverseTransform((dx1 / factor) + px); + + this.ViewMinimum = Math.Max(newViewMinimum, this.AbsoluteMinimum); + this.ViewMaximum = Math.Min(newViewMaximum, this.AbsoluteMaximum); + } + + /// + /// Applies a transformation after the inverse transform of the value. This is used in logarithmic axis. + /// + /// The value to transform. + /// + /// The transformed value. + /// + internal override double PostInverseTransform(double x) + { + return Math.Exp(x); + } + + /// + /// Applies a transformation before the transform the value. This is used in logarithmic axis. + /// + /// The value to transform. + /// + /// The transformed value. + /// + internal override double PreTransform(double x) + { + Debug.Assert(x > 0, "Value should be positive."); + + if (x <= 0) + { + return 0; + } + + return Math.Log(x); + } + + /// + /// Updates the actual maximum and minimum values. + /// If the user has zoomed/panned the axis, the internal ViewMaximum/ViewMinimum values will be used. + /// If Maximum or Minimum have been set, these values will be used. + /// Otherwise the maximum and minimum values of the series will be used, including the 'padding'. + /// + internal override void UpdateActualMaxMin() + { + if (this.PowerPadding) + { + double logBase = Math.Log(this.Base); + var e0 = (int)Math.Floor(Math.Log(this.ActualMinimum) / logBase); + var e1 = (int)Math.Ceiling(Math.Log(this.ActualMaximum) / logBase); + if (!double.IsNaN(this.ActualMinimum)) + { + this.ActualMinimum = Math.Exp(e0 * logBase).RemoveNoiseFromDoubleMath(); + } + + if (!double.IsNaN(this.ActualMaximum)) + { + this.ActualMaximum = Math.Exp(e1 * logBase).RemoveNoiseFromDoubleMath(); + } + } + + base.UpdateActualMaxMin(); + } + + } +} \ No newline at end of file diff -r 88d699a65cc2 -r 5be8f2773237 External/OxyPlot/OxyPlot/Axes/MagnitudeAxis.cs --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/External/OxyPlot/OxyPlot/Axes/MagnitudeAxis.cs Sat Jun 08 16:53:22 2013 +0000 @@ -0,0 +1,205 @@ +// -------------------------------------------------------------------------------------------------------------------- +// +// The MIT License (MIT) +// +// Copyright (c) 2012 Oystein Bjorke +// +// Permission is hereby granted, free of charge, to any person obtaining a +// copy of this software and associated documentation files (the +// "Software"), to deal in the Software without restriction, including +// without limitation the rights to use, copy, modify, merge, publish, +// distribute, sublicense, and/or sell copies of the Software, and to +// permit persons to whom the Software is furnished to do so, subject to +// the following conditions: +// +// The above copyright notice and this permission notice shall be included +// in all copies or substantial portions of the Software. +// +// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS +// OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF +// MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. +// IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY +// CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, +// TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE +// SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. +// +// +// Represents a magnitude axis for polar plots. +// +// -------------------------------------------------------------------------------------------------------------------- +namespace OxyPlot.Axes +{ + using System; + + /// + /// Represents a magnitude axis for polar plots. + /// + public class MagnitudeAxis : LinearAxis + { + /// + /// Initializes a new instance of the class. + /// + public MagnitudeAxis() + { + this.Position = AxisPosition.Bottom; + this.IsPanEnabled = false; + this.IsZoomEnabled = false; + + this.MajorGridlineStyle = LineStyle.Solid; + this.MinorGridlineStyle = LineStyle.Solid; + } + + /// + /// Initializes a new instance of the class. + /// + /// + /// The minimum. + /// + /// + /// The maximum. + /// + /// + /// The major step. + /// + /// + /// The minor step. + /// + /// + /// The title. + /// + public MagnitudeAxis( + double minimum = double.NaN, + double maximum = double.NaN, + double majorStep = double.NaN, + double minorStep = double.NaN, + string title = null) + : this() + { + this.Minimum = minimum; + this.Maximum = maximum; + this.MajorStep = majorStep; + this.MinorStep = minorStep; + this.Title = title; + } + + /// + /// Gets or sets the midpoint (screen coordinates) of the plot area. This is used by polar coordinate systems. + /// + internal ScreenPoint MidPoint { get; set; } + + /// + /// Inverse transform the specified screen point. + /// + /// + /// The x coordinate. + /// + /// + /// The y coordinate. + /// + /// + /// The y-axis. + /// + /// + /// The data point. + /// + public override DataPoint InverseTransform(double x, double y, Axis yaxis) + { + var angleAxis = yaxis as AngleAxis; + if (angleAxis == null) + { + throw new InvalidOperationException("Polar angle axis not defined!"); + } + + x -= this.MidPoint.x; + y -= this.MidPoint.y; + double th = Math.Atan2(y, x); + double r = Math.Sqrt((x * x) + (y * y)); + x = (r / this.scale) + this.offset; + y = (th / angleAxis.Scale) + angleAxis.Offset; + return new DataPoint(x, y); + } + + /// + /// Determines whether the axis is used for X/Y values. + /// + /// + /// true if it is an XY axis; otherwise, false . + /// + public override bool IsXyAxis() + { + return false; + } + + /// + /// Renders the axis on the specified render context. + /// + /// The render context. + /// The model. + /// The rendering order. + /// + public override void Render(IRenderContext rc, PlotModel model, AxisLayer axisLayer, int pass) + { + if (this.Layer != axisLayer) + { + return; + } + + var r = new MagnitudeAxisRenderer(rc, model); + r.Render(this, pass); + } + + /// + /// Transforms the specified point to screen coordinates. + /// + /// + /// The x value (for the current axis). + /// + /// + /// The y value. + /// + /// + /// The y axis. + /// + /// + /// The transformed point. + /// + public override ScreenPoint Transform(double x, double y, Axis yaxis) + { + var angleAxis = yaxis as AngleAxis; + if (angleAxis == null) + { + throw new InvalidOperationException("Polar angle axis not defined!"); + } + + double r = (x - this.Offset) * this.scale; + double theta = (y - angleAxis.Offset) * angleAxis.Scale; + + return new ScreenPoint(this.MidPoint.x + (r * Math.Cos(theta)), this.MidPoint.y - (r * Math.Sin(theta))); + } + + /// + /// Updates the scale and offset properties of the transform from the specified boundary rectangle. + /// + /// + /// The bounds. + /// + internal override void UpdateTransform(OxyRect bounds) + { + double x0 = bounds.Left; + double x1 = bounds.Right; + double y0 = bounds.Bottom; + double y1 = bounds.Top; + + this.ScreenMin = new ScreenPoint(x0, y1); + this.ScreenMax = new ScreenPoint(x1, y0); + + this.MidPoint = new ScreenPoint((x0 + x1) / 2, (y0 + y1) / 2); + + this.ActualMinimum = 0; + double r = Math.Min(Math.Abs(x1 - x0), Math.Abs(y1 - y0)); + this.scale = 0.5 * r / (this.ActualMaximum - this.ActualMinimum); + this.Offset = this.ActualMinimum; + } + + } +} \ No newline at end of file diff -r 88d699a65cc2 -r 5be8f2773237 External/OxyPlot/OxyPlot/Axes/RangeAxis.cs --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/External/OxyPlot/OxyPlot/Axes/RangeAxis.cs Sat Jun 08 16:53:22 2013 +0000 @@ -0,0 +1,469 @@ +// -------------------------------------------------------------------------------------------------------------------- +// +// The MIT License (MIT) +// +// Copyright (c) 2012 Oystein Bjorke +// +// Permission is hereby granted, free of charge, to any person obtaining a +// copy of this software and associated documentation files (the +// "Software"), to deal in the Software without restriction, including +// without limitation the rights to use, copy, modify, merge, publish, +// distribute, sublicense, and/or sell copies of the Software, and to +// permit persons to whom the Software is furnished to do so, subject to +// the following conditions: +// +// The above copyright notice and this permission notice shall be included +// in all copies or substantial portions of the Software. +// +// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS +// OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF +// MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. +// IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY +// CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, +// TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE +// SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. +// +// +// Updates the minor/major step intervals if they are undefined. +// +// -------------------------------------------------------------------------------------------------------------------- +using System; +using System.Collections.Generic; +using System.Collections.ObjectModel; +using System.Diagnostics; +using System.Globalization; + +namespace OxyPlot +{ + public class Axis : IAxis + { + public Axis() + { + Position = AxisPosition.Left; + IsVisible = true; + + Minimum = double.NaN; + Maximum = double.NaN; + MinorStep = double.NaN; + MajorStep = double.NaN; + + MinimumPadding = 0.01; + MaximumPadding = 0.01; + + TickStyle = TickStyle.Inside; + MajorGridlineStyle = LineStyle.None; + MinorGridlineStyle = LineStyle.None; + TicklineColor = Colors.Black; + MajorGridlineColor = Color.FromARGB(0x40, 0, 0, 0); + TicklineColor = Colors.Black; + MinorGridlineColor = Color.FromARGB(0x20, 0, 0, 0x00); + MajorGridlineThickness = 1; + MinorGridlineThickness = 1; + + ExtraGridlineStyle = LineStyle.Solid; + ExtraGridlineColor = Colors.Black; + ExtraGridlineThickness = 1; + + ShowMinorTicks = true; + + FontFamily = "Segoe UI"; + FontSize = 12; + + MinorTickSize = 4; + MajorTickSize = 7; + + StartPosition = 0; + EndPosition = 1; + + Angle = 0; + } + + public Axis(AxisPosition pos, double minimum, double maximum) + : this() + { + Position = pos; + Minimum = minimum; + Maximum = maximum; + } + public string Key { get; set; } + + public AxisPosition Position { get; set; } + public bool PositionAtZeroCrossing { get; set; } + public bool IsHorizontal { get { return Position == AxisPosition.Top || Position == AxisPosition.Bottom; } } + public bool IsVertical { get { return Position == AxisPosition.Left || Position == AxisPosition.Right; } } + public bool IsPolar { get { return Position == AxisPosition.Magnitude || Position == AxisPosition.Angle; } } + + public bool IsVisible { get; set; } + + public double ActualMinimum { get; set; } + public double ActualMaximum { get; set; } + internal double ActualMinorStep { get; set; } + internal double ActualMajorStep { get; set; } + + public double Minimum { get; set; } + public double Maximum { get; set; } + public double MinorStep { get; set; } + public double MajorStep { get; set; } + + public double MinimumPadding { get; set; } + public double MaximumPadding { get; set; } + + public TickStyle TickStyle { get; set; } + public double MinorTickSize { get; set; } + public double MajorTickSize { get; set; } + public Color TicklineColor { get; set; } + public bool ShowMinorTicks { get; set; } + + public LineStyle MajorGridlineStyle { get; set; } + public LineStyle MinorGridlineStyle { get; set; } + public Color MajorGridlineColor { get; set; } + public Color MinorGridlineColor { get; set; } + public double MajorGridlineThickness { get; set; } + public double MinorGridlineThickness { get; set; } + + public double[] ExtraGridlines { get; set; } + public LineStyle ExtraGridlineStyle { get; set; } + public Color ExtraGridlineColor { get; set; } + public double ExtraGridlineThickness { get; set; } + + public double Angle { get; set; } + public string StringFormat { get; set; } + internal string ActualStringFormat { get; set; } + public string Title { get; set; } + public string Unit { get; set; } + + public string FontFamily { get; set; } + public double FontSize { get; set; } + public double FontWeight { get; set; } + + public double StartPosition { get; set; } + public double EndPosition { get; set; } + + public Axis RelatedAxis { get; set; } + + public bool IsReversed { get { return StartPosition > EndPosition; } } + + internal double Offset; + internal double Scale; + internal Point MidPoint; + internal Point ScreenMin; + internal Point ScreenMax; + + public override string ToString() + { + return String.Format(CultureInfo.InvariantCulture, "{0}({1}, {2}, {3}, {4})", GetType().Name, Position, ActualMinimum, ActualMaximum, ActualMajorStep); + } + + public virtual void GetTickValues(out ICollection majorValues, out ICollection minorValues) + { + minorValues = CreateTickValues(ActualMinimum, ActualMaximum, ActualMinorStep); + majorValues = CreateTickValues(ActualMinimum, ActualMaximum, ActualMajorStep); + } + + public virtual string FormatValue(double x) + { + return x.ToString(ActualStringFormat, CultureInfo.InvariantCulture); + } + + private static ICollection CreateTickValues(double min, double max, double step) + { + if (max <= min) + throw new InvalidOperationException("Axis: Maximum should be larger than minimum."); + if (step <= 0) + throw new InvalidOperationException("Axis: Step cannot be negative."); + + double x = (int)Math.Round(min / step) * step; + + var values = new Collection(); + // Maximum number of iterations (in case of very small step size) + int it = 0; + const int maxit = 1000; + double epsilon = Math.Abs(max - min) * 1e-6; + while (x <= max + epsilon && it++ < maxit) + { + if (x >= min - epsilon && x <= max + epsilon) + { + x = RemoveNoiseFromDoubleMath(x); + values.Add(x); + } + x += step; + } + return values; + } + + protected virtual double PreTransform(double x) + { + return x; + } + + protected virtual double PostInverseTransform(double x) + { + return x; + } + + public virtual Point Transform(double x, double y, Axis yAxis) + { + Debug.Assert(yAxis != null); + if (IsPolar) + { + double r = (x - Offset) * Scale; + double th = yAxis != null ? (y - yAxis.Offset) * yAxis.Scale : double.NaN; + return new Point(MidPoint.X + r * Math.Cos(th), MidPoint.Y + r * Math.Sin(th)); + } + if (yAxis == null) + return new Point(); + return new Point(TransformX(x), yAxis != null ? yAxis.TransformX(y) : double.NaN); + } + + public double TransformX(double x) + { + return (PreTransform(x) - Offset) * Scale; + } + + public virtual Point InverseTransform(double x, double y, Axis yAxis) + { + Debug.Assert(yAxis != null); + if (IsPolar) + { + x -= MidPoint.X; + y -= MidPoint.Y; + double th = Math.Atan2(y, x); + double r = Math.Sqrt(x * x + y * y); + x = r / Scale + Offset; + y = yAxis != null ? th / yAxis.Scale + yAxis.Offset : double.NaN; + return new Point(x, y); + } + + return new Point(InverseTransformX(x), yAxis.InverseTransformX(y)); + } + + public double InverseTransformX(double x) + { + return PostInverseTransform(x / Scale + Offset); + } + + public double UpdateTransform(double x0, double x1, double y0, double y1) + { + ScreenMin = new Point(x0, y1); + ScreenMax = new Point(x1, y0); + + if (Position == AxisPosition.Angle) + { + MidPoint = new Point((x0 + x1) / 2, (y0 + y1) / 2); + Scale = 2 * Math.PI / (ActualMaximum - ActualMinimum); + Offset = ActualMinimum; + return Scale; + } + if (Position == AxisPosition.Magnitude) + { + ActualMinimum = 0; + MidPoint = new Point((x0 + x1) / 2, (y0 + y1) / 2); + double r = Math.Min(Math.Abs(x1 - x0), Math.Abs(y1 - y0)); + Scale = 0.5 * r / (ActualMaximum - ActualMinimum); + Offset = ActualMinimum; + return Scale; + } + double a0 = IsHorizontal ? x0 : y0; + double a1 = IsHorizontal ? x1 : y1; + + double dx = a1 - a0; + a1 = a0 + EndPosition * dx; + a0 = a0 + StartPosition * dx; + + if (ActualMaximum - ActualMinimum < double.Epsilon) + ActualMaximum = ActualMinimum + 1; + + double max = PreTransform(ActualMaximum); + double min = PreTransform(ActualMinimum); + + const double eps = 1e-6; + if (max - min < eps) max = min + 1; + + if (Math.Abs(a0 - a1) != 0) + Offset = (a0 * max - min * a1) / (a0 - a1); + else + Offset = 0; + + Scale = (a1 - a0) / (max - min); + + return Scale; + } + + public void SetScale(double scale) + { + double sgn = Math.Sign(Scale); + double mid = (ActualMaximum + ActualMinimum) / 2; + double dx = (Offset - mid) * Scale; + Scale = sgn * scale; + Offset = dx / Scale + mid; + } + + public virtual void Pan(double dx) + { + Minimum = ActualMinimum + dx; + Maximum = ActualMaximum + dx; + } + + public virtual void ScaleAt(double factor, double x) + { + double dx0 = (ActualMinimum - x) * Scale; + double dx1 = (ActualMaximum - x) * Scale; + Scale *= factor; + Minimum = dx0 / Scale + x; + Maximum = dx1 / Scale + x; + } + + public virtual void Zoom(double x0, double x1) + { + Minimum = Math.Min(x0, x1); + Maximum = Math.Max(x0, x1); + } + + public virtual void Reset() + { + Minimum = double.NaN; + Maximum = double.NaN; + } + + /// + /// Updates the minor/major step intervals if they are undefined. + /// + public void UpdateIntervals(double dx, double dy) + { + double labelSize = GetLabelSize(); + double length = IsHorizontal ? dx : dy; + + if (!double.IsNaN(MajorStep)) + ActualMajorStep = MajorStep; + else + ActualMajorStep = CalculateActualInterval(length, labelSize); + + if (!double.IsNaN(MinorStep)) + ActualMinorStep = MinorStep; + else + ActualMinorStep = ActualMajorStep / 5; + + if (double.IsNaN(ActualMinorStep)) + ActualMinorStep = 2; + if (double.IsNaN(ActualMajorStep)) + ActualMajorStep = 10; + + ActualStringFormat = StringFormat; + } + + private double GetLabelSize() + { + if (IsHorizontal) + return 100; + if (IsVertical) + return 30; + if (Position == AxisPosition.Angle) + return 50; + if (Position == AxisPosition.Magnitude) + return 100; + return 50; + } + + protected virtual double CalculateActualInterval(double availableSize, double maxIntervalSize) + { + return CalculateActualInterval2(availableSize, maxIntervalSize); + } + + private double CalculateActualInterval1(double availableSize, double maxIntervalSize) + { + int minTags = 5; + int maxTags = 20; + int numberOfTags = (int)(availableSize / maxIntervalSize); + double range = ActualMaximum - ActualMinimum; + double interval = range / numberOfTags; + const int k1 = 10; + interval = Math.Log10(interval / k1); + interval = Math.Ceiling(interval); + interval = Math.Pow(10, interval) * k1; + + if (range / interval > maxTags) interval *= 5; + if (range / interval < minTags) interval *= 0.5; + + if (interval <= 0) interval = 1; + return interval; + } + + /// + /// Returns the actual interval to use to determine which values are + /// displayed in the axis. + /// + /// The available size. + /// Actual interval to use to determine which values are + /// displayed in the axis. + /// + private double CalculateActualInterval2(double availableSize, double maxIntervalSize) + { + Func Exponent = x => Math.Ceiling(Math.Log(x, 10)); + Func Mantissa = x => x / Math.Pow(10, Exponent(x) - 1); + + // reduce intervals for horizontal axis. + // double maxIntervals = Orientation == AxisOrientation.X ? MaximumAxisIntervalsPer200Pixels * 0.8 : MaximumAxisIntervalsPer200Pixels; + // real maximum interval count + double maxIntervalCount = availableSize / maxIntervalSize; + + double range = Math.Abs(ActualMinimum - ActualMaximum); + double interval = Math.Pow(10, Exponent(range)); + double tempInterval = interval; + + // decrease interval until interval count becomes less than maxIntervalCount + while (true) + { + int mantissa = (int)Mantissa(tempInterval); + if (mantissa == 5) + { + // reduce 5 to 2 + tempInterval = RemoveNoiseFromDoubleMath(tempInterval / 2.5); + } + else if (mantissa == 2 || mantissa == 1 || mantissa == 10) + { + // reduce 2 to 1,10 to 5,1 to 0.5 + tempInterval = RemoveNoiseFromDoubleMath(tempInterval / 2.0); + } + + if (range / tempInterval > maxIntervalCount) + { + break; + } + + interval = tempInterval; + } + return interval; + } + + /// + /// Removes the noise from double math. + /// + /// The value. + /// A double without a noise. + internal static double RemoveNoiseFromDoubleMath(double value) + { + if (value == 0.0 || Math.Abs((Math.Log10(Math.Abs(value)))) < 27) + { + return (double)((decimal)value); + } + return Double.Parse(value.ToString(CultureInfo.InvariantCulture), CultureInfo.InvariantCulture); + } + + public void Include(double p) + { + if (double.IsNaN(p) || double.IsInfinity(p)) + return; + + if (double.IsNaN(ActualMinimum)) + ActualMinimum = p; + else + ActualMinimum = Math.Min(ActualMinimum, p); + + if (double.IsNaN(ActualMaximum)) + ActualMaximum = p; + else + ActualMaximum = Math.Max(ActualMaximum, p); + } + + } +} \ No newline at end of file diff -r 88d699a65cc2 -r 5be8f2773237 External/OxyPlot/OxyPlot/Axes/TickStyle.cs --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/External/OxyPlot/OxyPlot/Axes/TickStyle.cs Sat Jun 08 16:53:22 2013 +0000 @@ -0,0 +1,57 @@ +// -------------------------------------------------------------------------------------------------------------------- +// +// The MIT License (MIT) +// +// Copyright (c) 2012 Oystein Bjorke +// +// Permission is hereby granted, free of charge, to any person obtaining a +// copy of this software and associated documentation files (the +// "Software"), to deal in the Software without restriction, including +// without limitation the rights to use, copy, modify, merge, publish, +// distribute, sublicense, and/or sell copies of the Software, and to +// permit persons to whom the Software is furnished to do so, subject to +// the following conditions: +// +// The above copyright notice and this permission notice shall be included +// in all copies or substantial portions of the Software. +// +// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS +// OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF +// MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. +// IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY +// CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, +// TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE +// SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. +// +// +// Tick styles. +// +// -------------------------------------------------------------------------------------------------------------------- +namespace OxyPlot.Axes +{ + /// + /// Specifies the style of axis ticks. + /// + public enum TickStyle + { + /// + /// The ticks are rendered crossing the axis line. + /// + Crossing, + + /// + /// The ticks are rendered inside of the plot area. + /// + Inside, + + /// + /// The ticks are rendered Outside the plot area. + /// + Outside, + + /// + /// The ticks are not rendered. + /// + None + } +} \ No newline at end of file diff -r 88d699a65cc2 -r 5be8f2773237 External/OxyPlot/OxyPlot/Axes/TimeAxis.cs --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/External/OxyPlot/OxyPlot/Axes/TimeAxis.cs Sat Jun 08 16:53:22 2013 +0000 @@ -0,0 +1,120 @@ +// -------------------------------------------------------------------------------------------------------------------- +// +// The MIT License (MIT) +// +// Copyright (c) 2012 Oystein Bjorke +// +// Permission is hereby granted, free of charge, to any person obtaining a +// copy of this software and associated documentation files (the +// "Software"), to deal in the Software without restriction, including +// without limitation the rights to use, copy, modify, merge, publish, +// distribute, sublicense, and/or sell copies of the Software, and to +// permit persons to whom the Software is furnished to do so, subject to +// the following conditions: +// +// The above copyright notice and this permission notice shall be included +// in all copies or substantial portions of the Software. +// +// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS +// OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF +// MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. +// IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY +// CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, +// TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE +// SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. +// +// +// Time Axis +// The values should be in seconds. +// The StringFormat value can be used to force formatting of the axis values +// "h:mm" shows hours and minutes +// "m:ss" shows minutes and seconds +// +// -------------------------------------------------------------------------------------------------------------------- +using System; +using System.Linq; + +namespace OxyPlot +{ + /// + /// Time Axis + /// The values should be in seconds. + /// The StringFormat value can be used to force formatting of the axis values + /// "h:mm" shows hours and minutes + /// "m:ss" shows minutes and seconds + /// + public class TimeAxis : LinearAxis + { + /// + /// Initializes a new instance of the class. + /// + /// The position. + /// The axis title. + /// The string format for the axis values. + public TimeAxis(AxisPosition pos, string title = null, string format = "m:ss") + : base(pos, title) + { + StringFormat = format; + } + + /// + /// Initializes a new instance of the class. + /// + /// The position. + /// The min. + /// The max. + /// The axis title. + /// The string format for the axis values. + public TimeAxis(AxisPosition pos = AxisPosition.Bottom, double min = double.NaN, double max = double.NaN, + string title = null, string format = "m:ss") + : base(pos, min, max, title) + { + StringFormat = format; + } + + /// + /// Formats the value. + /// + /// The x. + /// + public override string FormatValue(double x) + { + var span = TimeSpan.FromSeconds(x); + string s = ActualStringFormat ?? "h:mm:ss"; + + s = s.Replace("mm", span.Minutes.ToString("00")); + s = s.Replace("ss", span.Seconds.ToString("00")); + s = s.Replace("hh", span.Hours.ToString("00")); + s = s.Replace("msec", span.Milliseconds.ToString("000")); + s = s.Replace("m", ((int)span.TotalMinutes).ToString("0")); + s = s.Replace("s", ((int)span.TotalSeconds).ToString("0")); + s = s.Replace("h", ((int)span.TotalHours).ToString("0")); + return s; + } + + protected override double CalculateActualInterval(double availableSize, double maxIntervalSize) + { + double range = Math.Abs(ActualMinimum - ActualMaximum); + double interval = 1; + var goodIntervals = new[] { 1.0, 5, 10, 30, 60, 120, 300, 600, 900, 1200, 1800, 3600 }; + + const int maxSteps = 20; + + while (true) + { + if (range / interval < maxSteps) + { + return interval; + } + + double nextInterval = goodIntervals.FirstOrDefault(i => i > interval); + if (nextInterval == 0) + { + nextInterval = interval * 2; + } + + interval = nextInterval; + } + } + } +} \ No newline at end of file diff -r 88d699a65cc2 -r 5be8f2773237 External/OxyPlot/OxyPlot/Axes/TimeSpanAxis.cs --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/External/OxyPlot/OxyPlot/Axes/TimeSpanAxis.cs Sat Jun 08 16:53:22 2013 +0000 @@ -0,0 +1,197 @@ +// -------------------------------------------------------------------------------------------------------------------- +// +// The MIT License (MIT) +// +// Copyright (c) 2012 Oystein Bjorke +// +// Permission is hereby granted, free of charge, to any person obtaining a +// copy of this software and associated documentation files (the +// "Software"), to deal in the Software without restriction, including +// without limitation the rights to use, copy, modify, merge, publish, +// distribute, sublicense, and/or sell copies of the Software, and to +// permit persons to whom the Software is furnished to do so, subject to +// the following conditions: +// +// The above copyright notice and this permission notice shall be included +// in all copies or substantial portions of the Software. +// +// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS +// OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF +// MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. +// IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY +// CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, +// TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE +// SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. +// +// +// Time axis. +// +// -------------------------------------------------------------------------------------------------------------------- +namespace OxyPlot.Axes +{ + using System; + using System.Linq; + + /// + /// Represents an axis presenting values. + /// + /// + /// The values should be in seconds. + /// The StringFormat value can be used to force formatting of the axis values + /// "h:mm" shows hours and minutes + /// "m:ss" shows minutes and seconds + /// + public class TimeSpanAxis : LinearAxis + { + /// + /// Initializes a new instance of the class. + /// + public TimeSpanAxis() + { + } + + /// + /// Initializes a new instance of the class. + /// + /// + /// The position. + /// + /// + /// The axis title. + /// + /// + /// The string format for the axis values. + /// + public TimeSpanAxis(AxisPosition pos, string title = null, string format = "m:ss") + : base(pos, title) + { + this.StringFormat = format; + } + + /// + /// Initializes a new instance of the class. + /// + /// + /// The position. + /// + /// + /// The min. + /// + /// + /// The max. + /// + /// + /// The axis title. + /// + /// + /// The string format for the axis values. + /// + public TimeSpanAxis( + AxisPosition pos = AxisPosition.Bottom, + double min = double.NaN, + double max = double.NaN, + string title = null, + string format = "m:ss") + : base(pos, min, max, title) + { + this.StringFormat = format; + } + + /// + /// Converts a time span to a double. + /// + /// + /// The time span. + /// + /// + /// A double value. + /// + public static double ToDouble(TimeSpan s) + { + return s.TotalSeconds; + } + + /// + /// Converts a double to a time span. + /// + /// + /// The value. + /// + /// + /// A time span. + /// + public static TimeSpan ToTimeSpan(double value) + { + return TimeSpan.FromSeconds(value); + } + + /// + /// Formats the value. + /// + /// + /// The x. + /// + /// + /// The format value. + /// + public override string FormatValue(double x) + { + TimeSpan span = TimeSpan.FromSeconds(x); + string s = this.ActualStringFormat ?? "h:mm:ss"; + + s = s.Replace("mm", span.Minutes.ToString("00")); + s = s.Replace("ss", span.Seconds.ToString("00")); + s = s.Replace("hh", span.Hours.ToString("00")); + s = s.Replace("msec", span.Milliseconds.ToString("000")); + s = s.Replace("m", ((int)span.TotalMinutes).ToString("0")); + s = s.Replace("s", ((int)span.TotalSeconds).ToString("0")); + s = s.Replace("h", ((int)span.TotalHours).ToString("0")); + return s; + } + + /// + /// Gets the value from an axis coordinate, converts from double to the correct data type if necessary. e.g. DateTimeAxis returns the DateTime and CategoryAxis returns category strings. + /// + /// The coordinate. + /// + /// The value. + /// + public override object GetValue(double x) + { + return TimeSpan.FromSeconds(x); + } + + /// + /// Calculates the actual interval. + /// + /// Size of the available area. + /// Maximum length of the intervals. + /// + /// The calculate actual interval. + /// + protected override double CalculateActualInterval(double availableSize, double maxIntervalSize) + { + double range = Math.Abs(this.ActualMinimum - this.ActualMaximum); + double interval = 1; + var goodIntervals = new[] { 1.0, 5, 10, 30, 60, 120, 300, 600, 900, 1200, 1800, 3600 }; + + int maxNumberOfIntervals = Math.Max((int)(availableSize / maxIntervalSize), 2); + + while (true) + { + if (range / interval < maxNumberOfIntervals) + { + return interval; + } + + double nextInterval = goodIntervals.FirstOrDefault(i => i > interval); + if (Math.Abs(nextInterval) < double.Epsilon) + { + nextInterval = interval * 2; + } + + interval = nextInterval; + } + } + } +} \ No newline at end of file diff -r 88d699a65cc2 -r 5be8f2773237 External/OxyPlot/OxyPlot/ClassDiagrams/PlotModel.cd --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/External/OxyPlot/OxyPlot/ClassDiagrams/PlotModel.cd Sat Jun 08 16:53:22 2013 +0000 @@ -0,0 +1,276 @@ + + + + + + + + + EBZwcA2UaBI/BUK9ZBHDJRgBY1uVERMI45sgpP2SPzE= + PlotModel\PlotModel.cs + + + + + + AAQCAAEIAiAAAGCAABBAAAAhRCAMEAAAADAAggACIgA= + Series\LineSeries.cs + + + + + + IAAAAAyAEAABgAAAACACAAAABAAEAAAAAAAAAgAAAAA= + Series\DataPointSeries.cs + + + + + + AgAAAAEAEAAAAIAAAAAACAAAAAAECAAAABMAAgIAAAA= + Series\AreaSeries.cs + + + + + + AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA= + Series\FunctionSeries.cs + + + + + + AAQAAAAAAQAAACAAAAAAAAAAAAAAAAAAAAEAAAAAQAA= + Axes\LinearAxis.cs + + + + + + AAAAAAAAAQAAEgAAAIAAABQAAAAAQAAAAAAAABQAQAA= + Axes\LogarithmicAxis.cs + + + + + + AAAAAAAAIAAAAAEAAAAAAAAAAAEAAAAAABEAAAAAAAA= + Axes\TimeSpanAxis.cs + + + + + + AIAAEAABMAAEEAgAIBAAAFAAAAAEnAAAAAEgAJAAABE= + Axes\CategoryAxis.cs + + + + + + gAIAAAAAIAAkGAEBAAAAIAAAggAAAAAAABEAAAAVAAA= + Axes\DateTimeAxis.cs + + + + + + gAAQAAAFAAAAAAAAAEAAQAQAAAAAAAAEABAADAACAAA= + Annotations\Annotation.cs + + + + + + BAAQEAAAACBwAIAAABgAgAAAEAAAAAAACTAAkgAgYGA= + Annotations\LineAnnotation.cs + + + + + + CAAAAAgAIAQAAAAAAAAAAAAAAIAAAABAAAAAEAAAAAA= + Series\BarSeries\BarSeries.cs + + + + + + sAAQAAE1WAAAAAAAAEAAQAQAAAAEAAAAABAUACACEAA= + Series\XYAxisSeries.cs + + + + + + AAAAAAEAAAAAAAAAAAAAAAAAAAAAAAAAABAAAAAABAA= + Series\CandleStickSeries.cs + + + + + + AAAAAAkBECABCAAAABgAAAQABAQEAAABAHAAggACAAA= + Series\HighLowSeries.cs + + + + + + AAAAAAAAAAAAAEAAAAAAAAAAAAAAAAAAAAAAAIIAAAA= + Series\ItemsSeries.cs + + + + + + AQAQAAEAWGAYACAIAAAAAAAgAAgEICJAgpQFAoCCAAI= + Series\PieSeries.cs + + + + + + AARQAAEIEAAAAEgQAAAIAAAgACBEAAAEABAwAgQDAgA= + Series\ScatterSeries.cs + + + + + + AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAABAAAgAAAAA= + Series\StairStepSeries.cs + + + + + + AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAABAAAgAAQAA= + Series\StemSeries.cs + + + + + + AAAAAAAAAQAAAAAAAAAAQAQAAAAEAAAAABAAAAAAAAA= + Axes\AngleAxis.cs + + + + + + AAAAAAAAAQAAAAAAAAAAQAQAAAAEAIAAABAAAAAAAAA= + Axes\MagnitudeAxis.cs + + + + + + AAAQAAEAWABAEEAAAAAAAAAAAAAEAAAAABAkBgISAAA= + Series\Series.cs + + + + + + + gEeXCAGRedQgH2V09tJAe5wCkhCEgABEG1cgxZQB4CU= + Axes\Axis.cs + + + + + + AAQACAAAACBAQAAAQFAAAAAAABAAAAAAgDAAgAAAAAg= + Annotations\ArrowAnnotation.cs + + + + + + AAAAAAAAACBggAAAABAAAAAAAAAACAAAADAAgAAAAAA= + Annotations\PolygonAnnotation.cs + + + + + + AAAAAAAgACBAAIAggAAAAAAAAAgAAAIAABIggAAAgAA= + Annotations\TextAnnotation.cs + + + + + + BYQAAIEAKCSAACCQAAAAAAABAAgEIBBAAhAUAgoCAAE= + Series\BarSeries\BarSeriesBase.cs + + + + + + + AAAAAAgAIAQAAAAAAEAAAAAAAIAAAABAAAAAEAAAAAA= + Series\BarSeries\ColumnSeries.cs + + + + + + DQQAAAkBGCSACECAAAAAAAABAIgEIgAAABAUEgoCAAE= + Series\BarSeries\IntervalBarSeries.cs + + + + + + + AAAAAAEAECCACACAAAAAAAAAAAgEAAAAABAQAggCAAE= + Series\BarSeries\RectangleBarSeries.cs + + + + + + DYQAAAsBGCUACEAAAQAgAAABAKgEAoAAABAUEgICAAE= + Series\BarSeries\TornadoBarSeries.cs + + + + + + AAAAABAAAQAAAAAAAQIAACAAAAAAAAiAABAAAQAAAAA= + Axes\ColorAxis.cs + + + + + + AAAAAAAAEAAACEAAAAAAAAAAAAAAAgAAAAAAAAAAAAA= + Series\BarSeries\BarSeriesBase{T}.cs + + + + + + AAAAAAgAAAAAAAAAAAAAAAAAAIAAAgAAAAAAEAAAAAA= + Series\BarSeries\CategorizedSeries.cs + + + + + + AAAIAAAAAEAAAAAAAAAAAAAAAAAEABAAAAAAAAAAAAA= + Series\BarSeries\ErrorColumnSeries.cs + + + + + + AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAABAAAgAQAAA= + Series\ITrackableSeries.cs + + + + \ No newline at end of file diff -r 88d699a65cc2 -r 5be8f2773237 External/OxyPlot/OxyPlot/ClassDiagrams/Reporting.cd --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/External/OxyPlot/OxyPlot/ClassDiagrams/Reporting.cd Sat Jun 08 16:53:22 2013 +0000 @@ -0,0 +1,204 @@ + + + + + + + + + + + + + AAQAAAAAAAAAAAAAAAAAAEAAAAAAAAAAAAAAAABgQAA= + Reporting\Report\TableOfContents.cs + + + + + + AAAAAAAAAgAAAAAAAAAAAEAAAAgAAAAAAAAAAAAAAAA= + Reporting\Report\DrawingFigure.cs + + + + + + + + + + + + + AAAAAAAAAgAAAAAAAAAAAEAAAAAAAAAACAAAAAAAAAA= + Reporting\Report\Equation.cs + + + + + + + + + + + + + AAAAAAEgAAAIAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA= + Reporting\Report\Figure.cs + + + + + + + + + + + + + AAAAAAAAAAAAAAAEAAAAAEAAAAAAAAABAgAACAAAAAA= + Reporting\Report\Header.cs + + + + + + AAAAAAAAAgAAAAAAAAAAAEAAAAAAAAAAAAAAAAAAAAA= + Reporting\Report\Image.cs + + + + + + + + + + + + + AAAAAAAAAAAAAAAAAAAAAEAAAAAAAAAAAAAACAAAAAA= + Reporting\Report\Paragraph.cs + + + + + + AAAAAAAABAAAAAAAAAAAAEAAAAAAAAAAAAAAAAAAQAA= + Reporting\Report\PlotFigure.cs + + + + + + + + + + + + + AICAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA= + Reporting\Report\PropertyTable.cs + + + + + + AAAAAAAAAAAAAEAAgAAAAEAAAAAAAAAAAAAAAAEAAAA= + Reporting\Report\Report.cs + + + + + + AAcGAAAAAACCAAAAAAAEAEAAAAAAAAAAAAAAAAELCAA= + Reporting\Report\ReportItem.cs + + + + + + + + + + + + + AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA= + Reporting\Report\ReportSection.cs + + + + + + + + + + + + + AAQAAAAgAAAAAEAgAAAAAEBAAAAAAAEACAAAAAgAAAA= + Reporting\Report\Table.cs + + + + + + ACAAgAAAAAAgAIQAAAAQAAAAAAoUAABAIEIkAAigAAA= + Reporting\ReportWriters\HtmlReportWriter.cs + + + + + + + ACABgAAAACAsAAQABAAAAAQAAAAAIAAAAEAkAAAiAAA= + Reporting\ReportWriters\LatexReportWriter.cs + + + + + + + ICAAgABAAAAgAAQIAAAACIAEAAAAAAAAAEAkAAAgAAA= + Reporting\ReportWriters\TextReportWriter.cs + + + + + + + + + + + + + + AAAAAgAAIAAACAAAACgIAEAAAAAAAAAAAAAAAAhAgAA= + Reporting\Report\ItemsTable.cs + + + + + + ICAAkABAAAAgAAQIAAAACIAEAAAAAACEAEAkAAAgAAA= + Reporting\ReportWriters\WikiReportWriter.cs + + + + + + + ACAAgAAAAAAgAAQAAAAAAAAAAAAAAAAAAEAkAAAgAAA= + Reporting\ReportWriters\IReportWriter.cs + + + + \ No newline at end of file diff -r 88d699a65cc2 -r 5be8f2773237 External/OxyPlot/OxyPlot/ClassDiagrams/Series.cd --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/External/OxyPlot/OxyPlot/ClassDiagrams/Series.cd Sat Jun 08 16:53:22 2013 +0000 @@ -0,0 +1,161 @@ + + + + + + AAQCAAEIAiAAAGCAABBAAAAhRCAMEAAAADAAggAKIgA= + Series\LineSeries.cs + + + + + + IAAAAAyAEAABgAAAACACAAAABAAEAAAAAAAAAgAAAAA= + Series\DataPointSeries.cs + + + + + + AgAAAAEAEAAAAIAAAAAACAAAAAAECAAAABMAAgIAAAA= + Series\AreaSeries.cs + + + + + + AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA= + Series\FunctionSeries.cs + + + + + + CAAAAAgAIAQAAAAAAAAAAAAAAIAAAABAAAAAEAAAAAA= + Series\BarSeries\BarSeries.cs + + + + + + sAAQAAE1WAAAAAAAAEAAQAQAAAAEAAAAABAUACACEAA= + Series\XYAxisSeries.cs + + + + + + AAAAAAEAAAAAAAAAAAAAAAAAAAAAAAAAABAAAAAABAA= + Series\CandleStickSeries.cs + + + + + + AAAAAAkBECABCAAAABgAAAQABAQEAAABAHAAggAKAAA= + Series\HighLowSeries.cs + + + + + + AAAAAAAAAAAAAEAAAAAAAAAAAAAAAAAAAAAAAIIAAAA= + Series\ItemsSeries.cs + + + + + + AQAQAAEAWGAYACAIAAAAAAAgAAgEICJAgpQFAoCCAAI= + Series\PieSeries.cs + + + + + + AARQAAEIEAAAAEgQAAAIAAAgACBEQAIEABAwAgQDAgA= + Series\ScatterSeries.cs + + + + + + AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAABAAAgAAAAA= + Series\StairStepSeries.cs + + + + + + AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAABAAAgAAQAA= + Series\StemSeries.cs + + + + + + AAAQAAEAWABAEEAAAAAAAAAAAAAEAAAAABAkBgISAAA= + Series\Series.cs + + + + + + + BYQAgIEAKCSAACCQAAAAAAABAAgEIBBAAhAUEgoCAAE= + Series\BarSeries\BarSeriesBase.cs + + + + + + + AAAAAAgAIAQAAAAAAEAAAAAAAIAAAABAAAAAEAAAAAA= + Series\BarSeries\ColumnSeries.cs + + + + + + DQQAgAkBGCSACECAAAAAAAABAIgEIgAAABAUEgoCAAE= + Series\BarSeries\IntervalBarSeries.cs + + + + + + + AAAAgAEAECCACACAAAAAAAAAAAgEAAAAABAQEggCAAE= + Series\BarSeries\RectangleBarSeries.cs + + + + + + DYQAAAsBGCUICEAABQAgAAAFAKgEAoAAABA0EgICAAE= + Series\BarSeries\TornadoBarSeries.cs + + + + + + AAAAAAAAEAAACEAAAAAAAAAAAAAAAgAAAAAAAAAAAAA= + Series\BarSeries\BarSeriesBase{T}.cs + + + + + + AAAAAAgAAAAAAAAAAAAAAAAAAIAAAgAAAAAAEAAAAAA= + Series\BarSeries\CategorizedSeries.cs + + + + + + AAAIAAAAAEAAAAAAAAAAAAAAAAAEABAAAAAAAAAAAAA= + Series\BarSeries\ErrorColumnSeries.cs + + + + \ No newline at end of file diff -r 88d699a65cc2 -r 5be8f2773237 External/OxyPlot/OxyPlot/Foundation/ArrayHelper.cs --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/External/OxyPlot/OxyPlot/Foundation/ArrayHelper.cs Sat Jun 08 16:53:22 2013 +0000 @@ -0,0 +1,124 @@ +// -------------------------------------------------------------------------------------------------------------------- +// +// The MIT License (MIT) +// +// Copyright (c) 2012 Oystein Bjorke +// +// Permission is hereby granted, free of charge, to any person obtaining a +// copy of this software and associated documentation files (the +// "Software"), to deal in the Software without restriction, including +// without limitation the rights to use, copy, modify, merge, publish, +// distribute, sublicense, and/or sell copies of the Software, and to +// permit persons to whom the Software is furnished to do so, subject to +// the following conditions: +// +// The above copyright notice and this permission notice shall be included +// in all copies or substantial portions of the Software. +// +// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS +// OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF +// MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. +// IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY +// CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, +// TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE +// SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. +// +// +// Array helper methods. +// +// -------------------------------------------------------------------------------------------------------------------- +namespace OxyPlot +{ + using System; + + /// + /// Provides utility methods for vector generation. + /// + public static class ArrayHelper + { + /// + /// Creates a vector. + /// + /// + /// The first value. + /// + /// + /// The last value. + /// + /// + /// The number of steps. + /// + /// + /// A vector. + /// + public static double[] CreateVector(double x0, double x1, int n) + { + var result = new double[n]; + for (int i = 0; i < n; i++) + { + result[i] = (x0 + ((x1 - x0) * i / (n - 1))).RemoveNoise(); + } + + return result; + } + + /// + /// Creates a vector. + /// + /// + /// The first value. + /// + /// + /// The last value. + /// + /// + /// The step size. + /// + /// + /// A vector. + /// + public static double[] CreateVector(double x0, double x1, double dx) + { + var n = (int)Math.Round((x1 - x0) / dx); + var result = new double[n + 1]; + for (int i = 0; i <= n; i++) + { + result[i] = (x0 + (i * dx)).RemoveNoise(); + } + + return result; + } + + /// + /// Evaluates the specified function. + /// + /// + /// The function. + /// + /// + /// The x values. + /// + /// + /// The y values. + /// + /// + /// Array of evaluations. The value of f(x_i,y_j) will be placed at index [i, j]. + /// + public static double[,] Evaluate(Func f, double[] x, double[] y) + { + int m = x.Length; + int n = y.Length; + var result = new double[m, n]; + for (int i = 0; i < m; i++) + { + for (int j = 0; j < n; j++) + { + result[i, j] = f(x[i], y[j]); + } + } + + return result; + } + + } +} \ No newline at end of file diff -r 88d699a65cc2 -r 5be8f2773237 External/OxyPlot/OxyPlot/Foundation/CanonicalSplineHelper.cs --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/External/OxyPlot/OxyPlot/Foundation/CanonicalSplineHelper.cs Sat Jun 08 16:53:22 2013 +0000 @@ -0,0 +1,252 @@ +// -------------------------------------------------------------------------------------------------------------------- +// +// The MIT License (MIT) +// +// Copyright (c) 2012 Oystein Bjorke +// +// Permission is hereby granted, free of charge, to any person obtaining a +// copy of this software and associated documentation files (the +// "Software"), to deal in the Software without restriction, including +// without limitation the rights to use, copy, modify, merge, publish, +// distribute, sublicense, and/or sell copies of the Software, and to +// permit persons to whom the Software is furnished to do so, subject to +// the following conditions: +// +// The above copyright notice and this permission notice shall be included +// in all copies or substantial portions of the Software. +// +// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS +// OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF +// MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. +// IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY +// CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, +// TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE +// SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. +// +// +// Interpolates a list of points using a canonical spline. +// +// -------------------------------------------------------------------------------------------------------------------- +namespace OxyPlot +{ + using System; + using System.Collections.Generic; + using System.Linq; + + /// + /// Provides functionality to interpolate a list of points by a canonical spline. + /// + internal static class CanonicalSplineHelper + { + // CanonicalSplineHelper.cs (c) 2009 by Charles Petzold (WPF and Silverlight) + // www.charlespetzold.com/blog/2009/01/Canonical-Splines-in-WPF-and-Silverlight.html + /// + /// Creates a spline of data points. + /// + /// + /// The points. + /// + /// + /// The tension. + /// + /// + /// The tensions. + /// + /// + /// True if the spline is closed. + /// + /// + /// The tolerance. + /// + /// + /// A list of data points. + /// + internal static List CreateSpline( + IList points, double tension, IList tensions, bool isClosed, double tolerance) + { + var screenPoints = points.Select(p => new ScreenPoint(p.X, p.Y)).ToList(); + var interpolatedScreenPoints = CreateSpline(screenPoints, tension, tensions, isClosed, tolerance); + var interpolatedDataPoints = new List(interpolatedScreenPoints.Count); + + foreach (var s in interpolatedScreenPoints) + { + interpolatedDataPoints.Add(new DataPoint(s.X, s.Y)); + } + + return interpolatedDataPoints; + } + + /// + /// Creates a spline of screen points. + /// + /// + /// The points. + /// + /// + /// The tension. + /// + /// + /// The tensions. + /// + /// + /// True if the spline is closed. + /// + /// + /// The tolerance. + /// + /// + /// A list of screen points. + /// + internal static List CreateSpline( + IList points, double tension, IList tensions, bool isClosed, double tolerance) + { + var result = new List(); + if (points == null) + { + return result; + } + + int n = points.Count; + if (n < 1) + { + return result; + } + + if (n < 2) + { + result.AddRange(points); + return result; + } + + if (n == 2) + { + if (!isClosed) + { + Segment(result, points[0], points[0], points[1], points[1], tension, tension, tolerance); + } + else + { + Segment(result, points[1], points[0], points[1], points[0], tension, tension, tolerance); + Segment(result, points[0], points[1], points[0], points[1], tension, tension, tolerance); + } + } + else + { + bool useTensionCollection = tensions != null && tensions.Count > 0; + + for (int i = 0; i < n; i++) + { + double t1 = useTensionCollection ? tensions[i % tensions.Count] : tension; + double t2 = useTensionCollection ? tensions[(i + 1) % tensions.Count] : tension; + + if (i == 0) + { + Segment( + result, + isClosed ? points[n - 1] : points[0], + points[0], + points[1], + points[2], + t1, + t2, + tolerance); + } + else if (i == n - 2) + { + Segment( + result, + points[i - 1], + points[i], + points[i + 1], + isClosed ? points[0] : points[i + 1], + t1, + t2, + tolerance); + } + else if (i == n - 1) + { + if (isClosed) + { + Segment(result, points[i - 1], points[i], points[0], points[1], t1, t2, tolerance); + } + } + else + { + Segment(result, points[i - 1], points[i], points[i + 1], points[i + 2], t1, t2, tolerance); + } + } + } + + return result; + } + + /// + /// The segment. + /// + /// + /// The points. + /// + /// + /// The pt 0. + /// + /// + /// The pt 1. + /// + /// + /// The pt 2. + /// + /// + /// The pt 3. + /// + /// + /// The t 1. + /// + /// + /// The t 2. + /// + /// + /// The tolerance. + /// + private static void Segment( + IList points, + ScreenPoint pt0, + ScreenPoint pt1, + ScreenPoint pt2, + ScreenPoint pt3, + double t1, + double t2, + double tolerance) + { + // See Petzold, "Programming Microsoft Windows with C#", pages 645-646 or + // Petzold, "Programming Microsoft Windows with Microsoft Visual Basic .NET", pages 638-639 + // for derivation of the following formulas: + double sx1 = t1 * (pt2.X - pt0.X); + double sy1 = t1 * (pt2.Y - pt0.Y); + double sx2 = t2 * (pt3.X - pt1.X); + double sy2 = t2 * (pt3.Y - pt1.Y); + + double ax = sx1 + sx2 + 2 * pt1.X - 2 * pt2.X; + double ay = sy1 + sy2 + 2 * pt1.Y - 2 * pt2.Y; + double bx = -2 * sx1 - sx2 - 3 * pt1.X + 3 * pt2.X; + double by = -2 * sy1 - sy2 - 3 * pt1.Y + 3 * pt2.Y; + + double cx = sx1; + double cy = sy1; + double dx = pt1.X; + double dy = pt1.Y; + + var num = (int)((Math.Abs(pt1.X - pt2.X) + Math.Abs(pt1.Y - pt2.Y)) / tolerance); + + // Notice begins at 1 so excludes the first point (which is just pt1) + for (int i = 1; i < num; i++) + { + double t = (double)i / (num - 1); + var pt = new ScreenPoint( + ax * t * t * t + bx * t * t + cx * t + dx, + ay * t * t * t + by * t * t + cy * t + dy); + points.Add(pt); + } + } + + } +} \ No newline at end of file diff -r 88d699a65cc2 -r 5be8f2773237 External/OxyPlot/OxyPlot/Foundation/CodeGenerator/CodeGenerationAttribute.cs --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/External/OxyPlot/OxyPlot/Foundation/CodeGenerator/CodeGenerationAttribute.cs Sat Jun 08 16:53:22 2013 +0000 @@ -0,0 +1,57 @@ +// -------------------------------------------------------------------------------------------------------------------- +// +// The MIT License (MIT) +// +// Copyright (c) 2012 Oystein Bjorke +// +// Permission is hereby granted, free of charge, to any person obtaining a +// copy of this software and associated documentation files (the +// "Software"), to deal in the Software without restriction, including +// without limitation the rights to use, copy, modify, merge, publish, +// distribute, sublicense, and/or sell copies of the Software, and to +// permit persons to whom the Software is furnished to do so, subject to +// the following conditions: +// +// The above copyright notice and this permission notice shall be included +// in all copies or substantial portions of the Software. +// +// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS +// OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF +// MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. +// IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY +// CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, +// TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE +// SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. +// +// +// Attribute that controls if code should be generated for the property. +// +// -------------------------------------------------------------------------------------------------------------------- +namespace OxyPlot +{ + using System; + + /// + /// Specifies whether code should be generated for the property. + /// + [AttributeUsage(AttributeTargets.Property)] + public class CodeGenerationAttribute : Attribute + { + /// + /// Initializes a new instance of the class. + /// + /// + /// The generate code. + /// + public CodeGenerationAttribute(bool generateCode) + { + this.GenerateCode = generateCode; + } + + /// + /// Gets or sets a value indicating whether GenerateCode. + /// + public bool GenerateCode { get; set; } + + } +} \ No newline at end of file diff -r 88d699a65cc2 -r 5be8f2773237 External/OxyPlot/OxyPlot/Foundation/CodeGenerator/CodeGenerator.cs --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/External/OxyPlot/OxyPlot/Foundation/CodeGenerator/CodeGenerator.cs Sat Jun 08 16:53:22 2013 +0000 @@ -0,0 +1,448 @@ +// -------------------------------------------------------------------------------------------------------------------- +// +// The MIT License (MIT) +// +// Copyright (c) 2012 Oystein Bjorke +// +// Permission is hereby granted, free of charge, to any person obtaining a +// copy of this software and associated documentation files (the +// "Software"), to deal in the Software without restriction, including +// without limitation the rights to use, copy, modify, merge, publish, +// distribute, sublicense, and/or sell copies of the Software, and to +// permit persons to whom the Software is furnished to do so, subject to +// the following conditions: +// +// The above copyright notice and this permission notice shall be included +// in all copies or substantial portions of the Software. +// +// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS +// OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF +// MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. +// IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY +// CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, +// TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE +// SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. +// +// +// Generates c# code for the specified PlotModel. +// +// -------------------------------------------------------------------------------------------------------------------- +namespace OxyPlot +{ + using System; + using System.Collections; + using System.Collections.Generic; + using System.Globalization; + using System.Reflection; + using System.Text; + using System.Text.RegularExpressions; + + /// + /// Provides functionality to generate C# code for the specified . + /// + /// + /// This is useful for creating examples or unit tests. Press Ctrl+Alt+C in a plot to copy code to the clipboard. + /// Usage: + /// var cg = new CodeGenerator(myPlotModel); + /// Clipboard.SetText(cg.ToCode()); + /// + public class CodeGenerator + { + /// + /// The sb. + /// + private readonly StringBuilder sb; + + /// + /// The variables. + /// + private readonly Dictionary variables; + + /// + /// The indent string. + /// + private string indentString; + + /// + /// The indents. + /// + private int indents; + + /// + /// Initializes a new instance of the class. + /// + /// + /// The model. + /// + public CodeGenerator(PlotModel model) + { + this.variables = new Dictionary(); + this.sb = new StringBuilder(); + this.Indents = 8; + var title = model.Title ?? "Untitled"; + this.AppendLine("[Example({0})]", title.ToCode()); + string methodName = this.MakeValidVariableName(title); + this.AppendLine("public static PlotModel {0}()", methodName); + this.AppendLine("{"); + this.Indents += 4; + string modelName = this.Add(model); + this.AddChildren(modelName, "Axes", model.Axes); + this.AddChildren(modelName, "Series", model.Series); + this.AddChildren(modelName, "Annotations", model.Annotations); + this.AppendLine("return {0};", modelName); + this.Indents -= 4; + this.AppendLine("}"); + } + + /// + /// Gets or sets Indents. + /// + private int Indents + { + get + { + return this.indents; + } + + set + { + this.indents = value; + this.indentString = new string(' ', value); + } + } + + /// + /// Formats the code. + /// + /// + /// The format. + /// + /// + /// The values. + /// + /// + /// The format code. + /// + public static string FormatCode(string format, params object[] values) + { + var encodedValues = new object[values.Length]; + for (int i = 0; i < values.Length; i++) + { + encodedValues[i] = values[i].ToCode(); + } + + return string.Format(format, encodedValues); + } + + /// + /// Formats a constructor. + /// + /// + /// The type. + /// + /// + /// The format of the constructor arguments. + /// + /// + /// The argument values. + /// + /// + /// The format constructor. + /// + public static string FormatConstructor(Type type, string format, params object[] values) + { + return string.Format("new {0}({1})", type.Name, FormatCode(format, values)); + } + + /// + /// Returns the c# code for this model. + /// + /// + /// C# code. + /// + public string ToCode() + { + return this.sb.ToString(); + } + + /// + /// Adds the specified object to the generated code. + /// + /// + /// The object. + /// + /// + /// The variable name. + /// + private string Add(object obj) + { + Type type = obj.GetType(); + object defaultInstance = Activator.CreateInstance(type); + string varName = this.GetNewVariableName(type); + this.variables.Add(varName, true); + this.AppendLine("var {0} = new {1}();", varName, type.Name); + this.SetProperties(obj, varName, defaultInstance); + return varName; + } + + /// + /// Adds the children. + /// + /// + /// The name. + /// + /// + /// Name of the collection. + /// + /// + /// The children. + /// + private void AddChildren(string name, string collectionName, IEnumerable children) + { + foreach (var child in children) + { + string childName = this.Add(child); + this.AppendLine("{0}.{1}.Add({2});", name, collectionName, childName); + } + } + + /// + /// Adds the items. + /// + /// + /// The name. + /// + /// + /// The list. + /// + private void AddItems(string name, IList list) + { + foreach (var item in list) + { + var code = item.ToCode(); + if (code == null) + { + continue; + } + + this.AppendLine("{0}.Add({1});", name, code); + } + } + + /// + /// Appends the line. + /// + /// + /// The format string. + /// + /// + /// The args. + /// + private void AppendLine(string format, params object[] args) + { + if (args.Length > 0) + { + this.sb.AppendLine(this.indentString + string.Format(CultureInfo.InvariantCulture, format, args)); + } + else + { + this.sb.AppendLine(this.indentString + format); + } + } + + /// + /// Determines if the two specifed lists are equal. + /// + /// + /// The first list. + /// + /// + /// The second list. + /// + /// + /// True if all items are equal. + /// + private bool AreListsEqual(IList list1, IList list2) + { + if (list1 == null || list2 == null) + { + return false; + } + + if (list1.Count != list2.Count) + { + return false; + } + + for (int i = 0; i < list1.Count; i++) + { + if (!list1[i].Equals(list2[i])) + { + return false; + } + } + + return true; + } + + /// + /// Get the first attribute of the specified type. + /// + /// + /// The property info. + /// + /// + /// The type. + /// + /// + /// The attribute, or null if no attribute was found. + /// + private T GetFirstAttribute(PropertyInfo pi) where T : Attribute + { + foreach (T a in pi.GetCustomAttributes(typeof(CodeGenerationAttribute), true)) + { + return a; + } + + return null; + } + + /// + /// Gets a new variable name of the specified type. + /// + /// + /// The type. + /// + /// + /// The variable name. + /// + private string GetNewVariableName(Type type) + { + string prefix = type.Name; + prefix = char.ToLower(prefix[0]) + prefix.Substring(1); + int i = 1; + while (this.variables.ContainsKey(prefix + i)) + { + i++; + } + + return prefix + i; + } + + /// + /// Makes a valid variable name of a string. Invalid characters will simply be removed. + /// + /// + /// The title. + /// + /// + /// A valid variable name. + /// + private string MakeValidVariableName(string title) + { + if (title == null) + { + return null; + } + + var regex = new Regex("[a-zA-Z_][a-zA-Z0-9_]*"); + var result = new StringBuilder(); + foreach (var c in title) + { + string s = c.ToString(); + if (regex.Match(s).Success) + { + result.Append(s); + } + } + + return result.ToString(); + } + + /// + /// The set properties. + /// + /// + /// The instance. + /// + /// + /// The var name. + /// + /// + /// The default values. + /// + private void SetProperties(object instance, string varName, object defaultValues) + { + var instanceType = instance.GetType(); + var listsToAdd = new Dictionary(); + foreach (var pi in instanceType.GetProperties()) + { + // check the [CodeGeneration] attribute + var cga = this.GetFirstAttribute(pi); + if (cga != null && !cga.GenerateCode) + { + continue; + } + + string name = varName + "." + pi.Name; + object value = pi.GetValue(instance, null); + object defaultValue = pi.GetValue(defaultValues, null); + + // check if lists are equal + if (this.AreListsEqual(value as IList, defaultValue as IList)) + { + continue; + } + + // add items of lists + var list = value as IList; + if (list != null) + { + listsToAdd.Add(name, list); + continue; + } + + // only properties with public setters are used + var setter = pi.GetSetMethod(); + if (setter == null || !setter.IsPublic) + { + continue; + } + + // skip default values + if ((value != null && value.Equals(defaultValue)) || value == defaultValue) + { + continue; + } + + this.SetProperty(name, value); + } + + // Add the items of the lists + foreach (var kvp in listsToAdd) + { + var name = kvp.Key; + var list = kvp.Value; + this.AddItems(name, list); + } + } + + /// + /// Sets the property. + /// + /// + /// The property name. + /// + /// + /// The value. + /// + private void SetProperty(string name, object value) + { + string code = value.ToCode(); + if (code != null) + { + this.AppendLine("{0} = {1};", name, code); + } + } + } +} \ No newline at end of file diff -r 88d699a65cc2 -r 5be8f2773237 External/OxyPlot/OxyPlot/Foundation/CodeGenerator/CodeGeneratorStringExtensions.cs --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/External/OxyPlot/OxyPlot/Foundation/CodeGenerator/CodeGeneratorStringExtensions.cs Sat Jun 08 16:53:22 2013 +0000 @@ -0,0 +1,188 @@ +// -------------------------------------------------------------------------------------------------------------------- +// +// The MIT License (MIT) +// +// Copyright (c) 2012 Oystein Bjorke +// +// Permission is hereby granted, free of charge, to any person obtaining a +// copy of this software and associated documentation files (the +// "Software"), to deal in the Software without restriction, including +// without limitation the rights to use, copy, modify, merge, publish, +// distribute, sublicense, and/or sell copies of the Software, and to +// permit persons to whom the Software is furnished to do so, subject to +// the following conditions: +// +// The above copyright notice and this permission notice shall be included +// in all copies or substantial portions of the Software. +// +// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS +// OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF +// MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. +// IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY +// CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, +// TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE +// SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. +// +// +// The code generator string extensions. +// +// -------------------------------------------------------------------------------------------------------------------- +namespace OxyPlot +{ + using System; + using System.Globalization; + + /// + /// Provides extension methods for code generation. + /// + public static class CodeGeneratorStringExtensions + { + /// + /// Converts the value of this instance to c# code. + /// + /// + /// The instance. + /// + /// + /// C# code. + /// + public static string ToCode(this string value) + { + value = value.Replace("\"", "\\\""); + value = value.Replace("\r\n", "\\n"); + value = value.Replace("\n", "\\n"); + value = value.Replace("\t", "\\t"); + return "\"" + value + "\""; + } + + /// + /// Converts the value of this instance to c# code. + /// + /// + /// The value. + /// + /// + /// C# code. + /// + public static string ToCode(this bool value) + { + return value.ToString().ToLower(); + } + + /// + /// Converts the value of this instance to c# code. + /// + /// + /// The instance. + /// + /// + /// C# code. + /// + public static string ToCode(this int value) + { + return value.ToString(CultureInfo.InvariantCulture); + } + + /// + /// Converts the value of this instance to c# code. + /// + /// + /// The instance. + /// + /// + /// C# code. + /// + public static string ToCode(this Enum value) + { + return string.Format("{0}.{1}", value.GetType().Name, value); + } + + /// + /// Converts the value of this instance to c# code. + /// + /// + /// The instance. + /// + /// + /// C# code. + /// + public static string ToCode(this double value) + { + if (double.IsNaN(value)) + { + return "double.NaN"; + } + + if (double.IsPositiveInfinity(value)) + { + return "double.PositiveInfinity"; + } + + if (double.IsNegativeInfinity(value)) + { + return "double.NegativeInfinity"; + } + + if (value.Equals(double.MinValue)) + { + return "double.MinValue"; + } + + if (value.Equals(double.MaxValue)) + { + return "double.MaxValue"; + } + + return value.ToString(CultureInfo.InvariantCulture); + } + + /// + /// Converts the value of this instance to c# code. + /// + /// + /// The instance. + /// + /// + /// C# code. + /// + public static string ToCode(this object value) + { + if (value == null) + { + return "null"; + } + + if (value is int) + { + return ((int)value).ToCode(); + } + + if (value is double) + { + return ((double)value).ToCode(); + } + + if (value is string) + { + return ((string)value).ToCode(); + } + + if (value is bool) + { + return ((bool)value).ToCode(); + } + + if (value is Enum) + { + return ((Enum)value).ToCode(); + } + + if (value is ICodeGenerating) + { + return ((ICodeGenerating)value).ToCode(); + } + + return null; + } + } +} \ No newline at end of file diff -r 88d699a65cc2 -r 5be8f2773237 External/OxyPlot/OxyPlot/Foundation/CodeGenerator/ICodeGenerating.cs --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/External/OxyPlot/OxyPlot/Foundation/CodeGenerator/ICodeGenerating.cs Sat Jun 08 16:53:22 2013 +0000 @@ -0,0 +1,45 @@ +// -------------------------------------------------------------------------------------------------------------------- +// +// The MIT License (MIT) +// +// Copyright (c) 2012 Oystein Bjorke +// +// Permission is hereby granted, free of charge, to any person obtaining a +// copy of this software and associated documentation files (the +// "Software"), to deal in the Software without restriction, including +// without limitation the rights to use, copy, modify, merge, publish, +// distribute, sublicense, and/or sell copies of the Software, and to +// permit persons to whom the Software is furnished to do so, subject to +// the following conditions: +// +// The above copyright notice and this permission notice shall be included +// in all copies or substantial portions of the Software. +// +// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS +// OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF +// MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. +// IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY +// CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, +// TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE +// SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. +// +// +// Provides functionality to generate c# code of an object. +// +// -------------------------------------------------------------------------------------------------------------------- +namespace OxyPlot +{ + /// + /// Provides functionality to generate C# code of an object. + /// + public interface ICodeGenerating + { + /// + /// Returns c# code that generates this instance. + /// + /// + /// C# code. + /// + string ToCode(); + } +} \ No newline at end of file diff -r 88d699a65cc2 -r 5be8f2773237 External/OxyPlot/OxyPlot/Foundation/CohenSutherlandClipping.cs --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/External/OxyPlot/OxyPlot/Foundation/CohenSutherlandClipping.cs Sat Jun 08 16:53:22 2013 +0000 @@ -0,0 +1,298 @@ +// -------------------------------------------------------------------------------------------------------------------- +// +// The MIT License (MIT) +// +// Copyright (c) 2012 Oystein Bjorke +// +// Permission is hereby granted, free of charge, to any person obtaining a +// copy of this software and associated documentation files (the +// "Software"), to deal in the Software without restriction, including +// without limitation the rights to use, copy, modify, merge, publish, +// distribute, sublicense, and/or sell copies of the Software, and to +// permit persons to whom the Software is furnished to do so, subject to +// the following conditions: +// +// The above copyright notice and this permission notice shall be included +// in all copies or substantial portions of the Software. +// +// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS +// OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF +// MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. +// IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY +// CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, +// TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE +// SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. +// +// +// Line clipping algorithm. +// +// -------------------------------------------------------------------------------------------------------------------- +namespace OxyPlot +{ + /// + /// Provides a line clipping algorithm. + /// + /// + /// See http://en.wikipedia.org/wiki/Cohen%E2%80%93Sutherland + /// + public class CohenSutherlandClipping + { + /// + /// The bottom code. + /// + private const int Bottom = 4; // 0100 + + /// + /// The inside code. + /// + private const int Inside = 0; // 0000 + + /// + /// The left code. + /// + private const int Left = 1; // 0001 + + /// + /// The right code. + /// + private const int Right = 2; // 0010 + + /// + /// The top code. + /// + private const int Top = 8; // 1000 + + /// + /// The x maximum. + /// + private readonly double xmax; + + /// + /// The x minimum. + /// + private readonly double xmin; + + /// + /// The y maximum. + /// + private readonly double ymax; + + /// + /// The y minimum. + /// + private readonly double ymin; + + /// + /// Initializes a new instance of the class. + /// + /// + /// The clipping rectangle. + /// + public CohenSutherlandClipping(OxyRect rect) + { + this.xmin = rect.Left; + this.xmax = rect.Right; + this.ymin = rect.Top; + this.ymax = rect.Bottom; + } + + /// + /// Initializes a new instance of the class. + /// + /// + /// The xmin. + /// + /// + /// The xmax. + /// + /// + /// The ymin. + /// + /// + /// The ymax. + /// + public CohenSutherlandClipping(double xmin, double xmax, double ymin, double ymax) + { + this.xmin = xmin; + this.ymin = ymin; + this.xmax = xmax; + this.ymax = ymax; + } + + /// + /// Cohen–Sutherland clipping algorithm clips a line from + /// P0 = (x0, y0) to P1 = (x1, y1) against a rectangle with + /// diagonal from (xmin, ymin) to (xmax, ymax). + /// + /// X coordinate of the first point. + /// Y coordinate of the first point. + /// X coordinate of the second point. + /// Y coordinate of the second point. + /// + /// true if the line is inside. + /// + public bool ClipLine(ref double x0, ref double y0, ref double x1, ref double y1) + { + // compute outcodes for P0, P1, and whatever point lies outside the clip rectangle + int outcode0 = this.ComputeOutCode(x0, y0); + int outcode1 = this.ComputeOutCode(x1, y1); + bool accept = false; + + while (true) + { + if ((outcode0 | outcode1) == 0) + { + // logical or is 0. Trivially accept and get out of loop + accept = true; + break; + } + + if ((outcode0 & outcode1) != 0) + { + // logical and is not 0. Trivially reject and get out of loop + break; + } + + // failed both tests, so calculate the line segment to clip + // from an outside point to an intersection with clip edge + double x = 0, y = 0; + + // At least one endpoint is outside the clip rectangle; pick it. + int outcodeOut = outcode0 != 0 ? outcode0 : outcode1; + + // Now find the intersection point; + // use formulas y = y0 + slope * (x - x0), x = x0 + (1 / slope) * (y - y0) + if ((outcodeOut & Top) != 0) + { + // point is above the clip rectangle + x = x0 + ((x1 - x0) * (this.ymax - y0) / (y1 - y0)); + y = this.ymax; + } + else if ((outcodeOut & Bottom) != 0) + { + // point is below the clip rectangle + x = x0 + ((x1 - x0) * (this.ymin - y0) / (y1 - y0)); + y = this.ymin; + } + else if ((outcodeOut & Right) != 0) + { + // point is to the right of clip rectangle + y = y0 + ((y1 - y0) * (this.xmax - x0) / (x1 - x0)); + x = this.xmax; + } + else if ((outcodeOut & Left) != 0) + { + // point is to the left of clip rectangle + y = y0 + ((y1 - y0) * (this.xmin - x0) / (x1 - x0)); + x = this.xmin; + } + + // Now we move outside point to intersection point to clip + // and get ready for next pass. + if (outcodeOut == outcode0) + { + x0 = x; + y0 = y; + outcode0 = this.ComputeOutCode(x0, y0); + } + else + { + x1 = x; + y1 = y; + outcode1 = this.ComputeOutCode(x1, y1); + } + } + + return accept; + } + + /// + /// Cohen–Sutherland clipping algorithm clips a line from + /// P0 = (x0, y0) to P1 = (x1, y1) against a rectangle with + /// diagonal from (xmin, ymin) to (xmax, ymax). + /// + /// + /// The s 0. + /// + /// + /// The s 1. + /// + /// + /// true if the line is inside + /// + public bool ClipLine(ref ScreenPoint s0, ref ScreenPoint s1) + { + return this.ClipLine(ref s0.x, ref s0.y, ref s1.x, ref s1.y); + } + + /// + /// Determines whether the specified point is inside the rectangle. + /// + /// The x coordinate. + /// The y coordinate. + /// + /// true if the specified point is inside; otherwise, false. + /// + public bool IsInside(double x, double y) + { + return this.ComputeOutCode(x, y) == Inside; + } + + /// + /// Determines whether the specified point is inside the rectangle. + /// + /// The point. + /// + /// true if the specified point is inside; otherwise, false. + /// + public bool IsInside(ScreenPoint s) + { + return this.ComputeOutCode(s.X, s.Y) == Inside; + } + + /// + /// Computes the out code. + /// + /// + /// The x. + /// + /// + /// The y. + /// + /// + /// The out code. + /// + /// + /// Compute the bit code for a point (x, y) using the clip rectangle + /// bounded diagonally by (xmin, ymin), and (xmax, ymax) + /// + private int ComputeOutCode(double x, double y) + { + int code = Inside; // initialized as being inside of clip window + + if (x < this.xmin) + { + // to the left of clip window + code |= Left; + } + else if (x > this.xmax) + { + // to the right of clip window + code |= Right; + } + + if (y < this.ymin) + { + // below the clip window + code |= Bottom; + } + else if (y > this.ymax) + { + // above the clip window + code |= Top; + } + + return code; + } + } +} \ No newline at end of file diff -r 88d699a65cc2 -r 5be8f2773237 External/OxyPlot/OxyPlot/Foundation/Color.cs --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/External/OxyPlot/OxyPlot/Foundation/Color.cs Sat Jun 08 16:53:22 2013 +0000 @@ -0,0 +1,55 @@ +// -------------------------------------------------------------------------------------------------------------------- +// +// The MIT License (MIT) +// +// Copyright (c) 2012 Oystein Bjorke +// +// Permission is hereby granted, free of charge, to any person obtaining a +// copy of this software and associated documentation files (the +// "Software"), to deal in the Software without restriction, including +// without limitation the rights to use, copy, modify, merge, publish, +// distribute, sublicense, and/or sell copies of the Software, and to +// permit persons to whom the Software is furnished to do so, subject to +// the following conditions: +// +// The above copyright notice and this permission notice shall be included +// in all copies or substantial portions of the Software. +// +// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS +// OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF +// MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. +// IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY +// CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, +// TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE +// SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. +// +// -------------------------------------------------------------------------------------------------------------------- +namespace OxyPlot +{ + public class Color + { + public byte A { get; set; } + public byte R { get; set; } + public byte G { get; set; } + public byte B { get; set; } + + public static Color FromARGB(byte a, byte r, byte g, byte b) + { + return new Color { A = a, R = r, G = g, B = b }; + } + + public static Color FromRGB(byte r, byte g, byte b) + { + return new Color { A = 255, R = r, G = g, B = b }; + } + + public static Color FromAColor(byte a, Color color) + { + return new Color { A = a, R = color.R, G = color.G, B = color.B }; + } + public override string ToString() + { + return string.Format("#{0:x2}{1:x2}{2:x2}{3:x2}", A, R, G, B); + } + } +} \ No newline at end of file diff -r 88d699a65cc2 -r 5be8f2773237 External/OxyPlot/OxyPlot/Foundation/Colors.cs --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/External/OxyPlot/OxyPlot/Foundation/Colors.cs Sat Jun 08 16:53:22 2013 +0000 @@ -0,0 +1,45 @@ +// -------------------------------------------------------------------------------------------------------------------- +// +// The MIT License (MIT) +// +// Copyright (c) 2012 Oystein Bjorke +// +// Permission is hereby granted, free of charge, to any person obtaining a +// copy of this software and associated documentation files (the +// "Software"), to deal in the Software without restriction, including +// without limitation the rights to use, copy, modify, merge, publish, +// distribute, sublicense, and/or sell copies of the Software, and to +// permit persons to whom the Software is furnished to do so, subject to +// the following conditions: +// +// The above copyright notice and this permission notice shall be included +// in all copies or substantial portions of the Software. +// +// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS +// OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF +// MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. +// IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY +// CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, +// TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE +// SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. +// +// -------------------------------------------------------------------------------------------------------------------- +namespace OxyPlot +{ + public static class Colors + { + public static readonly Color Transparent = Color.FromARGB(0, 0, 0, 0); + public static readonly Color Black = Color.FromRGB(0, 0, 0); + public static readonly Color White = Color.FromRGB(0xFF, 0xFF, 0xFF); + public static readonly Color DarkGray = Color.FromRGB(0xA9, 0xA9, 0xA9); + public static readonly Color Gray = Color.FromRGB(0x80, 0x80, 0x80); + public static readonly Color LightGray = Color.FromRGB(0xD3, 0xD3, 0xD3); + public static readonly Color Red = Color.FromRGB(0xFF, 0, 0); + public static readonly Color Green = Color.FromRGB(0, 0xFF, 0); + public static readonly Color Blue = Color.FromRGB(0, 0, 0xFF); + public static readonly Color Orange = Color.FromRGB(0xFF, 0xA5, 0x00); + public static readonly Color Indigo = Color.FromRGB(0x4B, 0x00, 0x82); + public static readonly Color Violet = Color.FromRGB(0xEE, 0x82, 0xEE); + public static readonly Color Yellow = Color.FromRGB(0xFF, 0xFF, 0x00); + } +} \ No newline at end of file diff -r 88d699a65cc2 -r 5be8f2773237 External/OxyPlot/OxyPlot/Foundation/Conrec.cs --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/External/OxyPlot/OxyPlot/Foundation/Conrec.cs Sat Jun 08 16:53:22 2013 +0000 @@ -0,0 +1,294 @@ +// -------------------------------------------------------------------------------------------------------------------- +// +// The MIT License (MIT) +// +// Copyright (c) 2012 Oystein Bjorke +// +// Permission is hereby granted, free of charge, to any person obtaining a +// copy of this software and associated documentation files (the +// "Software"), to deal in the Software without restriction, including +// without limitation the rights to use, copy, modify, merge, publish, +// distribute, sublicense, and/or sell copies of the Software, and to +// permit persons to whom the Software is furnished to do so, subject to +// the following conditions: +// +// The above copyright notice and this permission notice shall be included +// in all copies or substantial portions of the Software. +// +// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS +// OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF +// MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. +// IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY +// CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, +// TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE +// SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. +// +// +// Creates contours from a triangular mesh. +// +// -------------------------------------------------------------------------------------------------------------------- +namespace OxyPlot +{ + using System; + + /// + /// Provides functionality to create contours from a triangular mesh. + /// + /// + /// + /// Ported from C / Fortran code by Paul Bourke. + /// See Conrec for + /// full description of code and the original source. + /// + /// + /// Contouring aids in visualizing three dimensional surfaces on a two dimensional + /// medium (on paper or in this case a computer graphics screen). Two most common + /// applications are displaying topological features of an area on a map or the air + /// pressure on a weather map. In all cases some parameter is plotted as a function + /// of two variables, the longitude and latitude or x and y axis. One problem with + /// computer contouring is the process is usually CPU intensive and the algorithms + /// often use advanced mathematical techniques making them susceptible to error. + /// + /// + public static class Conrec + { + /// + /// Renderer delegate + /// + /// + /// Start point x-coordinate + /// + /// + /// Start point y-coordinate + /// + /// + /// End point x-coordinate + /// + /// + /// End point y-coordinate + /// + /// + /// Contour level + /// + public delegate void RendererDelegate(double x1, double y1, double x2, double y2, double z); + + /// + /// Contour is a contouring subroutine for rectangularily spaced data + /// It emits calls to a line drawing subroutine supplied by the user + /// which draws a contour map corresponding to data on a randomly + /// spaced rectangular grid. The coordinates emitted are in the same + /// units given in the x() and y() arrays. + /// Any number of contour levels may be specified but they must be + /// in order of increasing value. + /// + /// + /// Matrix of data to contour. + /// + /// + /// Data matrix column coordinates. + /// + /// + /// Data matrix row coordinates. + /// + /// + /// Contour levels in increasing order. + /// + /// + /// The renderer. + /// + public static void Contour(double[,] d, double[] x, double[] y, double[] z, RendererDelegate renderer) + { + double x1 = 0.0; + double x2 = 0.0; + double y1 = 0.0; + double y2 = 0.0; + + var h = new double[5]; + var sh = new int[5]; + var xh = new double[5]; + var yh = new double[5]; + + int ilb = d.GetLowerBound(0); + int iub = d.GetUpperBound(0); + int jlb = d.GetLowerBound(1); + int jub = d.GetUpperBound(1); + int nc = z.Length; + + // The indexing of im and jm should be noted as it has to start from zero + // unlike the fortran counter part + int[] im = { 0, 1, 1, 0 }; + int[] jm = { 0, 0, 1, 1 }; + + // Note that castab is arranged differently from the FORTRAN code because + // Fortran and C/C++ arrays are transposed of each other, in this case + // it is more tricky as castab is in 3 dimension + int[,,] castab = + { + { { 0, 0, 8 }, { 0, 2, 5 }, { 7, 6, 9 } }, { { 0, 3, 4 }, { 1, 3, 1 }, { 4, 3, 0 } }, + { { 9, 6, 7 }, { 5, 2, 0 }, { 8, 0, 0 } } + }; + + Func xsect = (p1, p2) => ((h[p2] * xh[p1]) - (h[p1] * xh[p2])) / (h[p2] - h[p1]); + Func ysect = (p1, p2) => ((h[p2] * yh[p1]) - (h[p1] * yh[p2])) / (h[p2] - h[p1]); + + for (int j = jub - 1; j >= jlb; j--) + { + int i; + for (i = ilb; i <= iub - 1; i++) + { + double temp1 = Math.Min(d[i, j], d[i, j + 1]); + double temp2 = Math.Min(d[i + 1, j], d[i + 1, j + 1]); + double dmin = Math.Min(temp1, temp2); + temp1 = Math.Max(d[i, j], d[i, j + 1]); + temp2 = Math.Max(d[i + 1, j], d[i + 1, j + 1]); + double dmax = Math.Max(temp1, temp2); + + if (dmax >= z[0] && dmin <= z[nc - 1]) + { + int k; + for (k = 0; k < nc; k++) + { + if (z[k] >= dmin && z[k] <= dmax) + { + int m; + for (m = 4; m >= 0; m--) + { + if (m > 0) + { + // The indexing of im and jm should be noted as it has to + // start from zero + h[m] = d[i + im[m - 1], j + jm[m - 1]] - z[k]; + xh[m] = x[i + im[m - 1]]; + yh[m] = y[j + jm[m - 1]]; + } + else + { + h[0] = 0.25 * (h[1] + h[2] + h[3] + h[4]); + xh[0] = 0.5 * (x[i] + x[i + 1]); + yh[0] = 0.5 * (y[j] + y[j + 1]); + } + + if (h[m] > 0.0) + { + sh[m] = 1; + } + else if (h[m] < 0.0) + { + sh[m] = -1; + } + else + { + sh[m] = 0; + } + } + + //// Note: at this stage the relative heights of the corners and the + //// centre are in the h array, and the corresponding coordinates are + //// in the xh and yh arrays. The centre of the box is indexed by 0 + //// and the 4 corners by 1 to 4 as shown below. + //// Each triangle is then indexed by the parameter m, and the 3 + //// vertices of each triangle are indexed by parameters m1,m2,and + //// m3. + //// It is assumed that the centre of the box is always vertex 2 + //// though this isimportant only when all 3 vertices lie exactly on + //// the same contour level, in which case only the side of the box + //// is drawn. + //// vertex 4 +-------------------+ vertex 3 + //// | \ / | + //// | \ m-3 / | + //// | \ / | + //// | \ / | + //// | m=2 X m=2 | the centre is vertex 0 + //// | / \ | + //// | / \ | + //// | / m=1 \ | + //// | / \ | + //// vertex 1 +-------------------+ vertex 2 + + // Scan each triangle in the box + for (m = 1; m <= 4; m++) + { + int m1 = m; + int m2 = 0; + int m3; + if (m != 4) + { + m3 = m + 1; + } + else + { + m3 = 1; + } + + int caseValue = castab[sh[m1] + 1, sh[m2] + 1, sh[m3] + 1]; + if (caseValue != 0) + { + switch (caseValue) + { + case 1: // Line between vertices 1 and 2 + x1 = xh[m1]; + y1 = yh[m1]; + x2 = xh[m2]; + y2 = yh[m2]; + break; + case 2: // Line between vertices 2 and 3 + x1 = xh[m2]; + y1 = yh[m2]; + x2 = xh[m3]; + y2 = yh[m3]; + break; + case 3: // Line between vertices 3 and 1 + x1 = xh[m3]; + y1 = yh[m3]; + x2 = xh[m1]; + y2 = yh[m1]; + break; + case 4: // Line between vertex 1 and side 2-3 + x1 = xh[m1]; + y1 = yh[m1]; + x2 = xsect(m2, m3); + y2 = ysect(m2, m3); + break; + case 5: // Line between vertex 2 and side 3-1 + x1 = xh[m2]; + y1 = yh[m2]; + x2 = xsect(m3, m1); + y2 = ysect(m3, m1); + break; + case 6: // Line between vertex 3 and side 1-2 + x1 = xh[m3]; + y1 = yh[m3]; + x2 = xsect(m1, m2); + y2 = ysect(m1, m2); + break; + case 7: // Line between sides 1-2 and 2-3 + x1 = xsect(m1, m2); + y1 = ysect(m1, m2); + x2 = xsect(m2, m3); + y2 = ysect(m2, m3); + break; + case 8: // Line between sides 2-3 and 3-1 + x1 = xsect(m2, m3); + y1 = ysect(m2, m3); + x2 = xsect(m3, m1); + y2 = ysect(m3, m1); + break; + case 9: // Line between sides 3-1 and 1-2 + x1 = xsect(m3, m1); + y1 = ysect(m3, m1); + x2 = xsect(m1, m2); + y2 = ysect(m1, m2); + break; + } + + renderer(x1, y1, x2, y2, z[k]); + } + } + } + } + } + } + } + } + } +} \ No newline at end of file diff -r 88d699a65cc2 -r 5be8f2773237 External/OxyPlot/OxyPlot/Foundation/DataPoint.cs --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/External/OxyPlot/OxyPlot/Foundation/DataPoint.cs Sat Jun 08 16:53:22 2013 +0000 @@ -0,0 +1,136 @@ +// -------------------------------------------------------------------------------------------------------------------- +// +// The MIT License (MIT) +// +// Copyright (c) 2012 Oystein Bjorke +// +// Permission is hereby granted, free of charge, to any person obtaining a +// copy of this software and associated documentation files (the +// "Software"), to deal in the Software without restriction, including +// without limitation the rights to use, copy, modify, merge, publish, +// distribute, sublicense, and/or sell copies of the Software, and to +// permit persons to whom the Software is furnished to do so, subject to +// the following conditions: +// +// The above copyright notice and this permission notice shall be included +// in all copies or substantial portions of the Software. +// +// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS +// OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF +// MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. +// IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY +// CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, +// TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE +// SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. +// +// +// DataPoint value type. +// +// -------------------------------------------------------------------------------------------------------------------- +namespace OxyPlot +{ + using System.Diagnostics.CodeAnalysis; + + /// + /// Represents a point in the data coordinate system. + /// + /// + /// s are transformed to s. + /// + public struct DataPoint : IDataPoint, ICodeGenerating + { + /// + /// The undefined. + /// + public static readonly DataPoint Undefined = new DataPoint(double.NaN, double.NaN); + + /// + /// The x-coordinate. + /// + [SuppressMessage("StyleCop.CSharp.NamingRules", "SA1307:AccessibleFieldsMustBeginWithUpperCaseLetter", + Justification = "Reviewed. Suppression is OK here.")] + internal double x; + + /// + /// The y-coordinate. + /// + [SuppressMessage("StyleCop.CSharp.NamingRules", "SA1307:AccessibleFieldsMustBeginWithUpperCaseLetter", + Justification = "Reviewed. Suppression is OK here.")] + internal double y; + + /// + /// Initializes a new instance of the struct. + /// + /// + /// The x. + /// + /// + /// The y. + /// + public DataPoint(double x, double y) + { + this.x = x; + this.y = y; + } + + /// + /// Gets or sets the X. + /// + /// + /// The X. + /// + public double X + { + get + { + return this.x; + } + + set + { + this.x = value; + } + } + + /// + /// Gets or sets the Y. + /// + /// + /// The Y. + /// + public double Y + { + get + { + return this.y; + } + + set + { + this.y = value; + } + } + + /// + /// Returns C# code that generates this instance. + /// + /// + /// The to code. + /// + public string ToCode() + { + return CodeGenerator.FormatConstructor(this.GetType(), "{0},{1}", this.x, this.y); + } + + /// + /// Returns a that represents this instance. + /// + /// + /// A that represents this instance. + /// + public override string ToString() + { + return this.x + " " + this.y; + } + } +} \ No newline at end of file diff -r 88d699a65cc2 -r 5be8f2773237 External/OxyPlot/OxyPlot/Foundation/DataPointConverter.cs --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/External/OxyPlot/OxyPlot/Foundation/DataPointConverter.cs Sat Jun 08 16:53:22 2013 +0000 @@ -0,0 +1,82 @@ +// -------------------------------------------------------------------------------------------------------------------- +// +// The MIT License (MIT) +// +// Copyright (c) 2012 Oystein Bjorke +// +// Permission is hereby granted, free of charge, to any person obtaining a +// copy of this software and associated documentation files (the +// "Software"), to deal in the Software without restriction, including +// without limitation the rights to use, copy, modify, merge, publish, +// distribute, sublicense, and/or sell copies of the Software, and to +// permit persons to whom the Software is furnished to do so, subject to +// the following conditions: +// +// The above copyright notice and this permission notice shall be included +// in all copies or substantial portions of the Software. +// +// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS +// OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF +// MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. +// IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY +// CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, +// TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE +// SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. +// +// +// The DataPoint converter. +// +// -------------------------------------------------------------------------------------------------------------------- +namespace OxyPlot +{ + using System; + using System.ComponentModel; + using System.Globalization; + + /// + /// Converts a object from one data type to another. + /// + public class DataPointConverter : TypeConverter + { + /// + /// Returns whether this converter can convert an object of the given type to the type of this converter, using the specified context. + /// + /// An that provides a format context. + /// A that represents the type you want to convert from. + /// + /// true if this converter can perform the conversion; otherwise, false. + /// + public override bool CanConvertFrom(ITypeDescriptorContext context, Type sourceType) + { + if (sourceType == typeof(string)) + { + return true; + } + + return base.CanConvertFrom(context, sourceType); + } + + /// + /// Converts the given object to the type of this converter, using the specified context and culture information. + /// + /// An that provides a format context. + /// The to use as the current culture. + /// The to convert. + /// + /// An that represents the converted value. + /// + public override object ConvertFrom(ITypeDescriptorContext context, CultureInfo culture, object value) + { + if (value is string) + { + var input = (string)value; + var xy = input.Split(','); + double x = double.Parse(xy[0], CultureInfo.InvariantCulture); + double y = double.Parse(xy[1], CultureInfo.InvariantCulture); + return new DataPoint(x, y); + } + + return base.ConvertFrom(context, culture, value); + } + } +} \ No newline at end of file diff -r 88d699a65cc2 -r 5be8f2773237 External/OxyPlot/OxyPlot/Foundation/DoubleExtensions.cs --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/External/OxyPlot/OxyPlot/Foundation/DoubleExtensions.cs Sat Jun 08 16:53:22 2013 +0000 @@ -0,0 +1,236 @@ +// -------------------------------------------------------------------------------------------------------------------- +// +// The MIT License (MIT) +// +// Copyright (c) 2012 Oystein Bjorke +// +// Permission is hereby granted, free of charge, to any person obtaining a +// copy of this software and associated documentation files (the +// "Software"), to deal in the Software without restriction, including +// without limitation the rights to use, copy, modify, merge, publish, +// distribute, sublicense, and/or sell copies of the Software, and to +// permit persons to whom the Software is furnished to do so, subject to +// the following conditions: +// +// The above copyright notice and this permission notice shall be included +// in all copies or substantial portions of the Software. +// +// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS +// OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF +// MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. +// IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY +// CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, +// TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE +// SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. +// +// +// Extension methods for double values. +// +// -------------------------------------------------------------------------------------------------------------------- +namespace OxyPlot +{ + using System; + using System.Globalization; + + /// + /// Provides extension methods for the type. + /// + public static class DoubleExtensions + { + /// + /// Squares the specified value. + /// + /// + /// The value. + /// + /// + /// Squared value. + /// + public static double Squared(this double x) + { + return x * x; + } + + /// + /// Exponent function. + /// + /// + /// The value. + /// + /// + /// The exponent. + /// + public static double GetExponent(this double x) + { + return Math.Round(Math.Log(Math.Abs(x), 10)); + } + + /// + /// Mantissa function. + /// http://en.wikipedia.org/wiki/Mantissa + /// + /// + /// The value. + /// + /// + /// The mantissa. + /// + public static double GetMantissa(this double x) + { + return x / Math.Pow(10, x.GetExponent()); + } + + /// + /// Removes the floating point noise. + /// + /// + /// The value. + /// + /// + /// A double without noise. + /// + public static double RemoveNoise2(this double value) + { + return (double)((decimal)value); + } + + /// + /// Removes the floating point noise. + /// + /// + /// The value. + /// + /// + /// The maximum number of digits. + /// + /// + /// A double without noise. + /// + public static double RemoveNoise(this double value, int maxDigits = 8) + { + return double.Parse(value.ToString("e" + maxDigits)); + } + + /// + /// Removes the noise from double math. + /// + /// + /// The value. + /// + /// + /// A double without noise. + /// + public static double RemoveNoiseFromDoubleMath(this double value) + { + if (value.IsZero() || Math.Abs(Math.Log10(Math.Abs(value))) < 27) + { + return (double)((decimal)value); + } + + return double.Parse(value.ToString(CultureInfo.InvariantCulture), CultureInfo.InvariantCulture); + } + + /// + /// Determines whether the specified value is zero. + /// + /// The value. + /// + /// true if the specified value is zero; otherwise, false. + /// + public static bool IsZero(this double value) + { + return Math.Abs(value) < double.Epsilon; + } + + /// + /// Calculates the nearest larger multiple of the specified value. + /// + /// + /// The value. + /// + /// + /// The multiplier. + /// + /// + /// The multiple value. + /// + public static double ToUpperMultiple(this double value, double step) + { + var i = (int)Math.Ceiling(value / step); + return (step * i).RemoveNoise(); + } + + /// + /// Calculates the nearest smaller multiple of the specified value. + /// + /// + /// The value. + /// + /// + /// The multiplier. + /// + /// + /// The multiple value. + /// + public static double ToLowerMultiple(this double value, double step) + { + var i = (int)Math.Floor(value / step); + return (step * i).RemoveNoise(); + } + +#if THISISNOTINUSE + + // + // Gets the mantissa and exponent. + // + /// + /// From + /// + /// The d. + /// if set to true [negative]. + /// The mantissa. + /// The exponent. + public static void GetMantissaAndExponent(this double d, out bool negative, out long mantissa, out int exponent) + { + // Translate the double into sign, exponent and mantissa. + long bits = BitConverter.DoubleToInt64Bits(d); + +// Note that the shift is sign-extended, hence the test against -1 not 1 + negative = (bits < 0); + exponent = (int)((bits >> 52) & 0x7ffL); + mantissa = bits & 0xfffffffffffffL; + + // Subnormal numbers; exponent is effectively one higher, + // but there's no extra normalisation bit in the mantissa + if (exponent == 0) + { + exponent++; + } + +// Normal numbers; leave exponent as it is but add extra + // bit to the front of the mantissa + else + { + mantissa = mantissa | (1L << 52); + } + + // Bias the exponent. It's actually biased by 1023, but we're + // treating the mantissa as m.0 rather than 0.m, so we need + // to subtract another 52 from it. + exponent -= 1075; + + if (mantissa == 0) + { + return; + } + + /* Normalize */ + while ((mantissa & 1) == 0) + { /* i.e., Mantissa is even */ + mantissa >>= 1; + exponent++; + } + } +#endif + } +} \ No newline at end of file diff -r 88d699a65cc2 -r 5be8f2773237 External/OxyPlot/OxyPlot/Foundation/FontWeights.cs --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/External/OxyPlot/OxyPlot/Foundation/FontWeights.cs Sat Jun 08 16:53:22 2013 +0000 @@ -0,0 +1,48 @@ +// -------------------------------------------------------------------------------------------------------------------- +// +// The MIT License (MIT) +// +// Copyright (c) 2012 Oystein Bjorke +// +// Permission is hereby granted, free of charge, to any person obtaining a +// copy of this software and associated documentation files (the +// "Software"), to deal in the Software without restriction, including +// without limitation the rights to use, copy, modify, merge, publish, +// distribute, sublicense, and/or sell copies of the Software, and to +// permit persons to whom the Software is furnished to do so, subject to +// the following conditions: +// +// The above copyright notice and this permission notice shall be included +// in all copies or substantial portions of the Software. +// +// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS +// OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF +// MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. +// IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY +// CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, +// TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE +// SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. +// +// +// Static font weights. +// +// -------------------------------------------------------------------------------------------------------------------- +namespace OxyPlot +{ + /// + /// Provides a set of static predefined font weight values. + /// + public static class FontWeights + { + /// + /// Specifies a bold font weight. + /// + public const double Bold = 700; + + /// + /// Specifies a normal font weight. + /// + public const double Normal = 400; + + } +} \ No newline at end of file diff -r 88d699a65cc2 -r 5be8f2773237 External/OxyPlot/OxyPlot/Foundation/FractionHelper.cs --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/External/OxyPlot/OxyPlot/Foundation/FractionHelper.cs Sat Jun 08 16:53:22 2013 +0000 @@ -0,0 +1,155 @@ +// -------------------------------------------------------------------------------------------------------------------- +// +// The MIT License (MIT) +// +// Copyright (c) 2012 Oystein Bjorke +// +// Permission is hereby granted, free of charge, to any person obtaining a +// copy of this software and associated documentation files (the +// "Software"), to deal in the Software without restriction, including +// without limitation the rights to use, copy, modify, merge, publish, +// distribute, sublicense, and/or sell copies of the Software, and to +// permit persons to whom the Software is furnished to do so, subject to +// the following conditions: +// +// The above copyright notice and this permission notice shall be included +// in all copies or substantial portions of the Software. +// +// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS +// OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF +// MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. +// IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY +// CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, +// TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE +// SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. +// +// +// Generates fraction strings from double values. +// +// -------------------------------------------------------------------------------------------------------------------- +namespace OxyPlot +{ + using System; + using System.Globalization; + + /// + /// Provides functionality to generate fraction strings from double values. + /// + /// + /// Examples: "3/4", "PI/2" + /// + public static class FractionHelper + { + /// + /// Converts a double to a fraction string. + /// + /// + /// The value. + /// + /// + /// The unit. + /// + /// + /// The unit symbol. + /// + /// + /// The tolerance. + /// + /// + /// The format Provider. + /// + /// + /// The convert to fraction string. + /// + public static string ConvertToFractionString( + double value, + double unit = 1, + string unitSymbol = null, + double eps = 1e-6, + IFormatProvider formatProvider = null) + { + if (Math.Abs(value) < eps) + { + return "0"; + } + + // ½, ⅝, ¾ + value /= unit; + + // int whole = (int)(value - (int) value); + // int N = 10000; + // int frac = (int) ((value - whole)*N); + // var d = GCF(N,frac); + for (int d = 1; d <= 64; d++) + { + double n = value * d; + var ni = (int)Math.Round(n); + if (Math.Abs(n - ni) < eps) + { + string nis = unitSymbol == null || ni != 1 ? ni.ToString(CultureInfo.InvariantCulture) : string.Empty; + if (d == 1) + { + return string.Format("{0}{1}", nis, unitSymbol); + } + + return string.Format("{0}{1}/{2}", nis, unitSymbol, d); + } + } + + return string.Format(formatProvider ?? CultureInfo.CurrentCulture, "{0}{1}", value, unitSymbol); + } + + /// + /// Finds the greates common divisor. + /// + /// + /// The a. + /// + /// + /// The b. + /// + /// + /// The gcd. + /// + public static int gcd(int a, int b) + { + if (b == 0) + { + return a; + } + + return gcd(b, a % b); + } + + /// + /// Finds the greatest common factor. + /// + /// + /// The x. + /// + /// + /// The y. + /// + /// + /// The gcf. + /// + private static int GCF(int x, int y) + { + x = Math.Abs(x); + y = Math.Abs(y); + int z; + do + { + z = x % y; + if (z == 0) + { + return y; + } + + x = y; + y = z; + } + while (true); + } + } +} \ No newline at end of file diff -r 88d699a65cc2 -r 5be8f2773237 External/OxyPlot/OxyPlot/Foundation/HorizontalAlignment.cs --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/External/OxyPlot/OxyPlot/Foundation/HorizontalAlignment.cs Sat Jun 08 16:53:22 2013 +0000 @@ -0,0 +1,52 @@ +// -------------------------------------------------------------------------------------------------------------------- +// +// The MIT License (MIT) +// +// Copyright (c) 2012 Oystein Bjorke +// +// Permission is hereby granted, free of charge, to any person obtaining a +// copy of this software and associated documentation files (the +// "Software"), to deal in the Software without restriction, including +// without limitation the rights to use, copy, modify, merge, publish, +// distribute, sublicense, and/or sell copies of the Software, and to +// permit persons to whom the Software is furnished to do so, subject to +// the following conditions: +// +// The above copyright notice and this permission notice shall be included +// in all copies or substantial portions of the Software. +// +// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS +// OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF +// MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. +// IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY +// CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, +// TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE +// SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. +// +// +// Horizontal text alignment. +// +// -------------------------------------------------------------------------------------------------------------------- +namespace OxyPlot +{ + /// + /// Specifies the horizontal alignment. + /// + public enum HorizontalAlignment + { + /// + /// Aligned to the left. + /// + Left = -1, + + /// + /// Aligned in the center. + /// + Center = 0, + + /// + /// Aligned to the right. + /// + Right = 1 + } +} \ No newline at end of file diff -r 88d699a65cc2 -r 5be8f2773237 External/OxyPlot/OxyPlot/Foundation/IDataPoint.cs --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/External/OxyPlot/OxyPlot/Foundation/IDataPoint.cs Sat Jun 08 16:53:22 2013 +0000 @@ -0,0 +1,49 @@ +// -------------------------------------------------------------------------------------------------------------------- +// +// The MIT License (MIT) +// +// Copyright (c) 2012 Oystein Bjorke +// +// Permission is hereby granted, free of charge, to any person obtaining a +// copy of this software and associated documentation files (the +// "Software"), to deal in the Software without restriction, including +// without limitation the rights to use, copy, modify, merge, publish, +// distribute, sublicense, and/or sell copies of the Software, and to +// permit persons to whom the Software is furnished to do so, subject to +// the following conditions: +// +// The above copyright notice and this permission notice shall be included +// in all copies or substantial portions of the Software. +// +// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS +// OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF +// MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. +// IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY +// CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, +// TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE +// SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. +// +// +// DataPoint interface. +// +// -------------------------------------------------------------------------------------------------------------------- +namespace OxyPlot +{ + /// + /// Defines a point. + /// + public interface IDataPoint + { + /// + /// Gets or sets the x-coordinate. + /// + /// The x-coordinate. + double X { get; set; } + + /// + /// Gets or sets the y-coordinate. + /// + /// The y-coordinate. + double Y { get; set; } + } +} \ No newline at end of file diff -r 88d699a65cc2 -r 5be8f2773237 External/OxyPlot/OxyPlot/Foundation/IDataPointProvider.cs --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/External/OxyPlot/OxyPlot/Foundation/IDataPointProvider.cs Sat Jun 08 16:53:22 2013 +0000 @@ -0,0 +1,45 @@ +// -------------------------------------------------------------------------------------------------------------------- +// +// The MIT License (MIT) +// +// Copyright (c) 2012 Oystein Bjorke +// +// Permission is hereby granted, free of charge, to any person obtaining a +// copy of this software and associated documentation files (the +// "Software"), to deal in the Software without restriction, including +// without limitation the rights to use, copy, modify, merge, publish, +// distribute, sublicense, and/or sell copies of the Software, and to +// permit persons to whom the Software is furnished to do so, subject to +// the following conditions: +// +// The above copyright notice and this permission notice shall be included +// in all copies or substantial portions of the Software. +// +// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS +// OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF +// MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. +// IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY +// CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, +// TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE +// SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. +// +// +// Provides functionality to create data points for items in an . +// +// -------------------------------------------------------------------------------------------------------------------- +namespace OxyPlot +{ + /// + /// Provides functionality to create data points. + /// + public interface IDataPointProvider + { + /// + /// Gets the data point. + /// + /// + /// The data point. + /// + DataPoint GetDataPoint(); + } +} \ No newline at end of file diff -r 88d699a65cc2 -r 5be8f2773237 External/OxyPlot/OxyPlot/Foundation/LineStyle.cs --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/External/OxyPlot/OxyPlot/Foundation/LineStyle.cs Sat Jun 08 16:53:22 2013 +0000 @@ -0,0 +1,97 @@ +// -------------------------------------------------------------------------------------------------------------------- +// +// The MIT License (MIT) +// +// Copyright (c) 2012 Oystein Bjorke +// +// Permission is hereby granted, free of charge, to any person obtaining a +// copy of this software and associated documentation files (the +// "Software"), to deal in the Software without restriction, including +// without limitation the rights to use, copy, modify, merge, publish, +// distribute, sublicense, and/or sell copies of the Software, and to +// permit persons to whom the Software is furnished to do so, subject to +// the following conditions: +// +// The above copyright notice and this permission notice shall be included +// in all copies or substantial portions of the Software. +// +// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS +// OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF +// MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. +// IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY +// CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, +// TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE +// SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. +// +// +// Enumeration of line styles. +// +// -------------------------------------------------------------------------------------------------------------------- +namespace OxyPlot +{ + /// + /// Specifies the style of a line. + /// + public enum LineStyle + { + /// + /// The solid line style. + /// + Solid, + + /// + /// The dash line style. + /// + Dash, + + /// + /// The dot line style. + /// + Dot, + + /// + /// The dash dot line style. + /// + DashDot, + + /// + /// The dash dash dot line style. + /// + DashDashDot, + + /// + /// The dash dot dot line style. + /// + DashDotDot, + + /// + /// The dash dash dot dot line style. + /// + DashDashDotDot, + + /// + /// The long dash line style. + /// + LongDash, + + /// + /// The long dash dot line style. + /// + LongDashDot, + + /// + /// The long dash dot dot line style. + /// + LongDashDotDot, + + /// + /// The hidden line style. + /// + None, + + /// + /// The undefined line style. + /// + Undefined + } +} \ No newline at end of file diff -r 88d699a65cc2 -r 5be8f2773237 External/OxyPlot/OxyPlot/Foundation/LineStyleHelper.cs --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/External/OxyPlot/OxyPlot/Foundation/LineStyleHelper.cs Sat Jun 08 16:53:22 2013 +0000 @@ -0,0 +1,76 @@ +// -------------------------------------------------------------------------------------------------------------------- +// +// The MIT License (MIT) +// +// Copyright (c) 2012 Oystein Bjorke +// +// Permission is hereby granted, free of charge, to any person obtaining a +// copy of this software and associated documentation files (the +// "Software"), to deal in the Software without restriction, including +// without limitation the rights to use, copy, modify, merge, publish, +// distribute, sublicense, and/or sell copies of the Software, and to +// permit persons to whom the Software is furnished to do so, subject to +// the following conditions: +// +// The above copyright notice and this permission notice shall be included +// in all copies or substantial portions of the Software. +// +// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS +// OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF +// MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. +// IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY +// CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, +// TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE +// SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. +// +// +// Converts from LineStyle to stroke dash array. +// +// -------------------------------------------------------------------------------------------------------------------- +namespace OxyPlot +{ + /// + /// Provides functionality to convert from LineStyle to a stroke dash array. + /// + public static class LineStyleHelper + { + /// + /// Gets the stroke dash array for a given . + /// + /// + /// The line style. + /// + /// + /// A dash array. + /// + public static double[] GetDashArray(this LineStyle style) + { + switch (style) + { + case LineStyle.Solid: + return null; + case LineStyle.Dash: + return new double[] { 4, 1 }; + case LineStyle.Dot: + return new double[] { 1, 1 }; + case LineStyle.DashDot: + return new double[] { 4, 1, 1, 1 }; + case LineStyle.DashDashDot: + return new double[] { 4, 1, 4, 1, 1, 1 }; + case LineStyle.DashDotDot: + return new double[] { 4, 1, 1, 1, 1, 1 }; + case LineStyle.DashDashDotDot: + return new double[] { 4, 1, 4, 1, 1, 1, 1, 1 }; + case LineStyle.LongDash: + return new double[] { 10, 1 }; + case LineStyle.LongDashDot: + return new double[] { 10, 1, 1, 1 }; + case LineStyle.LongDashDotDot: + return new double[] { 10, 1, 1, 1, 1, 1 }; + default: + return null; + } + } + + } +} \ No newline at end of file diff -r 88d699a65cc2 -r 5be8f2773237 External/OxyPlot/OxyPlot/Foundation/ListFiller.cs --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/External/OxyPlot/OxyPlot/Foundation/ListFiller.cs Sat Jun 08 16:53:22 2013 +0000 @@ -0,0 +1,145 @@ +// -------------------------------------------------------------------------------------------------------------------- +// +// The MIT License (MIT) +// +// Copyright (c) 2012 Oystein Bjorke +// +// Permission is hereby granted, free of charge, to any person obtaining a +// copy of this software and associated documentation files (the +// "Software"), to deal in the Software without restriction, including +// without limitation the rights to use, copy, modify, merge, publish, +// distribute, sublicense, and/or sell copies of the Software, and to +// permit persons to whom the Software is furnished to do so, subject to +// the following conditions: +// +// The above copyright notice and this permission notice shall be included +// in all copies or substantial portions of the Software. +// +// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS +// OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF +// MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. +// IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY +// CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, +// TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE +// SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. +// +// -------------------------------------------------------------------------------------------------------------------- +namespace OxyPlot +{ + using System; + using System.Collections; + using System.Collections.Generic; + using System.Reflection; + + /// + /// Provides functionality to fill a list by specified properties of another list. + /// + /// + /// This class uses reflection. + /// + /// + /// The target list item type. + /// + public class ListFiller + where T : class, new() + { + /// + /// The properties. + /// + private readonly Dictionary> properties; + + /// + /// Initializes a new instance of the class. + /// + public ListFiller() + { + this.properties = new Dictionary>(); + } + + /// + /// Adds a setter for the specified property. + /// + /// + /// Name of the property. + /// + /// + /// The setter. + /// + public void Add(string propertyName, Action setter) + { + if (string.IsNullOrEmpty(propertyName)) + { + return; + } + + this.properties.Add(propertyName, setter); + } + + /// + /// Fills the specified target list. + /// + /// The target. + /// The source. + public void FillT(IList target, IEnumerable source) + { + this.Fill((IList)target, source); + } + + /// + /// Fills the specified target list. + /// + /// + /// The target. + /// + /// + /// The source list. + /// + public void Fill(IList target, IEnumerable source) + { + PropertyInfo[] pi = null; + Type t = null; + foreach (var sourceItem in source) + { + if (pi == null || sourceItem.GetType() != t) + { + t = sourceItem.GetType(); + pi = new PropertyInfo[this.properties.Count]; + int i = 0; + foreach (var p in this.properties) + { + if (string.IsNullOrEmpty(p.Key)) + { + i++; + continue; + } + + pi[i] = t.GetProperty(p.Key); + if (pi[i] == null) + { + throw new InvalidOperationException( + string.Format("Could not find field {0} on type {1}", p.Key, t)); + } + + i++; + } + } + + var item = new T(); + + int j = 0; + foreach (var p in this.properties) + { + if (pi[j] != null) + { + var value = pi[j].GetValue(sourceItem, null); + p.Value(item, value); + } + + j++; + } + + target.Add(item); + } + } + } +} \ No newline at end of file diff -r 88d699a65cc2 -r 5be8f2773237 External/OxyPlot/OxyPlot/Foundation/MarkerType.cs --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/External/OxyPlot/OxyPlot/Foundation/MarkerType.cs Sat Jun 08 16:53:22 2013 +0000 @@ -0,0 +1,91 @@ +// -------------------------------------------------------------------------------------------------------------------- +// +// The MIT License (MIT) +// +// Copyright (c) 2012 Oystein Bjorke +// +// Permission is hereby granted, free of charge, to any person obtaining a +// copy of this software and associated documentation files (the +// "Software"), to deal in the Software without restriction, including +// without limitation the rights to use, copy, modify, merge, publish, +// distribute, sublicense, and/or sell copies of the Software, and to +// permit persons to whom the Software is furnished to do so, subject to +// the following conditions: +// +// The above copyright notice and this permission notice shall be included +// in all copies or substantial portions of the Software. +// +// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS +// OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF +// MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. +// IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY +// CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, +// TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE +// SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. +// +// +// Enumeration of marker types. +// +// -------------------------------------------------------------------------------------------------------------------- +namespace OxyPlot +{ + /// + /// Specifies the marker type. + /// + public enum MarkerType + { + /// + /// Do not render markers. + /// + None, + + /// + /// Render markers as circles. + /// + Circle, + + /// + /// Render markers as squares. + /// + Square, + + /// + /// Render markers as diamonds. + /// + Diamond, + + /// + /// Render markers as triangles. + /// + Triangle, + + /// + /// Render markers as crosses (note: this marker type requires the stroke color to be set). + /// + /// + /// This marker type requires the stroke color to be set. + /// + Cross, + + /// + /// Renders markers as plus signs (note: this marker type requires the stroke color to be set). + /// + /// + /// This marker type requires the stroke color to be set. + /// + Plus, + + /// + /// Renders markers as stars (note: this marker type requires the stroke color to be set). + /// + /// + /// This marker type requires the stroke color to be set. + /// + Star, + + /// + /// Render markers by a custom shape (defined by outline). + /// + Custom + } +} \ No newline at end of file diff -r 88d699a65cc2 -r 5be8f2773237 External/OxyPlot/OxyPlot/Foundation/OxyColor.cs --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/External/OxyPlot/OxyPlot/Foundation/OxyColor.cs Sat Jun 08 16:53:22 2013 +0000 @@ -0,0 +1,626 @@ +// -------------------------------------------------------------------------------------------------------------------- +// +// The MIT License (MIT) +// +// Copyright (c) 2012 Oystein Bjorke +// +// Permission is hereby granted, free of charge, to any person obtaining a +// copy of this software and associated documentation files (the +// "Software"), to deal in the Software without restriction, including +// without limitation the rights to use, copy, modify, merge, publish, +// distribute, sublicense, and/or sell copies of the Software, and to +// permit persons to whom the Software is furnished to do so, subject to +// the following conditions: +// +// The above copyright notice and this permission notice shall be included +// in all copies or substantial portions of the Software. +// +// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS +// OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF +// MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. +// IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY +// CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, +// TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE +// SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. +// +// +// Describes a color in terms of alpha, red, green, and blue channels. +// +// -------------------------------------------------------------------------------------------------------------------- +namespace OxyPlot +{ + using System; + using System.ComponentModel; + using System.Globalization; + using System.Linq; + using System.Reflection; + + /// + /// Describes a color in terms of alpha, red, green, and blue channels. + /// + public class OxyColor : ICodeGenerating + { + /// + /// Gets or sets the alpha value. + /// + /// The alpha value. + public byte A { get; set; } + + /// + /// Gets or sets the blue value. + /// + /// The blue value. + public byte B { get; set; } + + /// + /// Gets or sets the green value. + /// + /// The green value. + public byte G { get; set; } + + /// + /// Gets or sets the red value. + /// + /// The red value. + public byte R { get; set; } + + /// + /// Parse a string. + /// + /// + /// The string in the format "#FFFFFF00" or "255,200,180,50". + /// + /// + /// The OxyColor. + /// + /// + /// Invalid format. + /// + public static OxyColor Parse(string value) + { + value = value.Trim(); + if (value.StartsWith("#")) + { + value = value.Trim('#'); + var u = uint.Parse(value, NumberStyles.HexNumber, CultureInfo.InvariantCulture); + if (value.Length < 8) + { + // alpha value was not specified + u += 0xFF000000; + } + + return FromUInt32(u); + } + + var values = value.Split(','); + if (values.Length < 3 || values.Length > 4) + { + throw new FormatException("Invalid format."); + } + + var i = 0; + + byte alpha = 255; + if (values.Length > 3) + { + alpha = byte.Parse(values[i++], CultureInfo.InvariantCulture); + } + + var red = byte.Parse(values[i++], CultureInfo.InvariantCulture); + var green = byte.Parse(values[i++], CultureInfo.InvariantCulture); + var blue = byte.Parse(values[i], CultureInfo.InvariantCulture); + return FromArgb(alpha, red, green, blue); + } + + /// + /// Calculates the difference between two s + /// + /// + /// The first color. + /// + /// + /// The second color. + /// + /// + /// L2-norm in RGBA space + /// + public static double ColorDifference(OxyColor c1, OxyColor c2) + { + // http://en.wikipedia.org/wiki/OxyColor_difference + // http://mathworld.wolfram.com/L2-Norm.html + double dr = (c1.R - c2.R) / 255.0; + double dg = (c1.G - c2.G) / 255.0; + double db = (c1.B - c2.B) / 255.0; + double da = (c1.A - c2.A) / 255.0; + double e = (dr * dr) + (dg * dg) + (db * db) + (da * da); + return Math.Sqrt(e); + } + + /// + /// Convert an to a . + /// + /// + /// The unsigned integer color value. + /// + /// + /// The . + /// + public static OxyColor FromUInt32(uint color) + { + var a = (byte)(color >> 24); + var r = (byte)(color >> 16); + var g = (byte)(color >> 8); + var b = (byte)(color >> 0); + return FromArgb(a, r, g, b); + } + + /// + /// Creates a OxyColor from the specified HSV array. + /// + /// + /// The HSV value array. + /// + /// + /// A OxyColor. + /// + public static OxyColor FromHsv(double[] hsv) + { + if (hsv.Length != 3) + { + throw new InvalidOperationException("Wrong length of hsv array."); + } + + return FromHsv(hsv[0], hsv[1], hsv[2]); + } + + /// + /// Convert from HSV to + /// http://en.wikipedia.org/wiki/HSL_Color_space + /// + /// + /// The hue value [0,1] + /// + /// + /// The saturation value [0,1] + /// + /// + /// The intensity value [0,1] + /// + /// + /// The . + /// + public static OxyColor FromHsv(double hue, double sat, double val) + { + double g, b; + double r = g = b = 0; + + if (sat.Equals(0)) + { + // Gray scale + r = g = b = val; + } + else + { + if (hue.Equals(1)) + { + hue = 0; + } + + hue *= 6.0; + int i = (int)Math.Floor(hue); + double f = hue - i; + double aa = val * (1 - sat); + double bb = val * (1 - (sat * f)); + double cc = val * (1 - (sat * (1 - f))); + switch (i) + { + case 0: + r = val; + g = cc; + b = aa; + break; + case 1: + r = bb; + g = val; + b = aa; + break; + case 2: + r = aa; + g = val; + b = cc; + break; + case 3: + r = aa; + g = bb; + b = val; + break; + case 4: + r = cc; + g = aa; + b = val; + break; + case 5: + r = val; + g = aa; + b = bb; + break; + } + } + + return FromRgb((byte)(r * 255), (byte)(g * 255), (byte)(b * 255)); + } + + /// + /// Calculate the difference in hue between two s. + /// + /// + /// The first color. + /// + /// + /// The second color. + /// + /// + /// The hue difference. + /// + public static double HueDifference(OxyColor c1, OxyColor c2) + { + var hsv1 = c1.ToHsv(); + var hsv2 = c2.ToHsv(); + double dh = hsv1[0] - hsv2[0]; + + // clamp to [-0.5,0.5] + if (dh > 0.5) + { + dh -= 1.0; + } + + if (dh < -0.5) + { + dh += 1.0; + } + + double e = dh * dh; + return Math.Sqrt(e); + } + + /// + /// Creates a color defined by an alpha value and another color. + /// + /// + /// Alpha value. + /// + /// + /// The original color. + /// + /// + /// A color. + /// + public static OxyColor FromAColor(byte a, OxyColor color) + { + return new OxyColor { A = a, R = color.R, G = color.G, B = color.B }; + } + + /// + /// Creates a color from the specified ARGB values. + /// + /// + /// The alpha value. + /// + /// + /// The red value. + /// + /// + /// The green value. + /// + /// + /// The blue value. + /// + /// + /// A color. + /// + public static OxyColor FromArgb(byte a, byte r, byte g, byte b) + { + return new OxyColor { A = a, R = r, G = g, B = b }; + } + + /// + /// Creates a new structure from the specified RGB values. + /// + /// + /// The red value. + /// + /// + /// The green value. + /// + /// + /// The blue value. + /// + /// + /// A structure with the specified values and an alpha channel value of 1. + /// + public static OxyColor FromRgb(byte r, byte g, byte b) + { + // ReSharper restore InconsistentNaming + return new OxyColor { A = 255, R = r, G = g, B = b }; + } + + /// + /// Interpolates the specified colors. + /// + /// + /// The color1. + /// + /// + /// The color2. + /// + /// + /// The t. + /// + /// + /// The interpolated color + /// + public static OxyColor Interpolate(OxyColor color1, OxyColor color2, double t) + { + double a = (color1.A * (1 - t)) + (color2.A * t); + double r = (color1.R * (1 - t)) + (color2.R * t); + double g = (color1.G * (1 - t)) + (color2.G * t); + double b = (color1.B * (1 - t)) + (color2.B * t); + return FromArgb((byte)a, (byte)r, (byte)g, (byte)b); + } + + /// + /// Convert OxyColor to double string. + /// + /// + /// A OxyColor string, e.g. "255,200,180,50". + /// + public string ToByteString() + { + return string.Format(CultureInfo.InvariantCulture, "{0},{1},{2},{3}", this.A, this.R, this.G, this.B); + } + + /// + /// Determines whether the specified is equal to this instance. + /// + /// + /// The to compare with this instance. + /// + /// + /// true if the specified is equal to this instance; otherwise, false . + /// + public override bool Equals(object obj) + { + if (ReferenceEquals(null, obj)) + { + return false; + } + + if (ReferenceEquals(this, obj)) + { + return true; + } + + if (obj.GetType() != typeof(OxyColor)) + { + return false; + } + + return this.Equals((OxyColor)obj); + } + + /// + /// Determines whether the specified is equal to this instance. + /// + /// + /// The to compare with this instance. + /// + /// + /// true if the specified is equal to this instance; otherwise, false . + /// + public bool Equals(OxyColor other) + { + if (ReferenceEquals(null, other)) + { + return false; + } + + if (ReferenceEquals(this, other)) + { + return true; + } + + return other.A == this.A && other.R == this.R && other.G == this.G && other.B == this.B; + } + + /// + /// Gets the color name. + /// + /// + /// The color name. + /// + public string GetColorName() + { + var t = typeof(OxyColors); + var colors = t.GetFields(BindingFlags.Public | BindingFlags.Static); + var colorField = colors.FirstOrDefault( + field => + { + var color = field.GetValue(null); + return this.Equals(color); + }); + return colorField != null ? colorField.Name : null; + } + + /// + /// Returns a hash code for this instance. + /// + /// + /// A hash code for this instance, suitable for use in hashing algorithms and data structures like a hash table. + /// + public override int GetHashCode() + { + unchecked + { + int result = this.A.GetHashCode(); + result = (result * 397) ^ this.R.GetHashCode(); + result = (result * 397) ^ this.G.GetHashCode(); + result = (result * 397) ^ this.B.GetHashCode(); + return result; + } + } + + /// + /// Returns a that represents this instance. + /// + /// + /// A that represents this instance. + /// + public override string ToString() + { + return string.Format( + CultureInfo.InvariantCulture, "#{0:x2}{1:x2}{2:x2}{3:x2}", this.A, this.R, this.G, this.B); + } + + /// + /// Changes the opacity value. + /// + /// + /// The new alpha. + /// + /// + /// The new color. + /// + public OxyColor ChangeAlpha(byte newAlpha) + { + return FromArgb(newAlpha, this.R, this.G, this.B); + } + + /// + /// Calculates the complementary OxyColor. + /// + /// + /// The complementary OxyColor. + /// + public OxyColor Complementary() + { + // http://en.wikipedia.org/wiki/Complementary_Color + var hsv = this.ToHsv(); + double newHue = hsv[0] - 0.5; + + // clamp to [0,1] + if (newHue < 0) + { + newHue += 1.0; + } + + return FromHsv(newHue, hsv[1], hsv[2]); + } + + /// + /// Converts from a to HSV values (double) + /// + /// + /// Array of [Hue,Saturation,Value] in the range [0,1] + /// + public double[] ToHsv() + { + byte r = this.R; + byte g = this.G; + byte b = this.B; + + byte min = Math.Min(Math.Min(r, g), b); + byte v = Math.Max(Math.Max(r, g), b); + double delta = v - min; + + double s = v.Equals(0) ? 0 : delta / v; + double h = 0; + + if (s.Equals(0)) + { + h = 0.0; + } + else + { + if (r == v) + { + h = (g - b) / delta; + } + else if (g == v) + { + h = 2 + ((b - r) / delta); + } + else if (b == v) + { + h = 4 + ((r - g) / delta); + } + + h *= 60; + if (h < 0.0) + { + h += 360; + } + } + + var hsv = new double[3]; + hsv[0] = h / 360.0; + hsv[1] = s; + hsv[2] = v / 255.0; + return hsv; + } + + /// + /// Changes the intensity. + /// + /// + /// The factor. + /// + /// + /// The new OxyColor. + /// + public OxyColor ChangeIntensity(double factor) + { + var hsv = this.ToHsv(); + hsv[2] *= factor; + if (hsv[2] > 1.0) + { + hsv[2] = 1.0; + } + + return FromHsv(hsv); + } + + /// + /// Converts to an unsigned integer. + /// + /// + /// The . + /// + public uint ToUint() + { + uint u = (uint)this.A << 24; + u += (uint)this.R << 16; + u += (uint)this.G << 8; + u += this.B; + return u; + + // (UInt32)((UInt32)c.A << 24 + (UInt32)c.R << 16 + (UInt32)c.G << 8 + (UInt32)c.B); + } + + /// + /// Returns C# code that generates this instance. + /// + /// + /// The to code. + /// + public string ToCode() + { + string name = this.GetColorName(); + if (name != null) + { + return string.Format("OxyColors.{0}", name); + } + + return string.Format("OxyColor.FromArgb({0}, {1}, {2}, {3})", this.A, this.R, this.G, this.B); + } + } +} \ No newline at end of file diff -r 88d699a65cc2 -r 5be8f2773237 External/OxyPlot/OxyPlot/Foundation/OxyColorConverter.cs --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/External/OxyPlot/OxyPlot/Foundation/OxyColorConverter.cs Sat Jun 08 16:53:22 2013 +0000 @@ -0,0 +1,135 @@ +// -------------------------------------------------------------------------------------------------------------------- +// +// The MIT License (MIT) +// +// Copyright (c) 2012 Oystein Bjorke +// +// Permission is hereby granted, free of charge, to any person obtaining a +// copy of this software and associated documentation files (the +// "Software"), to deal in the Software without restriction, including +// without limitation the rights to use, copy, modify, merge, publish, +// distribute, sublicense, and/or sell copies of the Software, and to +// permit persons to whom the Software is furnished to do so, subject to +// the following conditions: +// +// The above copyright notice and this permission notice shall be included +// in all copies or substantial portions of the Software. +// +// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS +// OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF +// MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. +// IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY +// CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, +// TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE +// SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. +// +// +// Converts colors from one data type to another. Access this class through the TypeDescriptor. +// +// -------------------------------------------------------------------------------------------------------------------- +namespace OxyPlot +{ + using System; + using System.ComponentModel; + using System.Globalization; + + /// + /// Converts between and . Access this class through the TypeDescriptor. + /// + public class OxyColorConverter : TypeConverter + { + /// + /// Determines whether an object can be converted from a given type to an instance of a . + /// + /// + /// Describes the context information of a type. + /// + /// + /// The type of the source that is being evaluated for conversion. + /// + /// + /// True if the type can be converted to a ; otherwise, false. + /// + public override bool CanConvertFrom(ITypeDescriptorContext context, Type sourceType) + { + return (sourceType == typeof(string)) || base.CanConvertFrom(context, sourceType); + } + + /// + /// Determines whether an instance of a can be converted to a different type. + /// + /// + /// Describes the context information of a type. + /// + /// + /// The desired type this is being evaluated for conversion. + /// + /// + /// True if this can be converted to destinationType; otherwise, false. + /// + public override bool CanConvertTo(ITypeDescriptorContext context, Type destinationType) + { + return (destinationType == typeof(string)) || base.CanConvertTo(context, destinationType); + } + + /// + /// Attempts to convert the specified object to a . + /// + /// + /// Describes the context information of a type. + /// + /// + /// Cultural information to respect during conversion. + /// + /// + /// The object being converted. + /// + /// + /// The created from converting value. + /// + public override object ConvertFrom(ITypeDescriptorContext context, CultureInfo culture, object value) + { + var str = value as string; + if (str == null) + { + return base.ConvertFrom(context, culture, value); + } + + return OxyColor.Parse(str); + } + + /// + /// Attempts to convert a to a specified type. + /// + /// + /// Describes the context information of a type. + /// + /// + /// Describes the of the type being converted. + /// + /// + /// The to convert. + /// + /// + /// The type to convert this to. + /// + /// + /// The object created from converting this . + /// + public override object ConvertTo( + ITypeDescriptorContext context, CultureInfo culture, object value, Type destinationType) + { + if (destinationType == null) + { + throw new ArgumentNullException("destinationType"); + } + + if (destinationType == typeof(string)) + { + return value != null ? value.ToString() : null; + } + + return base.ConvertTo(context, culture, value, destinationType); + } + } +} \ No newline at end of file diff -r 88d699a65cc2 -r 5be8f2773237 External/OxyPlot/OxyPlot/Foundation/OxyColors.cs --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/External/OxyPlot/OxyPlot/Foundation/OxyColors.cs Sat Jun 08 16:53:22 2013 +0000 @@ -0,0 +1,743 @@ +// -------------------------------------------------------------------------------------------------------------------- +// +// The MIT License (MIT) +// +// Copyright (c) 2012 Oystein Bjorke +// +// Permission is hereby granted, free of charge, to any person obtaining a +// copy of this software and associated documentation files (the +// "Software"), to deal in the Software without restriction, including +// without limitation the rights to use, copy, modify, merge, publish, +// distribute, sublicense, and/or sell copies of the Software, and to +// permit persons to whom the Software is furnished to do so, subject to +// the following conditions: +// +// The above copyright notice and this permission notice shall be included +// in all copies or substantial portions of the Software. +// +// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS +// OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF +// MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. +// IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY +// CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, +// TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE +// SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. +// +// +// Implements a set of predefined colors. +// +// -------------------------------------------------------------------------------------------------------------------- +namespace OxyPlot +{ + /// + /// Implements a set of predefined colors. + /// + public static class OxyColors + { + /// + /// The alice blue. + /// + public static readonly OxyColor AliceBlue = OxyColor.FromUInt32(0xFFF0F8FF); + + /// + /// The antique white. + /// + public static readonly OxyColor AntiqueWhite = OxyColor.FromUInt32(0xFFFAEBD7); + + /// + /// The aqua. + /// + public static readonly OxyColor Aqua = OxyColor.FromUInt32(0xFF00FFFF); + + /// + /// The aquamarine. + /// + public static readonly OxyColor Aquamarine = OxyColor.FromUInt32(0xFF7FFFD4); + + /// + /// The azure. + /// + public static readonly OxyColor Azure = OxyColor.FromUInt32(0xFFF0FFFF); + + /// + /// The beige. + /// + public static readonly OxyColor Beige = OxyColor.FromUInt32(0xFFF5F5DC); + + /// + /// The bisque. + /// + public static readonly OxyColor Bisque = OxyColor.FromUInt32(0xFFFFE4C4); + + /// + /// The black. + /// + public static readonly OxyColor Black = OxyColor.FromUInt32(0xFF000000); + + /// + /// The blanched almond. + /// + public static readonly OxyColor BlanchedAlmond = OxyColor.FromUInt32(0xFFFFEBCD); + + /// + /// The blue. + /// + public static readonly OxyColor Blue = OxyColor.FromUInt32(0xFF0000FF); + + /// + /// The blue violet. + /// + public static readonly OxyColor BlueViolet = OxyColor.FromUInt32(0xFF8A2BE2); + + /// + /// The brown. + /// + public static readonly OxyColor Brown = OxyColor.FromUInt32(0xFFA52A2A); + + /// + /// The burly wood. + /// + public static readonly OxyColor BurlyWood = OxyColor.FromUInt32(0xFFDEB887); + + /// + /// The cadet blue. + /// + public static readonly OxyColor CadetBlue = OxyColor.FromUInt32(0xFF5F9EA0); + + /// + /// The chartreuse. + /// + public static readonly OxyColor Chartreuse = OxyColor.FromUInt32(0xFF7FFF00); + + /// + /// The chocolate. + /// + public static readonly OxyColor Chocolate = OxyColor.FromUInt32(0xFFD2691E); + + /// + /// The coral. + /// + public static readonly OxyColor Coral = OxyColor.FromUInt32(0xFFFF7F50); + + /// + /// The cornflower blue. + /// + public static readonly OxyColor CornflowerBlue = OxyColor.FromUInt32(0xFF6495ED); + + /// + /// The cornsilk. + /// + public static readonly OxyColor Cornsilk = OxyColor.FromUInt32(0xFFFFF8DC); + + /// + /// The crimson. + /// + public static readonly OxyColor Crimson = OxyColor.FromUInt32(0xFFDC143C); + + /// + /// The cyan. + /// + public static readonly OxyColor Cyan = OxyColor.FromUInt32(0xFF00FFFF); + + /// + /// The dark blue. + /// + public static readonly OxyColor DarkBlue = OxyColor.FromUInt32(0xFF00008B); + + /// + /// The dark cyan. + /// + public static readonly OxyColor DarkCyan = OxyColor.FromUInt32(0xFF008B8B); + + /// + /// The dark goldenrod. + /// + public static readonly OxyColor DarkGoldenrod = OxyColor.FromUInt32(0xFFB8860B); + + /// + /// The dark gray. + /// + public static readonly OxyColor DarkGray = OxyColor.FromUInt32(0xFFA9A9A9); + + /// + /// The dark green. + /// + public static readonly OxyColor DarkGreen = OxyColor.FromUInt32(0xFF006400); + + /// + /// The dark khaki. + /// + public static readonly OxyColor DarkKhaki = OxyColor.FromUInt32(0xFFBDB76B); + + /// + /// The dark magenta. + /// + public static readonly OxyColor DarkMagenta = OxyColor.FromUInt32(0xFF8B008B); + + /// + /// The dark olive green. + /// + public static readonly OxyColor DarkOliveGreen = OxyColor.FromUInt32(0xFF556B2F); + + /// + /// The dark orange. + /// + public static readonly OxyColor DarkOrange = OxyColor.FromUInt32(0xFFFF8C00); + + /// + /// The dark orchid. + /// + public static readonly OxyColor DarkOrchid = OxyColor.FromUInt32(0xFF9932CC); + + /// + /// The dark red. + /// + public static readonly OxyColor DarkRed = OxyColor.FromUInt32(0xFF8B0000); + + /// + /// The dark salmon. + /// + public static readonly OxyColor DarkSalmon = OxyColor.FromUInt32(0xFFE9967A); + + /// + /// The dark sea green. + /// + public static readonly OxyColor DarkSeaGreen = OxyColor.FromUInt32(0xFF8FBC8F); + + /// + /// The dark slate blue. + /// + public static readonly OxyColor DarkSlateBlue = OxyColor.FromUInt32(0xFF483D8B); + + /// + /// The dark slate gray. + /// + public static readonly OxyColor DarkSlateGray = OxyColor.FromUInt32(0xFF2F4F4F); + + /// + /// The dark turquoise. + /// + public static readonly OxyColor DarkTurquoise = OxyColor.FromUInt32(0xFF00CED1); + + /// + /// The dark violet. + /// + public static readonly OxyColor DarkViolet = OxyColor.FromUInt32(0xFF9400D3); + + /// + /// The deep pink. + /// + public static readonly OxyColor DeepPink = OxyColor.FromUInt32(0xFFFF1493); + + /// + /// The deep sky blue. + /// + public static readonly OxyColor DeepSkyBlue = OxyColor.FromUInt32(0xFF00BFFF); + + /// + /// The dim gray. + /// + public static readonly OxyColor DimGray = OxyColor.FromUInt32(0xFF696969); + + /// + /// The dodger blue. + /// + public static readonly OxyColor DodgerBlue = OxyColor.FromUInt32(0xFF1E90FF); + + /// + /// The firebrick. + /// + public static readonly OxyColor Firebrick = OxyColor.FromUInt32(0xFFB22222); + + /// + /// The floral white. + /// + public static readonly OxyColor FloralWhite = OxyColor.FromUInt32(0xFFFFFAF0); + + /// + /// The forest green. + /// + public static readonly OxyColor ForestGreen = OxyColor.FromUInt32(0xFF228B22); + + /// + /// The fuchsia. + /// + public static readonly OxyColor Fuchsia = OxyColor.FromUInt32(0xFFFF00FF); + + /// + /// The gainsboro. + /// + public static readonly OxyColor Gainsboro = OxyColor.FromUInt32(0xFFDCDCDC); + + /// + /// The ghost white. + /// + public static readonly OxyColor GhostWhite = OxyColor.FromUInt32(0xFFF8F8FF); + + /// + /// The gold. + /// + public static readonly OxyColor Gold = OxyColor.FromUInt32(0xFFFFD700); + + /// + /// The goldenrod. + /// + public static readonly OxyColor Goldenrod = OxyColor.FromUInt32(0xFFDAA520); + + /// + /// The gray. + /// + public static readonly OxyColor Gray = OxyColor.FromUInt32(0xFF808080); + + /// + /// The green. + /// + public static readonly OxyColor Green = OxyColor.FromUInt32(0xFF008000); + + /// + /// The green yellow. + /// + public static readonly OxyColor GreenYellow = OxyColor.FromUInt32(0xFFADFF2F); + + /// + /// The honeydew. + /// + public static readonly OxyColor Honeydew = OxyColor.FromUInt32(0xFFF0FFF0); + + /// + /// The hot pink. + /// + public static readonly OxyColor HotPink = OxyColor.FromUInt32(0xFFFF69B4); + + /// + /// The indian red. + /// + public static readonly OxyColor IndianRed = OxyColor.FromUInt32(0xFFCD5C5C); + + /// + /// The indigo. + /// + public static readonly OxyColor Indigo = OxyColor.FromUInt32(0xFF4B0082); + + /// + /// The ivory. + /// + public static readonly OxyColor Ivory = OxyColor.FromUInt32(0xFFFFFFF0); + + /// + /// The khaki. + /// + public static readonly OxyColor Khaki = OxyColor.FromUInt32(0xFFF0E68C); + + /// + /// The lavender. + /// + public static readonly OxyColor Lavender = OxyColor.FromUInt32(0xFFE6E6FA); + + /// + /// The lavender blush. + /// + public static readonly OxyColor LavenderBlush = OxyColor.FromUInt32(0xFFFFF0F5); + + /// + /// The lawn green. + /// + public static readonly OxyColor LawnGreen = OxyColor.FromUInt32(0xFF7CFC00); + + /// + /// The lemon chiffon. + /// + public static readonly OxyColor LemonChiffon = OxyColor.FromUInt32(0xFFFFFACD); + + /// + /// The light blue. + /// + public static readonly OxyColor LightBlue = OxyColor.FromUInt32(0xFFADD8E6); + + /// + /// The light coral. + /// + public static readonly OxyColor LightCoral = OxyColor.FromUInt32(0xFFF08080); + + /// + /// The light cyan. + /// + public static readonly OxyColor LightCyan = OxyColor.FromUInt32(0xFFE0FFFF); + + /// + /// The light goldenrod yellow. + /// + public static readonly OxyColor LightGoldenrodYellow = OxyColor.FromUInt32(0xFFFAFAD2); + + /// + /// The light gray. + /// + public static readonly OxyColor LightGray = OxyColor.FromUInt32(0xFFD3D3D3); + + /// + /// The light green. + /// + public static readonly OxyColor LightGreen = OxyColor.FromUInt32(0xFF90EE90); + + /// + /// The light pink. + /// + public static readonly OxyColor LightPink = OxyColor.FromUInt32(0xFFFFB6C1); + + /// + /// The light salmon. + /// + public static readonly OxyColor LightSalmon = OxyColor.FromUInt32(0xFFFFA07A); + + /// + /// The light sea green. + /// + public static readonly OxyColor LightSeaGreen = OxyColor.FromUInt32(0xFF20B2AA); + + /// + /// The light sky blue. + /// + public static readonly OxyColor LightSkyBlue = OxyColor.FromUInt32(0xFF87CEFA); + + /// + /// The light slate gray. + /// + public static readonly OxyColor LightSlateGray = OxyColor.FromUInt32(0xFF778899); + + /// + /// The light steel blue. + /// + public static readonly OxyColor LightSteelBlue = OxyColor.FromUInt32(0xFFB0C4DE); + + /// + /// The light yellow. + /// + public static readonly OxyColor LightYellow = OxyColor.FromUInt32(0xFFFFFFE0); + + /// + /// The lime. + /// + public static readonly OxyColor Lime = OxyColor.FromUInt32(0xFF00FF00); + + /// + /// The lime green. + /// + public static readonly OxyColor LimeGreen = OxyColor.FromUInt32(0xFF32CD32); + + /// + /// The linen. + /// + public static readonly OxyColor Linen = OxyColor.FromUInt32(0xFFFAF0E6); + + /// + /// The magenta. + /// + public static readonly OxyColor Magenta = OxyColor.FromUInt32(0xFFFF00FF); + + /// + /// The maroon. + /// + public static readonly OxyColor Maroon = OxyColor.FromUInt32(0xFF800000); + + /// + /// The medium aquamarine. + /// + public static readonly OxyColor MediumAquamarine = OxyColor.FromUInt32(0xFF66CDAA); + + /// + /// The medium blue. + /// + public static readonly OxyColor MediumBlue = OxyColor.FromUInt32(0xFF0000CD); + + /// + /// The medium orchid. + /// + public static readonly OxyColor MediumOrchid = OxyColor.FromUInt32(0xFFBA55D3); + + /// + /// The medium purple. + /// + public static readonly OxyColor MediumPurple = OxyColor.FromUInt32(0xFF9370DB); + + /// + /// The medium sea green. + /// + public static readonly OxyColor MediumSeaGreen = OxyColor.FromUInt32(0xFF3CB371); + + /// + /// The medium slate blue. + /// + public static readonly OxyColor MediumSlateBlue = OxyColor.FromUInt32(0xFF7B68EE); + + /// + /// The medium spring green. + /// + public static readonly OxyColor MediumSpringGreen = OxyColor.FromUInt32(0xFF00FA9A); + + /// + /// The medium turquoise. + /// + public static readonly OxyColor MediumTurquoise = OxyColor.FromUInt32(0xFF48D1CC); + + /// + /// The medium violet red. + /// + public static readonly OxyColor MediumVioletRed = OxyColor.FromUInt32(0xFFC71585); + + /// + /// The midnight blue. + /// + public static readonly OxyColor MidnightBlue = OxyColor.FromUInt32(0xFF191970); + + /// + /// The mint cream. + /// + public static readonly OxyColor MintCream = OxyColor.FromUInt32(0xFFF5FFFA); + + /// + /// The misty rose. + /// + public static readonly OxyColor MistyRose = OxyColor.FromUInt32(0xFFFFE4E1); + + /// + /// The moccasin. + /// + public static readonly OxyColor Moccasin = OxyColor.FromUInt32(0xFFFFE4B5); + + /// + /// The navajo white. + /// + public static readonly OxyColor NavajoWhite = OxyColor.FromUInt32(0xFFFFDEAD); + + /// + /// The navy. + /// + public static readonly OxyColor Navy = OxyColor.FromUInt32(0xFF000080); + + /// + /// The old lace. + /// + public static readonly OxyColor OldLace = OxyColor.FromUInt32(0xFFFDF5E6); + + /// + /// The olive. + /// + public static readonly OxyColor Olive = OxyColor.FromUInt32(0xFF808000); + + /// + /// The olive drab. + /// + public static readonly OxyColor OliveDrab = OxyColor.FromUInt32(0xFF6B8E23); + + /// + /// The orange. + /// + public static readonly OxyColor Orange = OxyColor.FromUInt32(0xFFFFA500); + + /// + /// The orange red. + /// + public static readonly OxyColor OrangeRed = OxyColor.FromUInt32(0xFFFF4500); + + /// + /// The orchid. + /// + public static readonly OxyColor Orchid = OxyColor.FromUInt32(0xFFDA70D6); + + /// + /// The pale goldenrod. + /// + public static readonly OxyColor PaleGoldenrod = OxyColor.FromUInt32(0xFFEEE8AA); + + /// + /// The pale green. + /// + public static readonly OxyColor PaleGreen = OxyColor.FromUInt32(0xFF98FB98); + + /// + /// The pale turquoise. + /// + public static readonly OxyColor PaleTurquoise = OxyColor.FromUInt32(0xFFAFEEEE); + + /// + /// The pale violet red. + /// + public static readonly OxyColor PaleVioletRed = OxyColor.FromUInt32(0xFFDB7093); + + /// + /// The papaya whip. + /// + public static readonly OxyColor PapayaWhip = OxyColor.FromUInt32(0xFFFFEFD5); + + /// + /// The peach puff. + /// + public static readonly OxyColor PeachPuff = OxyColor.FromUInt32(0xFFFFDAB9); + + /// + /// The peru. + /// + public static readonly OxyColor Peru = OxyColor.FromUInt32(0xFFCD853F); + + /// + /// The pink. + /// + public static readonly OxyColor Pink = OxyColor.FromUInt32(0xFFFFC0CB); + + /// + /// The plum. + /// + public static readonly OxyColor Plum = OxyColor.FromUInt32(0xFFDDA0DD); + + /// + /// The powder blue. + /// + public static readonly OxyColor PowderBlue = OxyColor.FromUInt32(0xFFB0E0E6); + + /// + /// The purple. + /// + public static readonly OxyColor Purple = OxyColor.FromUInt32(0xFF800080); + + /// + /// The red. + /// + public static readonly OxyColor Red = OxyColor.FromUInt32(0xFFFF0000); + + /// + /// The rosy brown. + /// + public static readonly OxyColor RosyBrown = OxyColor.FromUInt32(0xFFBC8F8F); + + /// + /// The royal blue. + /// + public static readonly OxyColor RoyalBlue = OxyColor.FromUInt32(0xFF4169E1); + + /// + /// The saddle brown. + /// + public static readonly OxyColor SaddleBrown = OxyColor.FromUInt32(0xFF8B4513); + + /// + /// The salmon. + /// + public static readonly OxyColor Salmon = OxyColor.FromUInt32(0xFFFA8072); + + /// + /// The sandy brown. + /// + public static readonly OxyColor SandyBrown = OxyColor.FromUInt32(0xFFF4A460); + + /// + /// The sea green. + /// + public static readonly OxyColor SeaGreen = OxyColor.FromUInt32(0xFF2E8B57); + + /// + /// The sea shell. + /// + public static readonly OxyColor SeaShell = OxyColor.FromUInt32(0xFFFFF5EE); + + /// + /// The sienna. + /// + public static readonly OxyColor Sienna = OxyColor.FromUInt32(0xFFA0522D); + + /// + /// The silver. + /// + public static readonly OxyColor Silver = OxyColor.FromUInt32(0xFFC0C0C0); + + /// + /// The sky blue. + /// + public static readonly OxyColor SkyBlue = OxyColor.FromUInt32(0xFF87CEEB); + + /// + /// The slate blue. + /// + public static readonly OxyColor SlateBlue = OxyColor.FromUInt32(0xFF6A5ACD); + + /// + /// The slate gray. + /// + public static readonly OxyColor SlateGray = OxyColor.FromUInt32(0xFF708090); + + /// + /// The snow. + /// + public static readonly OxyColor Snow = OxyColor.FromUInt32(0xFFFFFAFA); + + /// + /// The spring green. + /// + public static readonly OxyColor SpringGreen = OxyColor.FromUInt32(0xFF00FF7F); + + /// + /// The steel blue. + /// + public static readonly OxyColor SteelBlue = OxyColor.FromUInt32(0xFF4682B4); + + /// + /// The tan. + /// + public static readonly OxyColor Tan = OxyColor.FromUInt32(0xFFD2B48C); + + /// + /// The teal. + /// + public static readonly OxyColor Teal = OxyColor.FromUInt32(0xFF008080); + + /// + /// The thistle. + /// + public static readonly OxyColor Thistle = OxyColor.FromUInt32(0xFFD8BFD8); + + /// + /// The tomato. + /// + public static readonly OxyColor Tomato = OxyColor.FromUInt32(0xFFFF6347); + + /// + /// The transparent. + /// + public static readonly OxyColor Transparent = OxyColor.FromUInt32(0x00FFFFFF); + + /// + /// The turquoise. + /// + public static readonly OxyColor Turquoise = OxyColor.FromUInt32(0xFF40E0D0); + + /// + /// The violet. + /// + public static readonly OxyColor Violet = OxyColor.FromUInt32(0xFFEE82EE); + + /// + /// The wheat. + /// + public static readonly OxyColor Wheat = OxyColor.FromUInt32(0xFFF5DEB3); + + /// + /// The white. + /// + public static readonly OxyColor White = OxyColor.FromUInt32(0xFFFFFFFF); + + /// + /// The white smoke. + /// + public static readonly OxyColor WhiteSmoke = OxyColor.FromUInt32(0xFFF5F5F5); + + /// + /// The yellow. + /// + public static readonly OxyColor Yellow = OxyColor.FromUInt32(0xFFFFFF00); + + /// + /// The yellow green. + /// + public static readonly OxyColor YellowGreen = OxyColor.FromUInt32(0xFF9ACD32); + + } +} \ No newline at end of file diff -r 88d699a65cc2 -r 5be8f2773237 External/OxyPlot/OxyPlot/Foundation/OxyImage.cs --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/External/OxyPlot/OxyPlot/Foundation/OxyImage.cs Sat Jun 08 16:53:22 2013 +0000 @@ -0,0 +1,444 @@ +// -------------------------------------------------------------------------------------------------------------------- +// +// The MIT License (MIT) +// +// Copyright (c) 2012 Oystein Bjorke +// +// Permission is hereby granted, free of charge, to any person obtaining a +// copy of this software and associated documentation files (the +// "Software"), to deal in the Software without restriction, including +// without limitation the rights to use, copy, modify, merge, publish, +// distribute, sublicense, and/or sell copies of the Software, and to +// permit persons to whom the Software is furnished to do so, subject to +// the following conditions: +// +// The above copyright notice and this permission notice shall be included +// in all copies or substantial portions of the Software. +// +// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS +// OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF +// MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. +// IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY +// CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, +// TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE +// SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. +// +// +// Represents an image, encoded as DIB, JPEG or PNG. +// +// -------------------------------------------------------------------------------------------------------------------- +namespace OxyPlot +{ + using System; + using System.IO; + using System.Linq; + + /// + /// Represents an image, encoded as DIB, JPEG or PNG. + /// + public class OxyImage + { + /// + /// The image data. + /// + private readonly byte[] data; + + /// + /// Initializes a new instance of the class from the specified stream. + /// + /// + /// A stream that provides the image data. + /// + public OxyImage(Stream s) + { + using (var ms = new MemoryStream()) + { + s.CopyTo(ms); + this.data = ms.ToArray(); + } + } + + /// + /// Initializes a new instance of the class from a byte array. + /// + /// + /// The image bytes. + /// + public OxyImage(byte[] bytes) + { + this.data = bytes; + } + + /// + /// Creates an from the specified array. + /// + /// + /// The pixel data, indexed as [row,column] (from bottom-left). + /// + /// + /// The resolution. + /// + /// + /// An . + /// + /// + /// This method is creating a simple BitmapInfoHeader. + /// + public static OxyImage FromArgbX(OxyColor[,] data, int dpi = 96) + { + int height = data.GetLength(0); + int width = data.GetLength(1); + var bytes = new byte[width * height * 4]; + int k = 0; + for (int i = 0; i < height; i++) + { + for (int j = 0; j < width; j++) + { + bytes[k++] = data[i, j].B; + bytes[k++] = data[i, j].G; + bytes[k++] = data[i, j].R; + bytes[k++] = data[i, j].A; + } + } + + return FromArgbX(width, height, bytes, dpi); + } + + /// + /// Creates an from the specified array. + /// + /// + /// The pixel data, indexed as [row,column] (from bottom-left). + /// + /// + /// The resolution. + /// + /// + /// An . + /// + /// + /// This method is creating a Bitmap V4 info header, including channel bit masks and color space information. + /// + public static OxyImage FromArgb(OxyColor[,] data, int dpi = 96) + { + int height = data.GetLength(0); + int width = data.GetLength(1); + var bytes = new byte[width * height * 4]; + int k = 0; + for (int i = 0; i < height; i++) + { + for (int j = 0; j < width; j++) + { + bytes[k++] = data[i, j].B; + bytes[k++] = data[i, j].G; + bytes[k++] = data[i, j].R; + bytes[k++] = data[i, j].A; + } + } + + return FromArgb(width, height, bytes, dpi); + } + + /// + /// Creates an from the specified pixel data. + /// + /// + /// The width. + /// + /// + /// The height. + /// + /// + /// The pixel data (BGRA from bottom-left). + /// + /// + /// The resolution. + /// + /// + /// An . + /// + /// + /// This method is creating a Bitmap V4 info header, including channel bit masks and color space information. + /// + public static OxyImage FromArgb(int width, int height, byte[] pixelData, int dpi = 96) + { + var ms = new MemoryStream(); + var w = new BinaryWriter(ms); + + const int OffBits = 14 + 108; + var size = OffBits + pixelData.Length; + + // Bitmap file header (14 bytes) + w.Write((byte)'B'); + w.Write((byte)'M'); + w.Write((uint)size); + w.Write((ushort)0); + w.Write((ushort)0); + w.Write((uint)OffBits); + + // Bitmap V4 info header (108 bytes) + WriteBitmapV4Header(w, width, height, 32, pixelData.Length, dpi); + + // Pixel array (from bottom-left corner) + w.Write(pixelData); + + return new OxyImage(ms.ToArray()); + } + + /// + /// Creates an from the specified 8-bit indexed pixel data. + /// + /// + /// The indexed pixel data (from bottom-left). + /// + /// + /// The palette. + /// + /// + /// The resolution. + /// + /// + /// An . + /// + public static OxyImage FromIndexed8(byte[,] indexedData, OxyColor[] palette, int dpi = 96) + { + int height = indexedData.GetLength(0); + int width = indexedData.GetLength(1); + return FromIndexed8(width, height, indexedData.Cast().ToArray(), palette, dpi); + } + + /// + /// Creates an from the specified 8-bit indexed pixel data. + /// + /// + /// The width. + /// + /// + /// The height. + /// + /// + /// The indexed pixel data (from bottom-left). + /// + /// + /// The palette. + /// + /// + /// The resolution. + /// + /// + /// An . + /// + public static OxyImage FromIndexed8( + int width, int height, byte[] indexedPixelData, OxyColor[] palette, int dpi = 96) + { + if (indexedPixelData.Length != width * height) + { + throw new ArgumentException("Length of data is not correct.", "indexedPixelData"); + } + + if (palette.Length == 0) + { + throw new ArgumentException("Palette not defined.", "palette"); + } + + var ms = new MemoryStream(); + var w = new BinaryWriter(ms); + + var offBits = 14 + 40 + (4 * palette.Length); + var size = offBits + indexedPixelData.Length; + + // Bitmap file header (14 bytes) + w.Write((byte)'B'); + w.Write((byte)'M'); + w.Write((uint)size); + w.Write((ushort)0); + w.Write((ushort)0); + w.Write((uint)offBits); + + // Bitmap info header + WriteBitmapInfoHeader(w, width, height, 8, indexedPixelData.Length, dpi, palette.Length); + + // Color table + foreach (var color in palette) + { + w.Write(color.B); + w.Write(color.G); + w.Write(color.R); + w.Write(color.A); + } + + // Pixel array (from bottom-left corner) + w.Write(indexedPixelData); + + return new OxyImage(ms.ToArray()); + } + + /// + /// Creates an from the specified pixel data. + /// + /// + /// The width. + /// + /// + /// The height. + /// + /// + /// The pixel data (BGRA from bottom-left). + /// + /// + /// The resolution. + /// + /// + /// An . + /// + /// + /// This method is creating a simple BitmapInfoHeader. + /// + public static OxyImage FromArgbX(int width, int height, byte[] pixelData, int dpi = 96) + { + var ms = new MemoryStream(); + var w = new BinaryWriter(ms); + + const int OffBits = 14 + 40; + var size = OffBits + pixelData.Length; + + // Bitmap file header (14 bytes) + w.Write((byte)'B'); + w.Write((byte)'M'); + w.Write((uint)size); + w.Write((ushort)0); + w.Write((ushort)0); + w.Write((uint)OffBits); + + // Bitmap info header + WriteBitmapInfoHeader(w, width, height, 32, pixelData.Length, dpi); + + // Pixel array (from bottom-left corner) + w.Write(pixelData); + + return new OxyImage(ms.ToArray()); + } + + /// + /// Gets the image data. + /// + /// + /// The image data as a byte array. + /// + public byte[] GetData() + { + return this.data; + } + + /// + /// Writes the bitmap info header. + /// + /// + /// The writer. + /// + /// + /// The width. + /// + /// + /// The height. + /// + /// + /// The number of bits per pixel. + /// + /// + /// The length of the pixel data. + /// + /// + /// The dpi. + /// + /// + /// The number of colors. + /// + private static void WriteBitmapInfoHeader( + BinaryWriter w, int width, int height, int bitsPerPixel, int length, int dpi, int colors = 0) + { + // Convert resolution to pixels per meter + var ppm = (uint)(dpi / 0.0254); + + w.Write((uint)40); + w.Write((uint)width); + w.Write((uint)height); + w.Write((ushort)1); + w.Write((ushort)bitsPerPixel); + w.Write((uint)0); + w.Write((uint)length); + w.Write(ppm); + w.Write(ppm); + w.Write((uint)colors); + w.Write((uint)colors); + } + + /// + /// Writes the bitmap V4 header. + /// + /// + /// The writer. + /// + /// + /// The width. + /// + /// + /// The height. + /// + /// + /// The number of bits per pixel. + /// + /// + /// The length. + /// + /// + /// The resolution. + /// + /// + /// The number of colors. + /// + private static void WriteBitmapV4Header( + BinaryWriter w, int width, int height, int bitsPerPixel, int length, int dpi, int colors = 0) + { + // Convert resolution to pixels per meter + var ppm = (uint)(dpi / 0.0254); + + w.Write((uint)108); + w.Write((uint)width); + w.Write((uint)height); + w.Write((ushort)1); + w.Write((ushort)bitsPerPixel); + w.Write((uint)3); + w.Write((uint)length); + w.Write(ppm); + w.Write(ppm); + w.Write((uint)colors); + w.Write((uint)colors); + + // Write the channel bit masks + w.Write(0x00FF0000); + w.Write(0x0000FF00); + w.Write(0x000000FF); + w.Write(0xFF000000); + + // Write the color space + w.Write((uint)0x206E6957); + w.Write(new byte[3 * 3 * 4]); + + // Write the gamma RGB + w.Write((uint)0); + w.Write((uint)0); + w.Write((uint)0); + } + + /// + /// Creates a PNG image from the specified pixels. + /// + /// The pixels (bottom line first). + /// An OxyImage. + public static OxyImage PngFromArgb(OxyColor[,] pixels) + { + return new OxyImage(PngEncoder.Encode(pixels)); + } + } +} \ No newline at end of file diff -r 88d699a65cc2 -r 5be8f2773237 External/OxyPlot/OxyPlot/Foundation/OxyPalette.cs --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/External/OxyPlot/OxyPlot/Foundation/OxyPalette.cs Sat Jun 08 16:53:22 2013 +0000 @@ -0,0 +1,102 @@ +// -------------------------------------------------------------------------------------------------------------------- +// +// The MIT License (MIT) +// +// Copyright (c) 2012 Oystein Bjorke +// +// Permission is hereby granted, free of charge, to any person obtaining a +// copy of this software and associated documentation files (the +// "Software"), to deal in the Software without restriction, including +// without limitation the rights to use, copy, modify, merge, publish, +// distribute, sublicense, and/or sell copies of the Software, and to +// permit persons to whom the Software is furnished to do so, subject to +// the following conditions: +// +// The above copyright notice and this permission notice shall be included +// in all copies or substantial portions of the Software. +// +// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS +// OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF +// MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. +// IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY +// CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, +// TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE +// SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. +// +// +// Represents a palette of colors. +// +// -------------------------------------------------------------------------------------------------------------------- +namespace OxyPlot +{ + using System.Collections.Generic; + + /// + /// Represents a palette of colors. + /// + public class OxyPalette + { + /// + /// Initializes a new instance of the class. + /// + public OxyPalette() + { + this.Colors = new List(); + } + + /// + /// Initializes a new instance of the class. + /// + /// + /// The colors. + /// + public OxyPalette(params OxyColor[] colors) + { + this.Colors = new List(colors); + } + + /// + /// Initializes a new instance of the class. + /// + /// + /// The colors. + /// + public OxyPalette(IEnumerable colors) + { + this.Colors = new List(colors); + } + + /// + /// Gets or sets the colors. + /// + /// The colors. + public IList Colors { get; set; } + + /// + /// Interpolates the specified colors to a palette of the specified size. + /// + /// + /// The size of the palette. + /// + /// + /// The colors. + /// + /// + /// A palette. + /// + public static OxyPalette Interpolate(int paletteSize, params OxyColor[] colors) + { + var palette = new OxyColor[paletteSize]; + for (int i = 0; i < paletteSize; i++) + { + double y = (double)i / (paletteSize - 1); + double x = y * (colors.Length - 1); + int i0 = (int)x; + int i1 = i0 + 1 < colors.Length ? i0 + 1 : i0; + palette[i] = OxyColor.Interpolate(colors[i0], colors[i1], x - i0); + } + + return new OxyPalette(palette); + } + } +} \ No newline at end of file diff -r 88d699a65cc2 -r 5be8f2773237 External/OxyPlot/OxyPlot/Foundation/OxyPalettes.cs --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/External/OxyPlot/OxyPlot/Foundation/OxyPalettes.cs Sat Jun 08 16:53:22 2013 +0000 @@ -0,0 +1,208 @@ +// -------------------------------------------------------------------------------------------------------------------- +// +// The MIT License (MIT) +// +// Copyright (c) 2012 Oystein Bjorke +// +// Permission is hereby granted, free of charge, to any person obtaining a +// copy of this software and associated documentation files (the +// "Software"), to deal in the Software without restriction, including +// without limitation the rights to use, copy, modify, merge, publish, +// distribute, sublicense, and/or sell copies of the Software, and to +// permit persons to whom the Software is furnished to do so, subject to +// the following conditions: +// +// The above copyright notice and this permission notice shall be included +// in all copies or substantial portions of the Software. +// +// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS +// OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF +// MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. +// IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY +// CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, +// TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE +// SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. +// +// +// Provides predefined palettes. +// +// -------------------------------------------------------------------------------------------------------------------- +namespace OxyPlot +{ + /// + /// Provides predefined palettes. + /// + public static class OxyPalettes + { + /// + /// Initializes static members of the class. + /// + static OxyPalettes() + { + BlueWhiteRed31 = BlueWhiteRed(31); + Hot64 = Hot(64); + Hue64 = Hue(64); + } + + /// + /// Gets the blue white red (31) palette. + /// + public static OxyPalette BlueWhiteRed31 { get; private set; } + + /// + /// Gets the hot (64) palette. + /// + public static OxyPalette Hot64 { get; private set; } + + /// + /// Gets the hue64 palette. + /// + public static OxyPalette Hue64 { get; private set; } + + /// + /// Creates a black/white/red palette with the specified number of colors. + /// + /// + /// The number of colors to create for the palette. + /// + /// + /// A palette. + /// + public static OxyPalette BlackWhiteRed(int numberOfColors) + { + return OxyPalette.Interpolate(numberOfColors, OxyColors.Black, OxyColors.White, OxyColors.Red); + } + + /// + /// Creates a blue/white/red palette with the specified number of colors. + /// + /// + /// The number of colors to create for the palette. + /// + /// + /// A palette. + /// + public static OxyPalette BlueWhiteRed(int numberOfColors) + { + return OxyPalette.Interpolate(numberOfColors, OxyColors.Blue, OxyColors.White, OxyColors.Red); + } + + /// + /// Creates a 'cool' palette with the specified number of colors. + /// + /// + /// The number of colors to create for the palette. + /// + /// + /// A palette. + /// + public static OxyPalette Cool(int numberOfColors) + { + return OxyPalette.Interpolate(numberOfColors, OxyColors.Cyan, OxyColors.Magenta); + } + + /// + /// Creates a gray-scale palette with the specified number of colors. + /// + /// + /// The number of colors to create for the palette. + /// + /// + /// A palette. + /// + public static OxyPalette Gray(int numberOfColors) + { + return OxyPalette.Interpolate(numberOfColors, OxyColors.Black, OxyColors.White); + } + + /// + /// Creates a 'hot' palette with the specified number of colors. + /// + /// + /// The number of colors to create for the palette. + /// + /// + /// A palette. + /// + public static OxyPalette Hot(int numberOfColors) + { + return OxyPalette.Interpolate( + numberOfColors, + OxyColors.Black, + OxyColor.FromRgb(127, 0, 0), + OxyColor.FromRgb(255, 127, 0), + OxyColor.FromRgb(255, 255, 127), + OxyColors.White); + } + + /// + /// Creates a palette from the hue component of the HSV color model. + /// + /// + /// The number of colors. + /// + /// + /// The palette. + /// + /// + /// This palette is particularly appropriate for displaying periodic functions. + /// + public static OxyPalette Hue(int numberOfColors) + { + return OxyPalette.Interpolate( + numberOfColors, + OxyColors.Red, + OxyColors.Yellow, + OxyColors.Green, + OxyColors.Cyan, + OxyColors.Blue, + OxyColors.Magenta, + OxyColors.Red); + } + + /// + /// Creates a 'jet' palette with the specified number of colors. + /// + /// + /// The number of colors to create for the palette. + /// + /// + /// A palette. + /// + /// + /// See http://www.mathworks.se/help/techdoc/ref/colormap.html. + /// + public static OxyPalette Jet(int numberOfColors) + { + return OxyPalette.Interpolate( + numberOfColors, + OxyColors.DarkBlue, + OxyColors.Cyan, + OxyColors.Yellow, + OxyColors.Orange, + OxyColors.DarkRed); + } + + /// + /// Creates a rainbow palette with the specified number of colors. + /// + /// + /// The number of colors to create for the palette. + /// + /// + /// A palette. + /// + public static OxyPalette Rainbow(int numberOfColors) + { + return OxyPalette.Interpolate( + numberOfColors, + OxyColors.Violet, + OxyColors.Indigo, + OxyColors.Blue, + OxyColors.Green, + OxyColors.Yellow, + OxyColors.Orange, + OxyColors.Red); + } + } +} \ No newline at end of file diff -r 88d699a65cc2 -r 5be8f2773237 External/OxyPlot/OxyPlot/Foundation/OxyPen.cs --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/External/OxyPlot/OxyPlot/Foundation/OxyPen.cs Sat Jun 08 16:53:22 2013 +0000 @@ -0,0 +1,138 @@ +// -------------------------------------------------------------------------------------------------------------------- +// +// The MIT License (MIT) +// +// Copyright (c) 2012 Oystein Bjorke +// +// Permission is hereby granted, free of charge, to any person obtaining a +// copy of this software and associated documentation files (the +// "Software"), to deal in the Software without restriction, including +// without limitation the rights to use, copy, modify, merge, publish, +// distribute, sublicense, and/or sell copies of the Software, and to +// permit persons to whom the Software is furnished to do so, subject to +// the following conditions: +// +// The above copyright notice and this permission notice shall be included +// in all copies or substantial portions of the Software. +// +// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS +// OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF +// MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. +// IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY +// CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, +// TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE +// SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. +// +// +// Describes a pen in terms of color, thickness, line style and line join type. +// +// -------------------------------------------------------------------------------------------------------------------- +namespace OxyPlot +{ + using System; + + /// + /// Describes a pen in terms of color, thickness, line style and line join type. + /// + public class OxyPen + { + /// + /// Initializes a new instance of the class. + /// + /// + /// The color. + /// + /// + /// The thickness. + /// + /// + /// The line style. + /// + /// + /// The line join. + /// + public OxyPen( + OxyColor color, + double thickness = 1.0, + LineStyle lineStyle = LineStyle.Solid, + OxyPenLineJoin lineJoin = OxyPenLineJoin.Miter) + { + this.Color = color; + this.Thickness = thickness; + this.DashArray = LineStyleHelper.GetDashArray(lineStyle); + this.LineStyle = lineStyle; + this.LineJoin = lineJoin; + } + + /// + /// Gets or sets the color. + /// + /// The color. + public OxyColor Color { get; set; } + + /// + /// Gets or sets the dash array. + /// + /// The dash array. + public double[] DashArray { get; set; } + + /// + /// Gets or sets the line join. + /// + /// The line join. + public OxyPenLineJoin LineJoin { get; set; } + + /// + /// Gets or sets the line style. + /// + /// The line style. + public LineStyle LineStyle { get; set; } + + /// + /// Gets or sets the thickness. + /// + /// The thickness. + public double Thickness { get; set; } + + /// + /// Creates the specified pen. + /// + /// The color. + /// The thickness. + /// The line style. + /// The line join. + /// A pen. + public static OxyPen Create( + OxyColor color, + double thickness, + LineStyle lineStyle = LineStyle.Solid, + OxyPenLineJoin lineJoin = OxyPenLineJoin.Miter) + { + if (color == null || lineStyle == LineStyle.None || Math.Abs(thickness) < double.Epsilon) + { + return null; + } + + return new OxyPen(color, thickness, lineStyle, lineJoin); + } + + /// + /// Returns a hash code for this instance. + /// + /// + /// A hash code for this instance, suitable for use in hashing algorithms and data structures like a hash table. + /// + public override int GetHashCode() + { + unchecked + { + int result = this.Color.GetHashCode(); + result = (result * 397) ^ this.Thickness.GetHashCode(); + result = (result * 397) ^ this.LineStyle.GetHashCode(); + result = (result * 397) ^ this.LineJoin.GetHashCode(); + return result; + } + } + + } +} \ No newline at end of file diff -r 88d699a65cc2 -r 5be8f2773237 External/OxyPlot/OxyPlot/Foundation/OxyPenLineJoin.cs --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/External/OxyPlot/OxyPlot/Foundation/OxyPenLineJoin.cs Sat Jun 08 16:53:22 2013 +0000 @@ -0,0 +1,52 @@ +// -------------------------------------------------------------------------------------------------------------------- +// +// The MIT License (MIT) +// +// Copyright (c) 2012 Oystein Bjorke +// +// Permission is hereby granted, free of charge, to any person obtaining a +// copy of this software and associated documentation files (the +// "Software"), to deal in the Software without restriction, including +// without limitation the rights to use, copy, modify, merge, publish, +// distribute, sublicense, and/or sell copies of the Software, and to +// permit persons to whom the Software is furnished to do so, subject to +// the following conditions: +// +// The above copyright notice and this permission notice shall be included +// in all copies or substantial portions of the Software. +// +// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS +// OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF +// MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. +// IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY +// CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, +// TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE +// SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. +// +// +// Pen line join. +// +// -------------------------------------------------------------------------------------------------------------------- +namespace OxyPlot +{ + /// + /// Specifies how to join line segments. + /// + public enum OxyPenLineJoin + { + /// + /// Line joins use regular angular vertices. + /// + Miter, + + /// + /// Line joins use rounded vertices. + /// + Round, + + /// + /// Line joins use beveled vertices. + /// + Bevel + } +} \ No newline at end of file diff -r 88d699a65cc2 -r 5be8f2773237 External/OxyPlot/OxyPlot/Foundation/OxyRect.cs --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/External/OxyPlot/OxyPlot/Foundation/OxyRect.cs Sat Jun 08 16:53:22 2013 +0000 @@ -0,0 +1,287 @@ +// -------------------------------------------------------------------------------------------------------------------- +// +// The MIT License (MIT) +// +// Copyright (c) 2012 Oystein Bjorke +// +// Permission is hereby granted, free of charge, to any person obtaining a +// copy of this software and associated documentation files (the +// "Software"), to deal in the Software without restriction, including +// without limitation the rights to use, copy, modify, merge, publish, +// distribute, sublicense, and/or sell copies of the Software, and to +// permit persons to whom the Software is furnished to do so, subject to +// the following conditions: +// +// The above copyright notice and this permission notice shall be included +// in all copies or substantial portions of the Software. +// +// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS +// OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF +// MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. +// IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY +// CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, +// TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE +// SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. +// +// +// Describes the width, height, and point origin of a rectangle. +// +// -------------------------------------------------------------------------------------------------------------------- +namespace OxyPlot +{ + using System; + using System.Diagnostics; + using System.Globalization; + + /// + /// Describes the width, height, and point origin of a rectangle. + /// + public struct OxyRect + { + /// + /// The height of the rectangle. + /// + private double height; + + /// + /// The x-coordinate location of the left side of the rectangle. + /// + private double left; + + /// + /// The y-coordinate location of the top side of the rectangle. + /// + private double top; + + /// + /// The width of the rectangle. + /// + private double width; + + /// + /// Initializes a new instance of the structure that has the specified x-coordinate, y-coordinate, width, and height. + /// + /// + /// The x-coordinate location of the left side of the rectangle. + /// + /// + /// The y-coordinate location of the top side of the rectangle. + /// + /// + /// The width of the rectangle. + /// + /// + /// The height of the rectangle. + /// + public OxyRect(double left, double top, double width, double height) + { + this.left = left; + this.top = top; + this.width = width; + this.height = height; + Debug.Assert(width >= 0, "Width should be larger than 0."); + Debug.Assert(height >= 0, "Height should be larger than 0."); + } + + /// + /// Gets or sets the y-axis value of the bottom of the rectangle. + /// + /// + /// The bottom. + /// + public double Bottom + { + get + { + return this.top + this.height; + } + + set + { + this.height = value - this.top; + } + } + + /// + /// Gets or sets the height of the rectangle. + /// + /// + /// The height. + /// + public double Height + { + get + { + return this.height; + } + + set + { + this.height = value; + } + } + + /// + /// Gets or sets the x-axis value of the left side of the rectangle. + /// + /// + /// The left. + /// + public double Left + { + get + { + return this.left; + } + + set + { + this.left = value; + } + } + + /// + /// Gets or sets the x-axis value of the right side of the rectangle. + /// + /// + /// The right. + /// + public double Right + { + get + { + return this.left + this.width; + } + + set + { + this.width = value - this.left; + } + } + + /// + /// Gets or sets the y-axis position of the top of the rectangle. + /// + /// + /// The top. + /// + public double Top + { + get + { + return this.top; + } + + set + { + this.top = value; + } + } + + /// + /// Gets or sets the width of the rectangle. + /// + /// + /// The width. + /// + public double Width + { + get + { + return this.width; + } + + set + { + this.width = value; + } + } + + /// + /// Gets the center point of the rectangle. + /// + /// The center. + public ScreenPoint Center + { + get + { + return new ScreenPoint(this.left + (this.width * 0.5), this.top + (this.height * 0.5)); + } + } + + /// + /// Creates a rectangle from the specified corner coordinates. + /// + /// + /// The x0. + /// + /// + /// The y0. + /// + /// + /// The x1. + /// + /// + /// The y1. + /// + /// + /// A rectangle. + /// + public static OxyRect Create(double x0, double y0, double x1, double y1) + { + return new OxyRect(Math.Min(x0, x1), Math.Min(y0, y1), Math.Abs(x1 - x0), Math.Abs(y1 - y0)); + } + + /// + /// Creates a rectangle from the specified corner coordinates. + /// + /// The first corner. + /// The second corner. + /// A rectangle. + public static OxyRect Create(ScreenPoint p0, ScreenPoint p1) + { + return Create(p0.X, p0.Y, p1.X, p1.Y); + } + + /// + /// Determines whether the specified point is inside the rectangle. + /// + /// + /// The x coordinate. + /// + /// + /// The y coordinate. + /// + /// + /// true if the rectangle contains the specified point; otherwise, false. + /// + public bool Contains(double x, double y) + { + return x >= this.Left && x <= this.Right && y >= this.Top && y <= this.Bottom; + } + + /// + /// Determines whether the specified point is inside the rectangle. + /// + /// The point. + /// + /// true if the rectangle contains the specified point; otherwise, false. + /// + public bool Contains(ScreenPoint p) + { + return this.Contains(p.x, p.y); + } + + /// + /// Returns a that represents this instance. + /// + /// + /// A that represents this instance. + /// + public override string ToString() + { + return string.Format( + CultureInfo.InvariantCulture, "({0}, {1}, {2}, {3})", this.left, this.top, this.width, this.height); + } + } +} \ No newline at end of file diff -r 88d699a65cc2 -r 5be8f2773237 External/OxyPlot/OxyPlot/Foundation/OxySize.cs --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/External/OxyPlot/OxyPlot/Foundation/OxySize.cs Sat Jun 08 16:53:22 2013 +0000 @@ -0,0 +1,87 @@ +// -------------------------------------------------------------------------------------------------------------------- +// +// The MIT License (MIT) +// +// Copyright (c) 2012 Oystein Bjorke +// +// Permission is hereby granted, free of charge, to any person obtaining a +// copy of this software and associated documentation files (the +// "Software"), to deal in the Software without restriction, including +// without limitation the rights to use, copy, modify, merge, publish, +// distribute, sublicense, and/or sell copies of the Software, and to +// permit persons to whom the Software is furnished to do so, subject to +// the following conditions: +// +// The above copyright notice and this permission notice shall be included +// in all copies or substantial portions of the Software. +// +// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS +// OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF +// MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. +// IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY +// CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, +// TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE +// SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. +// +// +// Implements a structure that is used to describe the Size of an object. +// +// -------------------------------------------------------------------------------------------------------------------- +namespace OxyPlot +{ + using System.Globalization; + + /// + /// Implements a structure that is used to describe the size of an object. + /// + public struct OxySize + { + /// + /// Empty Size. + /// + public static OxySize Empty = new OxySize(0, 0); + + /// + /// Initializes a new instance of the struct. + /// + /// + /// The width. + /// + /// + /// The height. + /// + public OxySize(double width, double height) + : this() + { + this.Width = width; + this.Height = height; + } + + /// + /// Gets or sets the height. + /// + /// + /// The height. + /// + public double Height { get; set; } + + /// + /// Gets or sets the width. + /// + /// + /// The width. + /// + public double Width { get; set; } + + /// + /// Returns a that represents this instance. + /// + /// + /// A that represents this instance. + /// + public override string ToString() + { + return string.Format(CultureInfo.InvariantCulture, "({0}, {1})", this.Width, this.Height); + } + } +} \ No newline at end of file diff -r 88d699a65cc2 -r 5be8f2773237 External/OxyPlot/OxyPlot/Foundation/OxyThickness.cs --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/External/OxyPlot/OxyPlot/Foundation/OxyThickness.cs Sat Jun 08 16:53:22 2013 +0000 @@ -0,0 +1,220 @@ +// -------------------------------------------------------------------------------------------------------------------- +// +// The MIT License (MIT) +// +// Copyright (c) 2012 Oystein Bjorke +// +// Permission is hereby granted, free of charge, to any person obtaining a +// copy of this software and associated documentation files (the +// "Software"), to deal in the Software without restriction, including +// without limitation the rights to use, copy, modify, merge, publish, +// distribute, sublicense, and/or sell copies of the Software, and to +// permit persons to whom the Software is furnished to do so, subject to +// the following conditions: +// +// The above copyright notice and this permission notice shall be included +// in all copies or substantial portions of the Software. +// +// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS +// OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF +// MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. +// IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY +// CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, +// TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE +// SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. +// +// +// Describes the thickness of a frame around a rectangle. Four Double values describe the Left, Top, Right, and Bottom sides of the rectangle, respectively. +// +// -------------------------------------------------------------------------------------------------------------------- +namespace OxyPlot +{ + using System.Globalization; + + /// + /// Describes the thickness of a frame around a rectangle. Four values describe the left, top, right, and bottom sides of the rectangle, respectively. + /// + public struct OxyThickness : ICodeGenerating + { + /// + /// The bottom. + /// + private double bottom; + + /// + /// The left. + /// + private double left; + + /// + /// The right. + /// + private double right; + + /// + /// The top. + /// + private double top; + + /// + /// Initializes a new instance of the struct. + /// + /// + /// The thickness. + /// + public OxyThickness(double thickness) + : this(thickness, thickness, thickness, thickness) + { + } + + /// + /// Initializes a new instance of the struct. + /// + /// + /// The left. + /// + /// + /// The top. + /// + /// + /// The right. + /// + /// + /// The bottom. + /// + public OxyThickness(double left, double top, double right, double bottom) + { + this.left = left; + this.top = top; + this.right = right; + this.bottom = bottom; + } + + /// + /// Gets or sets the bottom thickness. + /// + /// + /// The bottom thickness. + /// + public double Bottom + { + get + { + return this.bottom; + } + + set + { + this.bottom = value; + } + } + + /// + /// Gets the height. + /// + public double Height + { + get + { + return this.Bottom - this.Top; + } + } + + /// + /// Gets or sets the left thickness. + /// + /// + /// The left thickness. + /// + public double Left + { + get + { + return this.left; + } + + set + { + this.left = value; + } + } + + /// + /// Gets or sets the right thickness. + /// + /// + /// The right thickness. + /// + public double Right + { + get + { + return this.right; + } + + set + { + this.right = value; + } + } + + /// + /// Gets or sets the top thickness. + /// + /// + /// The top thickness. + /// + public double Top + { + get + { + return this.top; + } + + set + { + this.top = value; + } + } + + /// + /// Gets the width. + /// + public double Width + { + get + { + return this.Right - this.Left; + } + } + + /// + /// Returns C# code that generates this instance. + /// + /// + /// The to code. + /// + public string ToCode() + { + return string.Format( + CultureInfo.InvariantCulture, + "new OxyThickness({0},{1},{2},{3})", + this.Left, + this.Top, + this.Right, + this.Bottom); + } + + /// + /// Returns a that represents this instance. + /// + /// + /// A that represents this instance. + /// + public override string ToString() + { + return string.Format( + CultureInfo.InvariantCulture, "({0}, {1}, {2}, {3})", this.left, this.top, this.right, this.bottom); + } + } +} \ No newline at end of file diff -r 88d699a65cc2 -r 5be8f2773237 External/OxyPlot/OxyPlot/Foundation/Pen.cs --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/External/OxyPlot/OxyPlot/Foundation/Pen.cs Sat Jun 08 16:53:22 2013 +0000 @@ -0,0 +1,42 @@ +// -------------------------------------------------------------------------------------------------------------------- +// +// The MIT License (MIT) +// +// Copyright (c) 2012 Oystein Bjorke +// +// Permission is hereby granted, free of charge, to any person obtaining a +// copy of this software and associated documentation files (the +// "Software"), to deal in the Software without restriction, including +// without limitation the rights to use, copy, modify, merge, publish, +// distribute, sublicense, and/or sell copies of the Software, and to +// permit persons to whom the Software is furnished to do so, subject to +// the following conditions: +// +// The above copyright notice and this permission notice shall be included +// in all copies or substantial portions of the Software. +// +// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS +// OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF +// MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. +// IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY +// CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, +// TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE +// SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. +// +// -------------------------------------------------------------------------------------------------------------------- +namespace OxyPlot +{ + public class Pen + { + public Pen(Color c, double th, LineStyle ls) + { + Color = c; + Thickness = th; + DashArray = LineStyleHelper.GetDashArray(ls); + } + + public Color Color { get; set; } + public double Thickness { get; set; } + public double[] DashArray { get; set; } + } +} \ No newline at end of file diff -r 88d699a65cc2 -r 5be8f2773237 External/OxyPlot/OxyPlot/Foundation/PlotLength.cs --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/External/OxyPlot/OxyPlot/Foundation/PlotLength.cs Sat Jun 08 16:53:22 2013 +0000 @@ -0,0 +1,91 @@ +// -------------------------------------------------------------------------------------------------------------------- +// +// The MIT License (MIT) +// +// Copyright (c) 2012 Oystein Bjorke +// +// Permission is hereby granted, free of charge, to any person obtaining a +// copy of this software and associated documentation files (the +// "Software"), to deal in the Software without restriction, including +// without limitation the rights to use, copy, modify, merge, publish, +// distribute, sublicense, and/or sell copies of the Software, and to +// permit persons to whom the Software is furnished to do so, subject to +// the following conditions: +// +// The above copyright notice and this permission notice shall be included +// in all copies or substantial portions of the Software. +// +// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS +// OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF +// MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. +// IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY +// CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, +// TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE +// SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. +// +// +// Represents lengths in the plot. +// +// -------------------------------------------------------------------------------------------------------------------- + +namespace OxyPlot +{ + /// + /// Represents lengths in the plot. + /// + public struct PlotLength + { + /// + /// The unit type + /// + private readonly PlotLengthUnit unit; + + /// + /// The value + /// + private readonly double value; + + /// + /// Initializes a new instance of the struct. + /// + /// + /// The value. + /// + /// + /// The unit. + /// + public PlotLength(double value, PlotLengthUnit unit) + { + this.value = value; + this.unit = unit; + } + + /// + /// Gets the value. + /// + /// + /// The value. + /// + public double Value + { + get + { + return this.value; + } + } + + /// + /// Gets the type of the unit. + /// + /// + /// The type of the unit. + /// + public PlotLengthUnit Unit + { + get + { + return this.unit; + } + } + } +} \ No newline at end of file diff -r 88d699a65cc2 -r 5be8f2773237 External/OxyPlot/OxyPlot/Foundation/PlotLengthUnit.cs --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/External/OxyPlot/OxyPlot/Foundation/PlotLengthUnit.cs Sat Jun 08 16:53:22 2013 +0000 @@ -0,0 +1,58 @@ +// -------------------------------------------------------------------------------------------------------------------- +// +// The MIT License (MIT) +// +// Copyright (c) 2012 Oystein Bjorke +// +// Permission is hereby granted, free of charge, to any person obtaining a +// copy of this software and associated documentation files (the +// "Software"), to deal in the Software without restriction, including +// without limitation the rights to use, copy, modify, merge, publish, +// distribute, sublicense, and/or sell copies of the Software, and to +// permit persons to whom the Software is furnished to do so, subject to +// the following conditions: +// +// The above copyright notice and this permission notice shall be included +// in all copies or substantial portions of the Software. +// +// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS +// OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF +// MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. +// IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY +// CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, +// TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE +// SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. +// +// +// Describes the kind of value that a object is holding. +// +// -------------------------------------------------------------------------------------------------------------------- + +namespace OxyPlot +{ + /// + /// Describes the kind of value that a object is holding. + /// + public enum PlotLengthUnit + { + /// + /// The value is in data space (transformed by x/y axis) + /// + Data = 0, + + /// + /// The value is in screen units + /// + ScreenUnits = 1, + + /// + /// The value is relative to the plot viewport (0-1) + /// + RelativeToViewport = 2, + + /// + /// The value is relative to the plot area (0-1) + /// + RelativeToPlotArea = 3 + } +} \ No newline at end of file diff -r 88d699a65cc2 -r 5be8f2773237 External/OxyPlot/OxyPlot/Foundation/PngEncoder.cs --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/External/OxyPlot/OxyPlot/Foundation/PngEncoder.cs Sat Jun 08 16:53:22 2013 +0000 @@ -0,0 +1,323 @@ +// -------------------------------------------------------------------------------------------------------------------- +// +// The MIT License (MIT) +// +// Copyright (c) 2012 Oystein Bjorke +// +// Permission is hereby granted, free of charge, to any person obtaining a +// copy of this software and associated documentation files (the +// "Software"), to deal in the Software without restriction, including +// without limitation the rights to use, copy, modify, merge, publish, +// distribute, sublicense, and/or sell copies of the Software, and to +// permit persons to whom the Software is furnished to do so, subject to +// the following conditions: +// +// The above copyright notice and this permission notice shall be included +// in all copies or substantial portions of the Software. +// +// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS +// OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF +// MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. +// IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY +// CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, +// TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE +// SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. +// +// -------------------------------------------------------------------------------------------------------------------- + +namespace OxyPlot +{ + using System; + using System.Collections.Generic; + using System.IO; + using System.Linq; + + /// + /// Provides encoding of uncompressed png images. + /// + public class PngEncoder + { + /// + /// The CRC table + /// + private static readonly ulong[] CrcTable; + + /// + /// Initializes static members of the class. + /// + static PngEncoder() + { + CrcTable = new ulong[256]; + for (int n = 0; n < 256; n++) + { + var c = (ulong)n; + for (int k = 0; k < 8; k++) + { + if ((c & 1) != 0) + { + c = 0xedb88320L ^ (c >> 1); + } + else + { + c = c >> 1; + } + } + + CrcTable[n] = c; + } + } + + /// + /// Encodes the specified image data to png. + /// + /// + /// The pixel data (bottom line first). + /// + /// + /// The image resolution in dots per inch. + /// + /// + /// The png image data. + /// + public static byte[] Encode(OxyColor[,] pixels, int dpi = 96) + { + int height = pixels.GetLength(0); + int width = pixels.GetLength(1); + var bytes = new byte[(width * height * 4) + height]; + + int k = 0; + for (int i = height - 1; i >= 0; i--) + { + bytes[k++] = 0; // Filter + for (int j = 0; j < width; j++) + { + bytes[k++] = pixels[i, j].R; + bytes[k++] = pixels[i, j].G; + bytes[k++] = pixels[i, j].B; + bytes[k++] = pixels[i, j].A; + } + } + + var w = new MemoryWriter(); + w.Write((byte)0x89); + w.Write("PNG\r\n\x1a\n".ToCharArray()); + WriteChunk(w, "IHDR", CreateHeaderData(width, height)); + WriteChunk(w, "pHYs", CreatePhysicalDimensionsData(dpi, dpi)); + WriteChunk(w, "IDAT", CreateUncompressedBlocks(bytes)); + WriteChunk(w, "IEND", new byte[0]); + return w.ToArray(); + } + + /// + /// Calculates the Adler-32 check sum. + /// + /// + /// The data. + /// + /// + /// The check sum. + /// + private static uint Adler32(IEnumerable data) + { + // http://en.wikipedia.org/wiki/Adler-32 + uint a = 1; + uint b = 0; + const uint ModAdler = 65521; + foreach (var x in data) + { + a = (a + x) % ModAdler; + b = (b + a) % ModAdler; + } + + return (b << 16) | a; + } + + /// + /// Creates the header data. + /// + /// + /// The width. + /// + /// + /// The height. + /// + /// + /// The header. + /// + private static byte[] CreateHeaderData(int width, int height) + { + // http://www.w3.org/TR/PNG-Chunks.html + var w = new MemoryWriter(); + WriteBigEndian(w, width); + WriteBigEndian(w, height); + w.Write((byte)8); // bit depth + w.Write((byte)6); // color type RGBA + w.Write((byte)0); // compression method + w.Write((byte)0); // filter method + w.Write((byte)0); // interlace method + return w.ToArray(); + } + + /// + /// Creates the physical dimensions data. + /// + /// + /// The horizontal resolution. + /// + /// + /// The vertical resolution. + /// + /// + /// The data. + /// + private static byte[] CreatePhysicalDimensionsData(int dpix, int dpiy) + { + var ppux = (int)(dpix / 0.0254); + var ppuy = (int)(dpiy / 0.0254); + var w = new MemoryWriter(); + WriteBigEndian(w, ppux); + WriteBigEndian(w, ppuy); + w.Write((byte)1); // Unit: metre + return w.ToArray(); + } + + /// + /// Creates the uncompressed blocks. + /// + /// + /// The data. + /// + /// + /// The output data. + /// + private static byte[] CreateUncompressedBlocks(byte[] bytes) + { + // http://www.w3.org/TR/PNG-Compression.html + const int MaxDeflate = 0xFFFF; + var w = new MemoryWriter(); + const uint CompressionMethod = 8; + const uint Check = (31 - ((CompressionMethod << 8) % 31)) % 31; + w.Write((byte)CompressionMethod); + w.Write((byte)Check); + for (int i = 0; i < bytes.Length; i += MaxDeflate) + { + var n = (ushort)Math.Min(bytes.Length - i, MaxDeflate); + var last = (byte)(i + n < bytes.Length ? 0 : 1); + w.Write(last); + w.Write((byte)(n & 0xFF)); + w.Write((byte)((n >> 8) & 0xFF)); + var n2 = ~n; + w.Write((byte)(n2 & 0xFF)); + w.Write((byte)((n2 >> 8) & 0xFF)); + w.Write(bytes, i, n); + } + + WriteBigEndian(w, Adler32(bytes)); + return w.ToArray(); + } + + /// + /// Updates the CRC check sum. + /// + /// + /// The input CRC. + /// + /// + /// The data. + /// + /// + /// The updated CRC. + /// + private static ulong UpdateCrc(ulong crc, IEnumerable data) + { + return data.Aggregate(crc, (current, x) => CrcTable[(current ^ x) & 0xff] ^ (current >> 8)); + } + + /// + /// Writes the integer value with big endian byte order. + /// + /// + /// The writer. + /// + /// + /// The value. + /// + private static void WriteBigEndian(BinaryWriter w, int value) + { + var bytes = BitConverter.GetBytes(value); + w.Write(bytes[3]); + w.Write(bytes[2]); + w.Write(bytes[1]); + w.Write(bytes[0]); + } + + /// + /// Writes the unsigned integer value with big endian byte order. + /// + /// + /// The writer. + /// + /// + /// The value. + /// + private static void WriteBigEndian(BinaryWriter w, uint value) + { + var bytes = BitConverter.GetBytes(value); + w.Write(bytes[3]); + w.Write(bytes[2]); + w.Write(bytes[1]); + w.Write(bytes[0]); + } + + /// + /// Writes a png chunk. + /// + /// + /// The writer. + /// + /// + /// The chunk type. + /// + /// + /// The chunk data. + /// + private static void WriteChunk(BinaryWriter w, string type, byte[] data) + { + var ty = type.ToCharArray().Select(ch => (byte)ch).ToArray(); + WriteBigEndian(w, data.Length); + w.Write(ty); + w.Write(data); + + var c = 0xffffffff; + c = (uint)UpdateCrc(c, ty); + c = (uint)UpdateCrc(c, data); + var crc = c ^ 0xffffffff; + + WriteBigEndian(w, crc); + } + + /// + /// Provides a binary writer that writes to memory. + /// + private class MemoryWriter : BinaryWriter + { + /// + /// Initializes a new instance of the class. + /// + public MemoryWriter() + : base(new MemoryStream()) + { + } + + /// + /// Gets the content as a byte array. + /// + /// The byte array. + public byte[] ToArray() + { + this.BaseStream.Flush(); + return ((MemoryStream)this.BaseStream).ToArray(); + } + } + } +} \ No newline at end of file diff -r 88d699a65cc2 -r 5be8f2773237 External/OxyPlot/OxyPlot/Foundation/Point.cs --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/External/OxyPlot/OxyPlot/Foundation/Point.cs Sat Jun 08 16:53:22 2013 +0000 @@ -0,0 +1,58 @@ +// -------------------------------------------------------------------------------------------------------------------- +// +// The MIT License (MIT) +// +// Copyright (c) 2012 Oystein Bjorke +// +// Permission is hereby granted, free of charge, to any person obtaining a +// copy of this software and associated documentation files (the +// "Software"), to deal in the Software without restriction, including +// without limitation the rights to use, copy, modify, merge, publish, +// distribute, sublicense, and/or sell copies of the Software, and to +// permit persons to whom the Software is furnished to do so, subject to +// the following conditions: +// +// The above copyright notice and this permission notice shall be included +// in all copies or substantial portions of the Software. +// +// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS +// OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF +// MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. +// IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY +// CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, +// TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE +// SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. +// +// -------------------------------------------------------------------------------------------------------------------- +namespace OxyPlot +{ + public struct Point + { + internal double x; + + internal double y; + + public Point(double x, double y) + { + this.x = x; + this.y = y; + } + + public double X + { + get { return x; } + set { x = value; } + } + + public double Y + { + get { return y; } + set { y = value; } + } + + public override string ToString() + { + return x + " " + y; + } + } +} \ No newline at end of file diff -r 88d699a65cc2 -r 5be8f2773237 External/OxyPlot/OxyPlot/Foundation/Rectangle.cs --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/External/OxyPlot/OxyPlot/Foundation/Rectangle.cs Sat Jun 08 16:53:22 2013 +0000 @@ -0,0 +1,36 @@ +// -------------------------------------------------------------------------------------------------------------------- +// +// The MIT License (MIT) +// +// Copyright (c) 2012 Oystein Bjorke +// +// Permission is hereby granted, free of charge, to any person obtaining a +// copy of this software and associated documentation files (the +// "Software"), to deal in the Software without restriction, including +// without limitation the rights to use, copy, modify, merge, publish, +// distribute, sublicense, and/or sell copies of the Software, and to +// permit persons to whom the Software is furnished to do so, subject to +// the following conditions: +// +// The above copyright notice and this permission notice shall be included +// in all copies or substantial portions of the Software. +// +// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS +// OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF +// MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. +// IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY +// CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, +// TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE +// SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. +// +// -------------------------------------------------------------------------------------------------------------------- +namespace OxyPlot +{ + public struct Rectangle + { + public double Top { get; set; } + public double Bottom { get; set; } + public double Left { get; set; } + public double Right { get; set; } + } +} \ No newline at end of file diff -r 88d699a65cc2 -r 5be8f2773237 External/OxyPlot/OxyPlot/Foundation/ReflectionHelper.cs --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/External/OxyPlot/OxyPlot/Foundation/ReflectionHelper.cs Sat Jun 08 16:53:22 2013 +0000 @@ -0,0 +1,81 @@ +// -------------------------------------------------------------------------------------------------------------------- +// +// The MIT License (MIT) +// +// Copyright (c) 2012 Oystein Bjorke +// +// Permission is hereby granted, free of charge, to any person obtaining a +// copy of this software and associated documentation files (the +// "Software"), to deal in the Software without restriction, including +// without limitation the rights to use, copy, modify, merge, publish, +// distribute, sublicense, and/or sell copies of the Software, and to +// permit persons to whom the Software is furnished to do so, subject to +// the following conditions: +// +// The above copyright notice and this permission notice shall be included +// in all copies or substantial portions of the Software. +// +// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS +// OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF +// MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. +// IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY +// CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, +// TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE +// SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. +// +// +// Provides reflection based support methods. +// +// -------------------------------------------------------------------------------------------------------------------- +namespace OxyPlot +{ + using System; + using System.Collections; + using System.Collections.Generic; + using System.Globalization; + using System.Reflection; + + /// + /// Provides utility methods reflection based support methods. + /// + public static class ReflectionHelper + { + /// + /// Fills a list by the specified property of a source list/enumerable. + /// + /// + /// The source list. + /// + /// + /// The property name. + /// + /// + /// The list to be filled. + /// + /// + /// The type of the destination list items (and the source property). + /// + public static void FillList(IEnumerable source, string propertyName, IList list) + { + PropertyInfo pi = null; + Type t = null; + foreach (var o in source) + { + if (pi == null || o.GetType() != t) + { + t = o.GetType(); + pi = t.GetProperty(propertyName); + if (pi == null) + { + throw new InvalidOperationException( + string.Format("Could not find field {0} on type {1}", propertyName, t)); + } + } + + var v = pi.GetValue(o, null); + var value = (T)Convert.ChangeType(v, typeof(T), CultureInfo.InvariantCulture); + list.Add(value); + } + } + } +} \ No newline at end of file diff -r 88d699a65cc2 -r 5be8f2773237 External/OxyPlot/OxyPlot/Foundation/ScreenPoint.cs --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/External/OxyPlot/OxyPlot/Foundation/ScreenPoint.cs Sat Jun 08 16:53:22 2013 +0000 @@ -0,0 +1,198 @@ +// -------------------------------------------------------------------------------------------------------------------- +// +// The MIT License (MIT) +// +// Copyright (c) 2012 Oystein Bjorke +// +// Permission is hereby granted, free of charge, to any person obtaining a +// copy of this software and associated documentation files (the +// "Software"), to deal in the Software without restriction, including +// without limitation the rights to use, copy, modify, merge, publish, +// distribute, sublicense, and/or sell copies of the Software, and to +// permit persons to whom the Software is furnished to do so, subject to +// the following conditions: +// +// The above copyright notice and this permission notice shall be included +// in all copies or substantial portions of the Software. +// +// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS +// OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF +// MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. +// IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY +// CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, +// TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE +// SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. +// +// +// Describes a point defined in the screen coordinate system. +// +// -------------------------------------------------------------------------------------------------------------------- +namespace OxyPlot +{ + using System; + + /// + /// Represents a point defined in the screen coordinate system. + /// + /// + /// The rendering methods transforms s to s. + /// + public struct ScreenPoint + { + /// + /// The undefined point. + /// + public static readonly ScreenPoint Undefined = new ScreenPoint(double.NaN, double.NaN); + + /// + /// The x-coordinate. + /// + internal double x; + + /// + /// The y-coordinate. + /// + internal double y; + + /// + /// Initializes a new instance of the struct. + /// + /// + /// The x-coordinate. + /// + /// + /// The y-coordinate. + /// + public ScreenPoint(double x, double y) + { + this.x = x; + this.y = y; + } + + /// + /// Gets or sets the x-coordinate. + /// + /// The x-coordinate. + public double X + { + get + { + return this.x; + } + + set + { + this.x = value; + } + } + + /// + /// Gets or sets the y-coordinate. + /// + /// The y-coordinate. + public double Y + { + get + { + return this.y; + } + + set + { + this.y = value; + } + } + + /// + /// Determines whether the specified point is undefined. + /// + /// + /// The point. + /// + /// + /// true if the specified point is undefined; otherwise, false . + /// + public static bool IsUndefined(ScreenPoint point) + { + return double.IsNaN(point.X) && double.IsNaN(point.Y); + } + + /// + /// Gets the distance to the specified point. + /// + /// + /// The point. + /// + /// + /// The distance. + /// + public double DistanceTo(ScreenPoint point) + { + double dx = point.x - this.x; + double dy = point.y - this.y; + return Math.Sqrt((dx * dx) + (dy * dy)); + } + + /// + /// Gets the squared distance to the specified point. + /// + /// + /// The point. + /// + /// + /// The squared distance. + /// + public double DistanceToSquared(ScreenPoint point) + { + double dx = point.x - this.x; + double dy = point.y - this.y; + return (dx * dx) + (dy * dy); + } + + /// + /// Returns a that represents this instance. + /// + /// + /// A that represents this instance. + /// + public override string ToString() + { + return this.x + " " + this.y; + } + + /// + /// Translates a by a . + /// + /// The point. + /// The vector. + /// The translated point. + public static ScreenPoint operator +(ScreenPoint p1, ScreenVector p2) + { + return new ScreenPoint(p1.x + p2.x, p1.y + p2.y); + } + + /// + /// Subtracts a from a + /// and returns the result as a . + /// + /// The point on which to perform the subtraction. + /// The point to subtract from p1. + /// A structure that represents the difference between p1 and p2. + public static ScreenVector operator -(ScreenPoint p1, ScreenPoint p2) + { + return new ScreenVector(p1.x - p2.x, p1.y - p2.y); + } + + /// + /// Subtracts a from a + /// and returns the result as a . + /// + /// The point on which to perform the subtraction. + /// The vector to subtract from p1. + /// A that represents point translated by the negative vector. + public static ScreenPoint operator -(ScreenPoint point, ScreenVector vector) + { + return new ScreenPoint(point.x - vector.x, point.y - vector.y); + } + } +} \ No newline at end of file diff -r 88d699a65cc2 -r 5be8f2773237 External/OxyPlot/OxyPlot/Foundation/ScreenPointHelper.cs --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/External/OxyPlot/OxyPlot/Foundation/ScreenPointHelper.cs Sat Jun 08 16:53:22 2013 +0000 @@ -0,0 +1,255 @@ +// -------------------------------------------------------------------------------------------------------------------- +// +// The MIT License (MIT) +// +// Copyright (c) 2012 Oystein Bjorke +// +// Permission is hereby granted, free of charge, to any person obtaining a +// copy of this software and associated documentation files (the +// "Software"), to deal in the Software without restriction, including +// without limitation the rights to use, copy, modify, merge, publish, +// distribute, sublicense, and/or sell copies of the Software, and to +// permit persons to whom the Software is furnished to do so, subject to +// the following conditions: +// +// The above copyright notice and this permission notice shall be included +// in all copies or substantial portions of the Software. +// +// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS +// OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF +// MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. +// IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY +// CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, +// TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE +// SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. +// +// +// Provides various algorithms for polygons and lines of ScreenPoint. +// +// -------------------------------------------------------------------------------------------------------------------- +namespace OxyPlot +{ + using System.Collections.Generic; + + /// + /// Provides algorithms for polygons and lines of . + /// + public static class ScreenPointHelper + { + /// + /// Finds the nearest point on the specified polyline. + /// + /// + /// The point. + /// + /// + /// The points. + /// + /// + /// The nearest point. + /// + public static ScreenPoint FindNearestPointOnPolyline(ScreenPoint point, IList points) + { + double minimumDistance = double.MaxValue; + var nearestPoint = default(ScreenPoint); + + for (int i = 0; i + 1 < points.Count; i++) + { + var p1 = points[i]; + var p2 = points[i + 1]; + if (ScreenPoint.IsUndefined(p1) || ScreenPoint.IsUndefined(p2)) + { + continue; + } + + // Find the nearest point on the line segment. + var nearestPointOnSegment = FindPointOnLine(point, p1, p2); + + if (ScreenPoint.IsUndefined(nearestPointOnSegment)) + { + continue; + } + + double l2 = (point - nearestPointOnSegment).LengthSquared; + + if (l2 < minimumDistance) + { + nearestPoint = nearestPointOnSegment; + minimumDistance = l2; + } + } + + return nearestPoint; + } + + /// + /// Finds the point on line. + /// + /// + /// The point. + /// + /// + /// The first point on the line. + /// + /// + /// The second point on the line. + /// + /// + /// The nearest point on the line. + /// + /// + /// See Bourke. + /// + public static ScreenPoint FindPointOnLine(ScreenPoint p, ScreenPoint p1, ScreenPoint p2) + { + double dx = p2.x - p1.x; + double dy = p2.y - p1.y; + double u = FindPositionOnLine(p, p1, p2); + + if (double.IsNaN(u)) + { + u = 0; + } + + if (u < 0) + { + u = 0; + } + + if (u > 1) + { + u = 1; + } + + return new ScreenPoint(p1.x + (u * dx), p1.y + (u * dy)); + } + + /// + /// Finds the nearest point on line. + /// + /// + /// The point. + /// + /// + /// The start point on the line. + /// + /// + /// The end point on the line. + /// + /// + /// The relative position of the nearest point. + /// + /// + /// See Bourke. + /// + public static double FindPositionOnLine(ScreenPoint p, ScreenPoint p1, ScreenPoint p2) + { + double dx = p2.x - p1.x; + double dy = p2.y - p1.y; + double u1 = ((p.x - p1.x) * dx) + ((p.y - p1.y) * dy); + double u2 = (dx * dx) + (dy * dy); + + if (u2 < 1e-6) + { + return double.NaN; + } + + return u1 / u2; + } + + /// + /// Determines whether the specified point is in the specified polygon. + /// + /// + /// The point. + /// + /// + /// The polygon points. + /// + /// + /// true if the point is in the polygon; otherwise, false. + /// + public static bool IsPointInPolygon(ScreenPoint p, IList pts) + { + int nvert = pts.Count; + bool c = false; + for (int i = 0, j = nvert - 1; i < nvert; j = i++) + { + if (((pts[i].Y > p.Y) != (pts[j].Y > p.Y)) + && (p.X < ((pts[j].X - pts[i].X) * ((p.Y - pts[i].Y) / (pts[j].Y - pts[i].Y))) + pts[i].X)) + { + c = !c; + } + } + + return c; + } + + /// + /// Resamples the points with the specified point distance limit. + /// + /// + /// All points. + /// + /// + /// The minimum squared distance. + /// + /// + /// List of resampled points. + /// + public static IList ResamplePoints(IList allPoints, double minimumDistance) + { + double minimumSquaredDistance = minimumDistance * minimumDistance; + int n = allPoints.Count; + var result = new List(n); + if (n > 0) + { + result.Add(allPoints[0]); + int i0 = 0; + for (int i = 1; i < n; i++) + { + double distSquared = allPoints[i0].DistanceToSquared(allPoints[i]); + if (distSquared < minimumSquaredDistance && i != n - 1) + { + continue; + } + + i0 = i; + result.Add(allPoints[i]); + } + } + + return result; + } + + /// + /// Gets the centroid of the specified polygon. + /// + /// + /// The points. + /// + /// + /// The centroid. + /// + public static ScreenPoint GetCentroid(IList points) + { + double cx = 0; + double cy = 0; + double a = 0; + + for (int i = 0; i < points.Count; i++) + { + int i1 = (i + 1) % points.Count; + double da = (points[i].x * points[i1].y) - (points[i1].x * points[i].y); + cx += (points[i].x + points[i1].x) * da; + cy += (points[i].y + points[i1].y) * da; + a += da; + } + + a *= 0.5; + cx /= 6 * a; + cy /= 6 * a; + return new ScreenPoint(cx, cy); + } + } +} \ No newline at end of file diff -r 88d699a65cc2 -r 5be8f2773237 External/OxyPlot/OxyPlot/Foundation/ScreenVector.cs --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/External/OxyPlot/OxyPlot/Foundation/ScreenVector.cs Sat Jun 08 16:53:22 2013 +0000 @@ -0,0 +1,155 @@ +// -------------------------------------------------------------------------------------------------------------------- +// +// The MIT License (MIT) +// +// Copyright (c) 2012 Oystein Bjorke +// +// Permission is hereby granted, free of charge, to any person obtaining a +// copy of this software and associated documentation files (the +// "Software"), to deal in the Software without restriction, including +// without limitation the rights to use, copy, modify, merge, publish, +// distribute, sublicense, and/or sell copies of the Software, and to +// permit persons to whom the Software is furnished to do so, subject to +// the following conditions: +// +// The above copyright notice and this permission notice shall be included +// in all copies or substantial portions of the Software. +// +// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS +// OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF +// MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. +// IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY +// CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, +// TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE +// SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. +// +// +// Represents a vector defined in the screen coordinate system. +// +// -------------------------------------------------------------------------------------------------------------------- +namespace OxyPlot +{ + using System; + + /// + /// Represents a vector defined in the screen coordinate system. + /// + public struct ScreenVector + { + /// + /// The x-coordinate. + /// + internal double x; + + /// + /// The y-coordinate. + /// + internal double y; + + /// + /// Initializes a new instance of the structure. + /// + /// + /// The x-coordinate. + /// + /// + /// The y-coordinate. + /// + public ScreenVector(double x, double y) + { + this.x = x; + this.y = y; + } + + /// + /// Gets the length. + /// + public double Length + { + get + { + return Math.Sqrt((this.x * this.x) + (this.y * this.y)); + } + } + + /// + /// Gets the length squared. + /// + public double LengthSquared + { + get + { + return (this.x * this.x) + (this.y * this.y); + } + } + + /// + /// Gets or sets the x-coordinate. + /// + /// The x-coordinate. + public double X + { + get + { + return this.x; + } + + set + { + this.x = value; + } + } + + /// + /// Gets or sets the y-coordinate. + /// + /// The y-coordinate. + public double Y + { + get + { + return this.y; + } + + set + { + this.y = value; + } + } + + /// + /// Normalizes this vector. + /// + public void Normalize() + { + double l = Math.Sqrt((this.x * this.x) + (this.y * this.y)); + if (l > 0) + { + this.x /= l; + this.y /= l; + } + } + + /// + /// Returns a that represents this instance. + /// + /// + /// A that represents this instance. + /// + public override string ToString() + { + return this.x + " " + this.y; + } + + /// + /// Implements the operator *. + /// + /// The vector. + /// The multiplication factor. + /// The result of the operator. + public static ScreenVector operator *(ScreenVector v, double d) + { + return new ScreenVector(v.x * d, v.y * d); + } + } +} \ No newline at end of file diff -r 88d699a65cc2 -r 5be8f2773237 External/OxyPlot/OxyPlot/Foundation/Size.cs --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/External/OxyPlot/OxyPlot/Foundation/Size.cs Sat Jun 08 16:53:22 2013 +0000 @@ -0,0 +1,43 @@ +// -------------------------------------------------------------------------------------------------------------------- +// +// The MIT License (MIT) +// +// Copyright (c) 2012 Oystein Bjorke +// +// Permission is hereby granted, free of charge, to any person obtaining a +// copy of this software and associated documentation files (the +// "Software"), to deal in the Software without restriction, including +// without limitation the rights to use, copy, modify, merge, publish, +// distribute, sublicense, and/or sell copies of the Software, and to +// permit persons to whom the Software is furnished to do so, subject to +// the following conditions: +// +// The above copyright notice and this permission notice shall be included +// in all copies or substantial portions of the Software. +// +// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS +// OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF +// MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. +// IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY +// CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, +// TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE +// SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. +// +// -------------------------------------------------------------------------------------------------------------------- +namespace OxyPlot +{ + public struct Size + { + public double Width { get; set; } + public double Height { get; set; } + + public static Size Empty = new Size(0,0); + + public Size(double width, double height) + : this() + { + this.Width = width; + this.Height = height; + } + } +} \ No newline at end of file diff -r 88d699a65cc2 -r 5be8f2773237 External/OxyPlot/OxyPlot/Foundation/StreamExtensions.cs --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/External/OxyPlot/OxyPlot/Foundation/StreamExtensions.cs Sat Jun 08 16:53:22 2013 +0000 @@ -0,0 +1,25 @@ +namespace OxyPlot +{ + using System.IO; + + /// + /// Implements extension methods. + /// + public static class StreamExtensions + { + /// + /// Copies to the specified stream. + /// + /// The input stream. + /// The output stream. + public static void CopyTo(this Stream input, Stream output) + { + var buffer = new byte[32768]; + int read; + while ((read = input.Read(buffer, 0, buffer.Length)) > 0) + { + output.Write(buffer, 0, read); + } + } + } +} \ No newline at end of file diff -r 88d699a65cc2 -r 5be8f2773237 External/OxyPlot/OxyPlot/Foundation/StringHelper.cs --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/External/OxyPlot/OxyPlot/Foundation/StringHelper.cs Sat Jun 08 16:53:22 2013 +0000 @@ -0,0 +1,169 @@ +// -------------------------------------------------------------------------------------------------------------------- +// +// The MIT License (MIT) +// +// Copyright (c) 2012 Oystein Bjorke +// +// Permission is hereby granted, free of charge, to any person obtaining a +// copy of this software and associated documentation files (the +// "Software"), to deal in the Software without restriction, including +// without limitation the rights to use, copy, modify, merge, publish, +// distribute, sublicense, and/or sell copies of the Software, and to +// permit persons to whom the Software is furnished to do so, subject to +// the following conditions: +// +// The above copyright notice and this permission notice shall be included +// in all copies or substantial portions of the Software. +// +// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS +// OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF +// MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. +// IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY +// CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, +// TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE +// SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. +// +// +// Provides support for string formatting. +// +// -------------------------------------------------------------------------------------------------------------------- +namespace OxyPlot +{ + using System; + using System.Collections; + using System.Text; + using System.Text.RegularExpressions; + + /// + /// Provides extended string formatting functionality. + /// + public static class StringHelper + { + /// + /// The formatting expression. + /// + private static readonly Regex FormattingExpression = new Regex("{(?.+?)(?\\:.*?)?}"); + + /// + /// Replaces the format items in the specified string. + /// + /// + /// The culture specific format provider. + /// + /// + /// The format string. + /// + /// + /// The item. + /// + /// + /// The values. + /// + /// + /// The formatString and values works as in string.Format. In addition, you can format properties of the item object by using the syntax {PropertyName:Formatstring}. E.g. if you have a "Value" property in your item's class, use "{Value:0.00}" to output the value with two digits. Note that this formatting is using reflection and does not have the same performance as string.Format. + /// + /// + /// The formatted string. + /// + public static string Format(IFormatProvider provider, string formatString, object item, params object[] values) + { + // Replace items on the format {Property[:Formatstring]} + var s = FormattingExpression.Replace( + formatString, + delegate(Match match) + { + var property = match.Groups["Property"].Value; + if (property.Length > 0 && char.IsDigit(property[0])) + { + return match.Value; + } + + var pi = item.GetType().GetProperty(property); + if (pi == null) + { + return string.Empty; + } + + var v = pi.GetValue(item, null); + var format = match.Groups["Format"].Value; + + var fs = "{0" + format + "}"; + return string.Format(provider, fs, v); + }); + + // Also apply the standard formatting + s = string.Format(provider, s, values); + return s; + } + + /// + /// Creates a valid file name. + /// + /// + /// The title. + /// + /// + /// The extension. + /// + /// + /// A file name. + /// + public static string CreateValidFileName(string title, string extension) + { + string validFileName = title.Trim(); + var invalidFileNameChars = "/?<>\\:*|\0\t\r\n".ToCharArray(); + foreach (char invalChar in invalidFileNameChars) + { + validFileName = validFileName.Replace(invalChar.ToString(), string.Empty); + } + + foreach (char invalChar in invalidFileNameChars) + { + validFileName = validFileName.Replace(invalChar.ToString(), string.Empty); + } + + if (validFileName.Length > 160) + { + // safe value threshold is 260 + validFileName = validFileName.Remove(156) + "..."; + } + + return validFileName + extension; + } + + /// + /// Creates a string from a collection of items. + /// + /// + /// The provider. + /// + /// + /// The items. + /// + /// + /// The format string to apply to each item. + /// + /// + /// The separator. + /// + /// + /// The collection as a string. + /// + public static object CreateList( + IFormatProvider provider, IEnumerable items, string formatstring, string separator = ", ") + { + var sb = new StringBuilder(); + foreach (var item in items) + { + if (sb.Length > 0) + { + sb.Append(separator); + } + + sb.Append(string.Format(provider, formatstring, item)); + } + + return sb.ToString(); + } + } +} \ No newline at end of file diff -r 88d699a65cc2 -r 5be8f2773237 External/OxyPlot/OxyPlot/Foundation/SutherlandHodgmanClipping.cs --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/External/OxyPlot/OxyPlot/Foundation/SutherlandHodgmanClipping.cs Sat Jun 08 16:53:22 2013 +0000 @@ -0,0 +1,233 @@ +// -------------------------------------------------------------------------------------------------------------------- +// +// The MIT License (MIT) +// +// Copyright (c) 2012 Oystein Bjorke +// +// Permission is hereby granted, free of charge, to any person obtaining a +// copy of this software and associated documentation files (the +// "Software"), to deal in the Software without restriction, including +// without limitation the rights to use, copy, modify, merge, publish, +// distribute, sublicense, and/or sell copies of the Software, and to +// permit persons to whom the Software is furnished to do so, subject to +// the following conditions: +// +// The above copyright notice and this permission notice shall be included +// in all copies or substantial portions of the Software. +// +// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS +// OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF +// MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. +// IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY +// CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, +// TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE +// SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. +// +// +// Polygon clipping by the sutherland-hodgman algortihm. +// +// -------------------------------------------------------------------------------------------------------------------- +namespace OxyPlot +{ + using System; + using System.Collections.Generic; + + /// + /// Provides polygon clipping by the Sutherland-Hodgman algortihm. + /// + public static class SutherlandHodgmanClipping + { + /// + /// The rectangle edge. + /// + private enum RectangleEdge + { + /// + /// The left. + /// + Left, + + /// + /// The right. + /// + Right, + + /// + /// The top. + /// + Top, + + /// + /// The bottom. + /// + Bottom + } + + /// + /// The Sutherland-Hodgman polygon clipping algorithm. + /// + /// + /// See http://ezekiel.vancouver.wsu.edu/~cs442/lectures/clip/clip/index.html + /// + /// + /// The bounds. + /// + /// + /// The polygon points. + /// + /// + /// The clipped points. + /// + public static List ClipPolygon(OxyRect bounds, IList v) + { + List p1 = ClipOneAxis(bounds, RectangleEdge.Left, v); + List p2 = ClipOneAxis(bounds, RectangleEdge.Right, p1); + List p3 = ClipOneAxis(bounds, RectangleEdge.Top, p2); + return ClipOneAxis(bounds, RectangleEdge.Bottom, p3); + } + + /// + /// Clips to one axis. + /// + /// + /// The bounds. + /// + /// + /// The edge. + /// + /// + /// The points of the polygon. + /// + /// + /// The clipped points. + /// + private static List ClipOneAxis(OxyRect bounds, RectangleEdge edge, IList v) + { + if (v.Count == 0) + { + return new List(); + } + + var polygon = new List(v.Count); + + var s = v[v.Count - 1]; + + for (int i = 0; i < v.Count; ++i) + { + var p = v[i]; + bool pin = IsInside(bounds, edge, p); + bool sin = IsInside(bounds, edge, s); + + if (sin && pin) + { + // case 1: inside -> inside + polygon.Add(p); + } + else if (sin) + { + // case 2: inside -> outside + polygon.Add(LineIntercept(bounds, edge, s, p)); + } + else if (!pin) + { + // case 3: outside -> outside + // emit nothing + } + else + { + // case 4: outside -> inside + polygon.Add(LineIntercept(bounds, edge, s, p)); + polygon.Add(p); + } + + s = p; + } + + return polygon; + } + + /// + /// Determines whether the specified point is inside the edge/bounds. + /// + /// The bounds. + /// The edge to test. + /// The point. + /// + /// true if the specified point is inside; otherwise, false. + /// + private static bool IsInside(OxyRect bounds, RectangleEdge edge, ScreenPoint p) + { + switch (edge) + { + case RectangleEdge.Left: + return !(p.X < bounds.Left); + + case RectangleEdge.Right: + return !(p.X >= bounds.Right); + + case RectangleEdge.Top: + return !(p.Y < bounds.Top); + + case RectangleEdge.Bottom: + return !(p.Y >= bounds.Bottom); + + default: + throw new ArgumentException("edge"); + } + } + + /// + /// Fines the edge interception. + /// + /// The bounds. + /// The edge. + /// The first point. + /// The second point. + /// The interception. + private static ScreenPoint LineIntercept(OxyRect bounds, RectangleEdge edge, ScreenPoint a, ScreenPoint b) + { + if (a.x == b.x && a.y == b.y) + { + return a; + } + + switch (edge) + { + case RectangleEdge.Bottom: + if (b.Y == a.Y) + { + throw new ArgumentException("no intercept found"); + } + + return new ScreenPoint(a.X + (((b.X - a.X) * (bounds.Bottom - a.Y)) / (b.Y - a.Y)), bounds.Bottom); + + case RectangleEdge.Left: + if (b.X == a.X) + { + throw new ArgumentException("no intercept found"); + } + + return new ScreenPoint(bounds.Left, a.Y + (((b.Y - a.Y) * (bounds.Left - a.X)) / (b.X - a.X))); + + case RectangleEdge.Right: + if (b.X == a.X) + { + throw new ArgumentException("no intercept found"); + } + + return new ScreenPoint(bounds.Right, a.Y + (((b.Y - a.Y) * (bounds.Right - a.X)) / (b.X - a.X))); + + case RectangleEdge.Top: + if (b.Y == a.Y) + { + throw new ArgumentException("no intercept found"); + } + + return new ScreenPoint(a.X + (((b.X - a.X) * (bounds.Top - a.Y)) / (b.Y - a.Y)), bounds.Top); + } + + throw new ArgumentException("no intercept found"); + } + + } +} \ No newline at end of file diff -r 88d699a65cc2 -r 5be8f2773237 External/OxyPlot/OxyPlot/Foundation/VerticalAlignment.cs --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/External/OxyPlot/OxyPlot/Foundation/VerticalAlignment.cs Sat Jun 08 16:53:22 2013 +0000 @@ -0,0 +1,52 @@ +// -------------------------------------------------------------------------------------------------------------------- +// +// The MIT License (MIT) +// +// Copyright (c) 2012 Oystein Bjorke +// +// Permission is hereby granted, free of charge, to any person obtaining a +// copy of this software and associated documentation files (the +// "Software"), to deal in the Software without restriction, including +// without limitation the rights to use, copy, modify, merge, publish, +// distribute, sublicense, and/or sell copies of the Software, and to +// permit persons to whom the Software is furnished to do so, subject to +// the following conditions: +// +// The above copyright notice and this permission notice shall be included +// in all copies or substantial portions of the Software. +// +// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS +// OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF +// MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. +// IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY +// CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, +// TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE +// SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. +// +// +// Vertical text alignment. +// +// -------------------------------------------------------------------------------------------------------------------- +namespace OxyPlot +{ + /// + /// Specifies the vertical alignment. + /// + public enum VerticalAlignment + { + /// + /// Aligned at the top. + /// + Top = -1, + + /// + /// Aligned in the middle. + /// + Middle = 0, + + /// + /// Aligned at the bottom. + /// + Bottom = 1 + } +} \ No newline at end of file diff -r 88d699a65cc2 -r 5be8f2773237 External/OxyPlot/OxyPlot/Foundation/XmlWriterBase.cs --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/External/OxyPlot/OxyPlot/Foundation/XmlWriterBase.cs Sat Jun 08 16:53:22 2013 +0000 @@ -0,0 +1,233 @@ +// -------------------------------------------------------------------------------------------------------------------- +// +// The MIT License (MIT) +// +// Copyright (c) 2012 Oystein Bjorke +// +// Permission is hereby granted, free of charge, to any person obtaining a +// copy of this software and associated documentation files (the +// "Software"), to deal in the Software without restriction, including +// without limitation the rights to use, copy, modify, merge, publish, +// distribute, sublicense, and/or sell copies of the Software, and to +// permit persons to whom the Software is furnished to do so, subject to +// the following conditions: +// +// The above copyright notice and this permission notice shall be included +// in all copies or substantial portions of the Software. +// +// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS +// OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF +// MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. +// IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY +// CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, +// TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE +// SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. +// +// +// Abstract base class for exporters that write xml. +// +// -------------------------------------------------------------------------------------------------------------------- +namespace OxyPlot +{ + using System; + using System.IO; + using System.Text; + using System.Xml; + + /// + /// Provides an abstract base class for exporters that write xml. + /// + public abstract class XmlWriterBase : IDisposable + { + /// + /// The xml writer. + /// + private XmlWriter w; + + /// + /// The disposed flag. + /// + private bool disposed; + + /// + /// Initializes a new instance of the class. + /// + protected XmlWriterBase() + { + } + + /// + /// Initializes a new instance of the class. + /// + /// + /// The stream. + /// + protected XmlWriterBase(Stream stream) + { + this.w = XmlWriter.Create(stream, new XmlWriterSettings { Indent = true, Encoding = Encoding.UTF8 }); + } + + /// + /// Closes this instance. + /// + public virtual void Close() + { + } + + /// + /// Performs application-defined tasks associated with freeing, releasing, or resetting unmanaged resources. + /// + public void Dispose() + { + this.Dispose(true); + GC.SuppressFinalize(this); + } + + /// + /// Flushes this instance. + /// + public void Flush() + { + this.w.Flush(); + } + + /// + /// The write attribute string. + /// + /// + /// The name. + /// + /// + /// The value. + /// + protected void WriteAttributeString(string name, string value) + { + this.w.WriteAttributeString(name, value); + } + + /// + /// The write doc type. + /// + /// + /// The name. + /// + /// + /// The pubid. + /// + /// + /// The sysid. + /// + /// + /// The subset. + /// + protected void WriteDocType(string name, string pubid, string sysid, string subset) + { + this.w.WriteDocType(name, pubid, sysid, subset); + } + + /// + /// The write element string. + /// + /// + /// The name. + /// + /// + /// The text. + /// + protected void WriteElementString(string name, string text) + { + this.w.WriteElementString(name, text); + } + + /// + /// The write end document. + /// + protected void WriteEndDocument() + { + this.w.WriteEndDocument(); + } + + /// + /// The write end element. + /// + protected void WriteEndElement() + { + this.w.WriteEndElement(); + } + + /// + /// The write raw. + /// + /// + /// The text. + /// + protected void WriteRaw(string text) + { + this.w.WriteRaw(text); + } + + /// + /// The write start document. + /// + /// + /// The standalone. + /// + protected void WriteStartDocument(bool standalone) + { + this.w.WriteStartDocument(standalone); + } + + /// + /// The write start element. + /// + /// + /// The name. + /// + protected void WriteStartElement(string name) + { + this.w.WriteStartElement(name); + } + + /// + /// The write start element. + /// + /// + /// The name. + /// + /// + /// The ns. + /// + protected void WriteStartElement(string name, string ns) + { + this.w.WriteStartElement(name, ns); + } + + /// + /// The write string. + /// + /// + /// The text. + /// + protected void WriteString(string text) + { + this.w.WriteString(text); + } + + /// + /// Releases unmanaged and - optionally - managed resources + /// + /// true to release both managed and unmanaged resources; false to release only unmanaged resources. + private void Dispose(bool disposing) + { + if (!this.disposed) + { + if (disposing) + { + this.Close(); + } + } + + this.disposed = true; + } + } +} \ No newline at end of file diff -r 88d699a65cc2 -r 5be8f2773237 External/OxyPlot/OxyPlot/LibraryDoc.cs --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/External/OxyPlot/OxyPlot/LibraryDoc.cs Sat Jun 08 16:53:22 2013 +0000 @@ -0,0 +1,37 @@ +// -------------------------------------------------------------------------------------------------------------------- +// +// The MIT License (MIT) +// +// Copyright (c) 2012 Oystein Bjorke +// +// Permission is hereby granted, free of charge, to any person obtaining a +// copy of this software and associated documentation files (the +// "Software"), to deal in the Software without restriction, including +// without limitation the rights to use, copy, modify, merge, publish, +// distribute, sublicense, and/or sell copies of the Software, and to +// permit persons to whom the Software is furnished to do so, subject to +// the following conditions: +// +// The above copyright notice and this permission notice shall be included +// in all copies or substantial portions of the Software. +// +// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS +// OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF +// MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. +// IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY +// CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, +// TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE +// SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. +// +// -------------------------------------------------------------------------------------------------------------------- + +namespace OxyPlot +{ + /// + /// The OxyPlot solution provides plotting functionality on many platforms. + /// + [System.Runtime.CompilerServices.CompilerGenerated] + internal class LibraryDoc + { + } +} \ No newline at end of file diff -r 88d699a65cc2 -r 5be8f2773237 External/OxyPlot/OxyPlot/Manipulators/CursorType.cs --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/External/OxyPlot/OxyPlot/Manipulators/CursorType.cs Sat Jun 08 16:53:22 2013 +0000 @@ -0,0 +1,62 @@ +// -------------------------------------------------------------------------------------------------------------------- +// +// The MIT License (MIT) +// +// Copyright (c) 2012 Oystein Bjorke +// +// Permission is hereby granted, free of charge, to any person obtaining a +// copy of this software and associated documentation files (the +// "Software"), to deal in the Software without restriction, including +// without limitation the rights to use, copy, modify, merge, publish, +// distribute, sublicense, and/or sell copies of the Software, and to +// permit persons to whom the Software is furnished to do so, subject to +// the following conditions: +// +// The above copyright notice and this permission notice shall be included +// in all copies or substantial portions of the Software. +// +// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS +// OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF +// MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. +// IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY +// CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, +// TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE +// SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. +// +// +// Specifies the cursor type. +// +// -------------------------------------------------------------------------------------------------------------------- +namespace OxyPlot +{ + /// + /// Specifies the cursor type. + /// + public enum CursorType + { + /// + /// The default cursor + /// + Default = 0, + + /// + /// The pan cursor + /// + Pan, + + /// + /// The zoom rectangle cursor + /// + ZoomRectangle, + + /// + /// The horizontal zoom cursor + /// + ZoomHorizontal, + + /// + /// The vertical zoom cursor + /// + ZoomVertical + } +} \ No newline at end of file diff -r 88d699a65cc2 -r 5be8f2773237 External/OxyPlot/OxyPlot/Manipulators/IPlotControl.cs --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/External/OxyPlot/OxyPlot/Manipulators/IPlotControl.cs Sat Jun 08 16:53:22 2013 +0000 @@ -0,0 +1,176 @@ +// -------------------------------------------------------------------------------------------------------------------- +// +// The MIT License (MIT) +// +// Copyright (c) 2012 Oystein Bjorke +// +// Permission is hereby granted, free of charge, to any person obtaining a +// copy of this software and associated documentation files (the +// "Software"), to deal in the Software without restriction, including +// without limitation the rights to use, copy, modify, merge, publish, +// distribute, sublicense, and/or sell copies of the Software, and to +// permit persons to whom the Software is furnished to do so, subject to +// the following conditions: +// +// The above copyright notice and this permission notice shall be included +// in all copies or substantial portions of the Software. +// +// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS +// OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF +// MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. +// IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY +// CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, +// TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE +// SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. +// +// +// Interface for Plot controls. +// +// -------------------------------------------------------------------------------------------------------------------- +namespace OxyPlot +{ + using OxyPlot.Annotations; + using OxyPlot.Axes; + using OxyPlot.Series; + + /// + /// Defines functionality in the Plot controls. + /// + public interface IPlotControl + { + /// + /// Gets the actual model. + /// + /// The actual model. + PlotModel ActualModel { get; } + + /// + /// Gets the axes from a point. + /// + /// + /// The point. + /// + /// + /// The x-axis. + /// + /// + /// The y-axis. + /// + void GetAxesFromPoint(ScreenPoint pt, out Axis xaxis, out Axis yaxis); + + /// + /// Gets the series from point. + /// + /// + /// The point (screen coordinates). + /// + /// + /// The maximum allowed distance. + /// + /// + /// The series. + /// + Series.Series GetSeriesFromPoint(ScreenPoint pt, double limit = 100); + + /// + /// Hides the tracker. + /// + void HideTracker(); + + /// + /// Hides the zoom rectangle. + /// + void HideZoomRectangle(); + + /// + /// Invalidate the plot (not blocking the UI thread) + /// + /// + /// if set to true, all data collections will be updated. + /// + void InvalidatePlot(bool updateData = true); + + /// + /// Pans the specified axis. + /// + /// + /// The axis. + /// + /// + /// The previous point (screen coordinates). + /// + /// + /// The current point (screen coordinates). + /// + void Pan(Axis axis, ScreenPoint ppt, ScreenPoint cpt); + + /// + /// Refresh the plot immediately (blocking UI thread) + /// + /// + /// if set to true, all data collections will be updated. + /// + void RefreshPlot(bool updateData = true); + + /// + /// Resets the specified axis. + /// + /// + /// The axis. + /// + void Reset(Axis axis); + + /// + /// Sets the cursor type. + /// + /// + /// The cursor type. + /// + void SetCursorType(CursorType cursorType); + + /// + /// Shows the tracker. + /// + /// + /// The tracker data. + /// + void ShowTracker(TrackerHitResult trackerHitResult); + + /// + /// Shows the zoom rectangle. + /// + /// + /// The rectangle. + /// + void ShowZoomRectangle(OxyRect r); + + /// + /// Zooms the specified axis to the specified values. + /// + /// + /// The axis. + /// + /// + /// The new minimum value. + /// + /// + /// The new maximum value. + /// + void Zoom(Axis axis, double p1, double p2); + + /// + /// Zooms at the specified position. + /// + /// + /// The axis. + /// + /// + /// The zoom factor. + /// + /// + /// The position to zoom at. + /// + void ZoomAt(Axis axis, double factor, double x); + + } +} \ No newline at end of file diff -r 88d699a65cc2 -r 5be8f2773237 External/OxyPlot/OxyPlot/Manipulators/ManipulationEventArgs.cs --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/External/OxyPlot/OxyPlot/Manipulators/ManipulationEventArgs.cs Sat Jun 08 16:53:22 2013 +0000 @@ -0,0 +1,67 @@ +// -------------------------------------------------------------------------------------------------------------------- +// +// The MIT License (MIT) +// +// Copyright (c) 2012 Oystein Bjorke +// +// Permission is hereby granted, free of charge, to any person obtaining a +// copy of this software and associated documentation files (the +// "Software"), to deal in the Software without restriction, including +// without limitation the rights to use, copy, modify, merge, publish, +// distribute, sublicense, and/or sell copies of the Software, and to +// permit persons to whom the Software is furnished to do so, subject to +// the following conditions: +// +// The above copyright notice and this permission notice shall be included +// in all copies or substantial portions of the Software. +// +// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS +// OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF +// MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. +// IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY +// CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, +// TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE +// SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. +// +// +// Provides data for the manipulation events. +// +// -------------------------------------------------------------------------------------------------------------------- +namespace OxyPlot +{ + /// + /// Provides data for the manipulation events. + /// + public class ManipulationEventArgs + { + /// + /// Initializes a new instance of the class. + /// + /// + /// The current position. + /// + public ManipulationEventArgs(ScreenPoint currentPosition) + { + this.CurrentPosition = currentPosition; + } + + /// + /// Gets the current position. + /// + /// The current position. + public ScreenPoint CurrentPosition { get; private set; } + + /// + /// Gets or sets the X scaling factor. + /// + /// The scale value. + public double ScaleX { get; set; } + + /// + /// Gets or sets the Y scaling factor. + /// + /// The scale value. + public double ScaleY { get; set; } + + } +} \ No newline at end of file diff -r 88d699a65cc2 -r 5be8f2773237 External/OxyPlot/OxyPlot/Manipulators/ManipulatorBase.cs --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/External/OxyPlot/OxyPlot/Manipulators/ManipulatorBase.cs Sat Jun 08 16:53:22 2013 +0000 @@ -0,0 +1,151 @@ +// -------------------------------------------------------------------------------------------------------------------- +// +// The MIT License (MIT) +// +// Copyright (c) 2012 Oystein Bjorke +// +// Permission is hereby granted, free of charge, to any person obtaining a +// copy of this software and associated documentation files (the +// "Software"), to deal in the Software without restriction, including +// without limitation the rights to use, copy, modify, merge, publish, +// distribute, sublicense, and/or sell copies of the Software, and to +// permit persons to whom the Software is furnished to do so, subject to +// the following conditions: +// +// The above copyright notice and this permission notice shall be included +// in all copies or substantial portions of the Software. +// +// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS +// OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF +// MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. +// IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY +// CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, +// TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE +// SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. +// +// +// The manipulator base. +// +// -------------------------------------------------------------------------------------------------------------------- +namespace OxyPlot +{ + using OxyPlot.Axes; + + /// + /// Provides an absract base class for plot control manipulators. + /// + public class ManipulatorBase + { + /// + /// Initializes a new instance of the class. + /// + /// + /// The plot control. + /// + protected ManipulatorBase(IPlotControl plotControl) + { + this.PlotControl = plotControl; + } + + /// + /// Gets the first position of the manipulation. + /// + public ScreenPoint StartPosition { get; private set; } + + /// + /// Gets the plot control. + /// + protected IPlotControl PlotControl { get; private set; } + + /// + /// Gets or sets the X axis. + /// + /// The X axis. + protected Axis XAxis { get; set; } + + /// + /// Gets or sets the Y axis. + /// + /// The Y axis. + protected Axis YAxis { get; set; } + + /// + /// Occurs when a manipulation is complete. + /// + /// + /// The instance containing the event data. + /// + public virtual void Completed(ManipulationEventArgs e) + { + this.PlotControl.SetCursorType(CursorType.Default); + } + + /// + /// Occurs when the input device changes position during a manipulation. + /// + /// + /// The instance containing the event data. + /// + public virtual void Delta(ManipulationEventArgs e) + { + } + + /// + /// Gets the cursor for the manipulation. + /// + /// + /// The cursor. + /// + public virtual CursorType GetCursorType() + { + return CursorType.Default; + } + + /// + /// Occurs when an input device begins a manipulation on the plot. + /// + /// + /// The instance containing the event data. + /// + public virtual void Started(ManipulationEventArgs e) + { + Axis xaxis; + Axis yaxis; + this.PlotControl.GetAxesFromPoint(e.CurrentPosition, out xaxis, out yaxis); + this.StartPosition = e.CurrentPosition; + + this.XAxis = xaxis; + this.YAxis = yaxis; + + this.PlotControl.SetCursorType(this.GetCursorType()); + } + + /// + /// Transforms a point from screen coordinates to data coordinates. + /// + /// + /// The x coordinate. + /// + /// + /// The y coordinate. + /// + /// + /// A data point. + /// + protected DataPoint InverseTransform(double x, double y) + { + if (this.XAxis != null) + { + return this.XAxis.InverseTransform(x, y, this.YAxis); + } + + if (this.YAxis != null) + { + return new DataPoint(0, this.YAxis.InverseTransform(y)); + } + + return new DataPoint(); + } + + } +} \ No newline at end of file diff -r 88d699a65cc2 -r 5be8f2773237 External/OxyPlot/OxyPlot/Manipulators/PanManipulator.cs --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/External/OxyPlot/OxyPlot/Manipulators/PanManipulator.cs Sat Jun 08 16:53:22 2013 +0000 @@ -0,0 +1,100 @@ +// -------------------------------------------------------------------------------------------------------------------- +// +// The MIT License (MIT) +// +// Copyright (c) 2012 Oystein Bjorke +// +// Permission is hereby granted, free of charge, to any person obtaining a +// copy of this software and associated documentation files (the +// "Software"), to deal in the Software without restriction, including +// without limitation the rights to use, copy, modify, merge, publish, +// distribute, sublicense, and/or sell copies of the Software, and to +// permit persons to whom the Software is furnished to do so, subject to +// the following conditions: +// +// The above copyright notice and this permission notice shall be included +// in all copies or substantial portions of the Software. +// +// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS +// OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF +// MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. +// IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY +// CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, +// TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE +// SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. +// +// +// The pan manipulator. +// +// -------------------------------------------------------------------------------------------------------------------- +namespace OxyPlot +{ + /// + /// Provides a plot control manipulator for panning functionality. + /// + public class PanManipulator : ManipulatorBase + { + /// + /// Initializes a new instance of the class. + /// + /// + /// The plot control. + /// + public PanManipulator(IPlotControl plotControl) + : base(plotControl) + { + } + + /// + /// Gets or sets the previous position. + /// + private ScreenPoint PreviousPosition { get; set; } + + /// + /// Occurs when the input device changes position during a manipulation. + /// + /// + /// The instance containing the event data. + /// + public override void Delta(ManipulationEventArgs e) + { + base.Delta(e); + if (this.XAxis != null) + { + this.PlotControl.Pan(this.XAxis, this.PreviousPosition, e.CurrentPosition); + } + + if (this.YAxis != null) + { + this.PlotControl.Pan(this.YAxis, this.PreviousPosition, e.CurrentPosition); + } + + this.PlotControl.RefreshPlot(false); + this.PreviousPosition = e.CurrentPosition; + } + + /// + /// Gets the cursor for the manipulation. + /// + /// + /// The cursor. + /// + public override CursorType GetCursorType() + { + return CursorType.Pan; + } + + /// + /// Occurs when an input device begins a manipulation on the plot. + /// + /// + /// The instance containing the event data. + /// + public override void Started(ManipulationEventArgs e) + { + base.Started(e); + this.PreviousPosition = e.CurrentPosition; + } + + } +} \ No newline at end of file diff -r 88d699a65cc2 -r 5be8f2773237 External/OxyPlot/OxyPlot/Manipulators/ResetManipulator.cs --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/External/OxyPlot/OxyPlot/Manipulators/ResetManipulator.cs Sat Jun 08 16:53:22 2013 +0000 @@ -0,0 +1,71 @@ +// -------------------------------------------------------------------------------------------------------------------- +// +// The MIT License (MIT) +// +// Copyright (c) 2012 Oystein Bjorke +// +// Permission is hereby granted, free of charge, to any person obtaining a +// copy of this software and associated documentation files (the +// "Software"), to deal in the Software without restriction, including +// without limitation the rights to use, copy, modify, merge, publish, +// distribute, sublicense, and/or sell copies of the Software, and to +// permit persons to whom the Software is furnished to do so, subject to +// the following conditions: +// +// The above copyright notice and this permission notice shall be included +// in all copies or substantial portions of the Software. +// +// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS +// OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF +// MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. +// IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY +// CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, +// TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE +// SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. +// +// +// The reset manipulator. +// +// -------------------------------------------------------------------------------------------------------------------- +namespace OxyPlot +{ + /// + /// Provides a plot control manipulator for reset functionality. + /// + public class ResetManipulator : ManipulatorBase + { + /// + /// Initializes a new instance of the class. + /// + /// + /// The plot control. + /// + public ResetManipulator(IPlotControl plotControl) + : base(plotControl) + { + } + + /// + /// Occurs when an input device begins a manipulation on the plot. + /// + /// + /// The instance containing the event data. + /// + public override void Started(ManipulationEventArgs e) + { + base.Started(e); + if (this.XAxis != null) + { + this.PlotControl.Reset(this.XAxis); + } + + if (this.YAxis != null) + { + this.PlotControl.Reset(this.YAxis); + } + + this.PlotControl.InvalidatePlot(); + } + + } +} \ No newline at end of file diff -r 88d699a65cc2 -r 5be8f2773237 External/OxyPlot/OxyPlot/Manipulators/TrackerHitResult.cs --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/External/OxyPlot/OxyPlot/Manipulators/TrackerHitResult.cs Sat Jun 08 16:53:22 2013 +0000 @@ -0,0 +1,162 @@ +// -------------------------------------------------------------------------------------------------------------------- +// +// The MIT License (MIT) +// +// Copyright (c) 2012 Oystein Bjorke +// +// Permission is hereby granted, free of charge, to any person obtaining a +// copy of this software and associated documentation files (the +// "Software"), to deal in the Software without restriction, including +// without limitation the rights to use, copy, modify, merge, publish, +// distribute, sublicense, and/or sell copies of the Software, and to +// permit persons to whom the Software is furnished to do so, subject to +// the following conditions: +// +// The above copyright notice and this permission notice shall be included +// in all copies or substantial portions of the Software. +// +// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS +// OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF +// MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. +// IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY +// CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, +// TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE +// SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. +// +// +// Provides a data container for a tracker hit result. +// +// -------------------------------------------------------------------------------------------------------------------- +namespace OxyPlot +{ + using OxyPlot.Series; + + /// + /// Provides a data container for a tracker hit result. + /// + /// + /// This is used as DataContext for the TrackerControl. + /// The TrackerControl is visible when the user use the left mouse button to "track" points on the series. + /// + public class TrackerHitResult + { + /// + /// The default format string. + /// + private const string DefaultFormatString = "{0}\n{1}: {2}\n{3}: {4}"; + + /// + /// Initializes a new instance of the class. + /// + /// The series. + /// The data point. + /// The screen point. + /// The item. + /// The index. + /// The text. + public TrackerHitResult(OxyPlot.Series.Series series, IDataPoint dp, ScreenPoint sp, object item = null, double index = -1, string text = null) + { + this.DataPoint = dp; + this.Position = sp; + this.Item = item; + this.Index = index; + this.Series = series; + this.Text = text; + var ds = series as DataPointSeries; + if (ds != null) + { + this.XAxis = ds.XAxis; + this.YAxis = ds.YAxis; + } + } + + /// + /// Gets or sets the nearest or interpolated data point. + /// + public IDataPoint DataPoint { get; set; } + + /// + /// Gets or sets the source item of the point. + /// If the current point is from an ItemsSource and is not interpolated, this property will contain the item. + /// + public object Item { get; set; } + + /// + /// Gets or sets the index for the Item. + /// + public double Index { get; set; } + + /// + /// Gets or sets the horizontal/vertical line extents. + /// + public OxyRect LineExtents { get; set; } + + /// + /// Gets or sets the plot model. + /// + public PlotModel PlotModel { get; set; } + + /// + /// Gets or sets the position in screen coordinates. + /// + public ScreenPoint Position { get; set; } + + /// + /// Gets or sets the series that is being tracked. + /// + public Series.Series Series { get; set; } + + /// + /// Gets or sets the text shown in the tracker. + /// + public string Text { get; set; } + + /// + /// Gets or sets the X axis. + /// + public Axes.Axis XAxis { get; set; } + + /// + /// Gets or sets the Y axis. + /// + public Axes.Axis YAxis { get; set; } + + /// + /// Returns a that represents this instance. + /// + /// + /// A that represents this instance. + /// + public override string ToString() + { + if (this.Text != null) + { + return this.Text; + } + + var ts = this.Series as ITrackableSeries; + string formatString = DefaultFormatString; + if (ts != null && !string.IsNullOrEmpty(ts.TrackerFormatString)) + { + formatString = ts.TrackerFormatString; + } + + string xaxisTitle = (this.XAxis != null ? this.XAxis.Title : null) ?? "X"; + string yaxisTitle = (this.YAxis != null ? this.YAxis.Title : null) ?? "Y"; + object xvalue = this.XAxis != null ? this.XAxis.GetValue(this.DataPoint.X) : this.DataPoint.X; + object yvalue = this.YAxis != null ? this.YAxis.GetValue(this.DataPoint.Y) : this.DataPoint.Y; + + return StringHelper.Format( + this.Series.ActualCulture, + formatString, + this.Item, + this.Series.Title, + xaxisTitle, + xvalue, + yaxisTitle, + yvalue, + this.Item).Trim(); + } + + } +} \ No newline at end of file diff -r 88d699a65cc2 -r 5be8f2773237 External/OxyPlot/OxyPlot/Manipulators/TrackerManipulator.cs --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/External/OxyPlot/OxyPlot/Manipulators/TrackerManipulator.cs Sat Jun 08 16:53:22 2013 +0000 @@ -0,0 +1,186 @@ +// -------------------------------------------------------------------------------------------------------------------- +// +// The MIT License (MIT) +// +// Copyright (c) 2012 Oystein Bjorke +// +// Permission is hereby granted, free of charge, to any person obtaining a +// copy of this software and associated documentation files (the +// "Software"), to deal in the Software without restriction, including +// without limitation the rights to use, copy, modify, merge, publish, +// distribute, sublicense, and/or sell copies of the Software, and to +// permit persons to whom the Software is furnished to do so, subject to +// the following conditions: +// +// The above copyright notice and this permission notice shall be included +// in all copies or substantial portions of the Software. +// +// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS +// OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF +// MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. +// IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY +// CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, +// TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE +// SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. +// +// +// The tracker manipulator. +// +// -------------------------------------------------------------------------------------------------------------------- +namespace OxyPlot +{ + using OxyPlot.Series; + + /// + /// Provides a plot control manipulator for tracker functionality. + /// + public class TrackerManipulator : ManipulatorBase + { + /// + /// The current series. + /// + private ITrackableSeries currentSeries; + + /// + /// Initializes a new instance of the class. + /// + /// + /// The plot control. + /// + public TrackerManipulator(IPlotControl plotControl) + : base(plotControl) + { + this.Snap = true; + this.PointsOnly = false; + } + + /// + /// Gets or sets a value indicating whether to show tracker on points only (not interpolating). + /// + public bool PointsOnly { get; set; } + + /// + /// Gets or sets a value indicating whether to snap to the nearest point. + /// + public bool Snap { get; set; } + + /// + /// Occurs when a manipulation is complete. + /// + /// + /// The instance containing the event data. + /// + public override void Completed(ManipulationEventArgs e) + { + base.Completed(e); + + if (this.currentSeries == null) + { + return; + } + + this.currentSeries = null; + this.PlotControl.HideTracker(); + } + + /// + /// Occurs when the input device changes position during a manipulation. + /// + /// + /// The instance containing the event data. + /// + public override void Delta(ManipulationEventArgs e) + { + base.Delta(e); + if (this.currentSeries == null) + { + return; + } + + if (!this.PlotControl.ActualModel.PlotArea.Contains(e.CurrentPosition.X, e.CurrentPosition.Y)) + { + return; + } + + TrackerHitResult result = GetNearestHit(this.currentSeries, e.CurrentPosition, this.Snap, this.PointsOnly); + if (result != null) + { + result.PlotModel = this.PlotControl.ActualModel; + this.PlotControl.ShowTracker(result); + } + } + + /// + /// Gets the cursor for the manipulation. + /// + /// + /// The cursor. + /// + public override CursorType GetCursorType() + { + return CursorType.Default; + } + + /// + /// Occurs when an input device begins a manipulation on the plot. + /// + /// + /// The instance containing the event data. + /// + public override void Started(ManipulationEventArgs e) + { + base.Started(e); + this.currentSeries = this.PlotControl.GetSeriesFromPoint(e.CurrentPosition); + this.Delta(e); + } + + /// + /// Gets the nearest tracker hit. + /// + /// + /// The series. + /// + /// + /// The point. + /// + /// + /// Snap to points. + /// + /// + /// Check points only (no interpolation). + /// + /// + /// A tracker hit result. + /// + private static TrackerHitResult GetNearestHit(ITrackableSeries s, ScreenPoint point, bool snap, bool pointsOnly) + { + if (s == null) + { + return null; + } + + // Check data points only + if (snap || pointsOnly) + { + TrackerHitResult result = s.GetNearestPoint(point, false); + if (result != null) + { + if (result.Position.DistanceTo(point) < 20) + { + return result; + } + } + } + + // Check between data points (if possible) + if (!pointsOnly) + { + TrackerHitResult result = s.GetNearestPoint(point, true); + return result; + } + + return null; + } + + } +} \ No newline at end of file diff -r 88d699a65cc2 -r 5be8f2773237 External/OxyPlot/OxyPlot/Manipulators/ZoomManipulator.cs --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/External/OxyPlot/OxyPlot/Manipulators/ZoomManipulator.cs Sat Jun 08 16:53:22 2013 +0000 @@ -0,0 +1,72 @@ +// -------------------------------------------------------------------------------------------------------------------- +// +// The MIT License (MIT) +// +// Copyright (c) 2012 Oystein Bjorke +// +// Permission is hereby granted, free of charge, to any person obtaining a +// copy of this software and associated documentation files (the +// "Software"), to deal in the Software without restriction, including +// without limitation the rights to use, copy, modify, merge, publish, +// distribute, sublicense, and/or sell copies of the Software, and to +// permit persons to whom the Software is furnished to do so, subject to +// the following conditions: +// +// The above copyright notice and this permission notice shall be included +// in all copies or substantial portions of the Software. +// +// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS +// OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF +// MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. +// IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY +// CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, +// TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE +// SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. +// +// +// The zoom manipulator. +// +// -------------------------------------------------------------------------------------------------------------------- +namespace OxyPlot +{ + /// + /// Provides a plot control manipulator for zoom functionality. + /// + public class ZoomManipulator : ManipulatorBase + { + /// + /// Initializes a new instance of the class. + /// + /// + /// The plot control. + /// + public ZoomManipulator(IPlotControl plotControl) + : base(plotControl) + { + } + + /// + /// Occurs when the input device changes position during a manipulation. + /// + /// The instance containing the event data. + public override void Delta(ManipulationEventArgs e) + { + base.Delta(e); + + DataPoint current = this.InverseTransform(e.CurrentPosition.X, e.CurrentPosition.Y); + + if (this.XAxis != null) + { + this.PlotControl.ZoomAt(this.XAxis, e.ScaleX, current.X); + } + + if (this.YAxis != null) + { + this.PlotControl.ZoomAt(this.YAxis, e.ScaleY, current.Y); + } + + this.PlotControl.InvalidatePlot(); + } + + } +} \ No newline at end of file diff -r 88d699a65cc2 -r 5be8f2773237 External/OxyPlot/OxyPlot/Manipulators/ZoomRectangleManipulator.cs --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/External/OxyPlot/OxyPlot/Manipulators/ZoomRectangleManipulator.cs Sat Jun 08 16:53:22 2013 +0000 @@ -0,0 +1,154 @@ +// -------------------------------------------------------------------------------------------------------------------- +// +// The MIT License (MIT) +// +// Copyright (c) 2012 Oystein Bjorke +// +// Permission is hereby granted, free of charge, to any person obtaining a +// copy of this software and associated documentation files (the +// "Software"), to deal in the Software without restriction, including +// without limitation the rights to use, copy, modify, merge, publish, +// distribute, sublicense, and/or sell copies of the Software, and to +// permit persons to whom the Software is furnished to do so, subject to +// the following conditions: +// +// The above copyright notice and this permission notice shall be included +// in all copies or substantial portions of the Software. +// +// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS +// OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF +// MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. +// IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY +// CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, +// TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE +// SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. +// +// +// The zoom manipulator. +// +// -------------------------------------------------------------------------------------------------------------------- +namespace OxyPlot +{ + using System; + + /// + /// Provides a plot control manipulator for zoom by rectangle functionality. + /// + public class ZoomRectangleManipulator : ManipulatorBase + { + /// + /// Initializes a new instance of the class. + /// + /// + /// The plot control. + /// + public ZoomRectangleManipulator(IPlotControl plotControl) + : base(plotControl) + { + } + + /// + /// Gets or sets the zoom rectangle. + /// + private OxyRect ZoomRectangle { get; set; } + + /// + /// Occurs when a manipulation is complete. + /// + /// + /// The instance containing the event data. + /// + public override void Completed(ManipulationEventArgs e) + { + base.Completed(e); + + this.PlotControl.HideZoomRectangle(); + + if (this.ZoomRectangle.Width > 10 && this.ZoomRectangle.Height > 10) + { + DataPoint p0 = this.InverseTransform(this.ZoomRectangle.Left, this.ZoomRectangle.Top); + DataPoint p1 = this.InverseTransform(this.ZoomRectangle.Right, this.ZoomRectangle.Bottom); + + if (this.XAxis != null) + { + this.PlotControl.Zoom(this.XAxis, p0.X, p1.X); + } + + if (this.YAxis != null) + { + this.PlotControl.Zoom(this.YAxis, p0.Y, p1.Y); + } + + this.PlotControl.InvalidatePlot(); + } + } + + /// + /// Occurs when the input device changes position during a manipulation. + /// + /// + /// The instance containing the event data. + /// + public override void Delta(ManipulationEventArgs e) + { + base.Delta(e); + + OxyRect plotArea = this.PlotControl.ActualModel.PlotArea; + + double x = Math.Min(this.StartPosition.X, e.CurrentPosition.X); + double w = Math.Abs(this.StartPosition.X - e.CurrentPosition.X); + double y = Math.Min(this.StartPosition.Y, e.CurrentPosition.Y); + double h = Math.Abs(this.StartPosition.Y - e.CurrentPosition.Y); + + if (this.XAxis == null) + { + x = plotArea.Left; + w = plotArea.Width; + } + + if (this.YAxis == null) + { + y = plotArea.Top; + h = plotArea.Height; + } + + this.ZoomRectangle = new OxyRect(x, y, w, h); + this.PlotControl.ShowZoomRectangle(this.ZoomRectangle); + } + + /// + /// Gets the cursor for the manipulation. + /// + /// + /// The cursor. + /// + public override CursorType GetCursorType() + { + if (this.XAxis == null) + { + return CursorType.ZoomVertical; + } + + if (this.YAxis == null) + { + return CursorType.ZoomHorizontal; + } + + return CursorType.ZoomRectangle; + } + + /// + /// Occurs when an input device begins a manipulation on the plot. + /// + /// + /// The instance containing the event data. + /// + public override void Started(ManipulationEventArgs e) + { + base.Started(e); + this.ZoomRectangle = new OxyRect(this.StartPosition.X, this.StartPosition.Y, 0, 0); + this.PlotControl.ShowZoomRectangle(this.ZoomRectangle); + } + + } +} \ No newline at end of file diff -r 88d699a65cc2 -r 5be8f2773237 External/OxyPlot/OxyPlot/Manipulators/ZoomStepManipulator.cs --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/External/OxyPlot/OxyPlot/Manipulators/ZoomStepManipulator.cs Sat Jun 08 16:53:22 2013 +0000 @@ -0,0 +1,106 @@ +// -------------------------------------------------------------------------------------------------------------------- +// +// The MIT License (MIT) +// +// Copyright (c) 2012 Oystein Bjorke +// +// Permission is hereby granted, free of charge, to any person obtaining a +// copy of this software and associated documentation files (the +// "Software"), to deal in the Software without restriction, including +// without limitation the rights to use, copy, modify, merge, publish, +// distribute, sublicense, and/or sell copies of the Software, and to +// permit persons to whom the Software is furnished to do so, subject to +// the following conditions: +// +// The above copyright notice and this permission notice shall be included +// in all copies or substantial portions of the Software. +// +// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS +// OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF +// MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. +// IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY +// CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, +// TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE +// SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. +// +// +// The step manipulator. +// +// -------------------------------------------------------------------------------------------------------------------- +namespace OxyPlot +{ + /// + /// Provides a plot control manipulator for stepwise zoom functionality. + /// + public class ZoomStepManipulator : ManipulatorBase + { + /// + /// Initializes a new instance of the class. + /// + /// + /// The plot control. + /// + /// + /// The step. + /// + /// + /// The fine Control. + /// + public ZoomStepManipulator(IPlotControl plotControl, double step, bool fineControl) + : base(plotControl) + { + this.Step = step; + this.FineControl = fineControl; + } + + /// + /// Gets or sets a value indicating whether FineControl. + /// + public bool FineControl { get; set; } + + /// + /// Gets or sets Step. + /// + public double Step { get; set; } + + /// + /// The started. + /// + /// + /// The e. + /// + public override void Started(ManipulationEventArgs e) + { + base.Started(e); + + DataPoint current = this.InverseTransform(e.CurrentPosition.X, e.CurrentPosition.Y); + + double scale = this.Step; + if (this.FineControl) + { + scale *= 3; + } + + scale = 1 + scale; + + // make sure the zoom factor is not negative + if (scale < 0.1) + { + scale = 0.1; + } + + if (this.XAxis != null) + { + this.PlotControl.ZoomAt(this.XAxis, scale, current.X); + } + + if (this.YAxis != null) + { + this.PlotControl.ZoomAt(this.YAxis, scale, current.Y); + } + + this.PlotControl.InvalidatePlot(); + } + + } +} \ No newline at end of file diff -r 88d699a65cc2 -r 5be8f2773237 External/OxyPlot/OxyPlot/MouseActions/MouseAction.cs --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/External/OxyPlot/OxyPlot/MouseActions/MouseAction.cs Sat Jun 08 16:53:22 2013 +0000 @@ -0,0 +1,54 @@ +// -------------------------------------------------------------------------------------------------------------------- +// +// The MIT License (MIT) +// +// Copyright (c) 2012 Oystein Bjorke +// +// Permission is hereby granted, free of charge, to any person obtaining a +// copy of this software and associated documentation files (the +// "Software"), to deal in the Software without restriction, including +// without limitation the rights to use, copy, modify, merge, publish, +// distribute, sublicense, and/or sell copies of the Software, and to +// permit persons to whom the Software is furnished to do so, subject to +// the following conditions: +// +// The above copyright notice and this permission notice shall be included +// in all copies or substantial portions of the Software. +// +// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS +// OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF +// MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. +// IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY +// CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, +// TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE +// SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. +// +// -------------------------------------------------------------------------------------------------------------------- +namespace OxyPlot +{ + public abstract class MouseAction : IMouseAction + { + protected IPlotControl pc; + + protected MouseAction(IPlotControl pc) + { + this.pc = pc; + } + + public virtual void OnMouseDown(ScreenPoint pt, OxyMouseButton button, int clickCount, bool control, bool shift, bool alt) + { + } + + public virtual void OnMouseMove(ScreenPoint pt, bool control, bool shift, bool alt) + { + } + + public virtual void OnMouseUp() + { + } + + public virtual void OnMouseWheel(ScreenPoint pt, double delta, bool control, bool shift, bool alt) + { + } + } +} \ No newline at end of file diff -r 88d699a65cc2 -r 5be8f2773237 External/OxyPlot/OxyPlot/MouseActions/SliderAction.cs --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/External/OxyPlot/OxyPlot/MouseActions/SliderAction.cs Sat Jun 08 16:53:22 2013 +0000 @@ -0,0 +1,106 @@ +// -------------------------------------------------------------------------------------------------------------------- +// +// The MIT License (MIT) +// +// Copyright (c) 2012 Oystein Bjorke +// +// Permission is hereby granted, free of charge, to any person obtaining a +// copy of this software and associated documentation files (the +// "Software"), to deal in the Software without restriction, including +// without limitation the rights to use, copy, modify, merge, publish, +// distribute, sublicense, and/or sell copies of the Software, and to +// permit persons to whom the Software is furnished to do so, subject to +// the following conditions: +// +// The above copyright notice and this permission notice shall be included +// in all copies or substantial portions of the Software. +// +// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS +// OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF +// MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. +// IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY +// CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, +// TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE +// SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. +// +// -------------------------------------------------------------------------------------------------------------------- +namespace OxyPlot +{ + // todo: use screen coordinates instead of original points (problem on log axes) + public class SliderAction : MouseAction + { + public SliderAction(IPlot pc) + : base(pc) + { + } + + private DataSeries currentSeries; + + public override void OnMouseDown(ScreenPoint pt, OxyMouseButton button, int clickCount, bool control, bool shift) + { + base.OnMouseDown(pt, button, clickCount, control, shift); + + if (button != OxyMouseButton.Left) + return; + + // Middle button double click adds an annotation + if (clickCount == 2) + { + // pc.Annotations. + pc.Refresh(); + } + + currentSeries = pc.GetSeriesFromPoint(pt) as DataSeries; + + OnMouseMove(pt, control, shift); + + //pc.CaptureMouse(); + // pc.Cursor = Cursors.Cross; + } + + public override void OnMouseMove(ScreenPoint pt, bool control, bool shift) + { + if (currentSeries == null) + return; + + var current = GetNearestPoint(currentSeries, pt, !control, shift); + if (current != null) + pc.ShowSlider(currentSeries, current.Value); + } + + private static DataPoint? GetNearestPoint(ISeries s, ScreenPoint point, bool snap, bool pointsOnly) + { + if (s == null) + return null; + + if (snap || pointsOnly) + { + ScreenPoint spn; + DataPoint dpn; + if (s.GetNearestPoint(point, out dpn, out spn) && snap) + { + if (spn.DistanceTo(point) < 20) + return dpn; + } + } + + ScreenPoint sp; + DataPoint dp; + + if (!pointsOnly) + if (s.GetNearestInterpolatedPoint(point, out dp, out sp)) + return dp; + + return null; + } + + public override void OnMouseUp() + { + base.OnMouseUp(); + if (currentSeries == null) + return; + currentSeries = null; + pc.HideSlider(); + } + } +} \ No newline at end of file diff -r 88d699a65cc2 -r 5be8f2773237 External/OxyPlot/OxyPlot/NamespaceDoc.cs --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/External/OxyPlot/OxyPlot/NamespaceDoc.cs Sat Jun 08 16:53:22 2013 +0000 @@ -0,0 +1,37 @@ +// -------------------------------------------------------------------------------------------------------------------- +// +// The MIT License (MIT) +// +// Copyright (c) 2012 Oystein Bjorke +// +// Permission is hereby granted, free of charge, to any person obtaining a +// copy of this software and associated documentation files (the +// "Software"), to deal in the Software without restriction, including +// without limitation the rights to use, copy, modify, merge, publish, +// distribute, sublicense, and/or sell copies of the Software, and to +// permit persons to whom the Software is furnished to do so, subject to +// the following conditions: +// +// The above copyright notice and this permission notice shall be included +// in all copies or substantial portions of the Software. +// +// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS +// OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF +// MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. +// IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY +// CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, +// TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE +// SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. +// +// -------------------------------------------------------------------------------------------------------------------- + +namespace OxyPlot +{ + /// + /// The OxyPlot namespace contains the platform independent classes of the library. + /// + [System.Runtime.CompilerServices.CompilerGenerated] + internal class NamespaceDoc + { + } +} \ No newline at end of file diff -r 88d699a65cc2 -r 5be8f2773237 External/OxyPlot/OxyPlot/OxyPlot.csproj --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/External/OxyPlot/OxyPlot/OxyPlot.csproj Sat Jun 08 16:53:22 2013 +0000 @@ -0,0 +1,237 @@ + + + + + Debug + AnyCPU + {BCC43E58-E473-403E-A84D-63FEDC723040} + Library + Properties + OxyPlot + OxyPlot + v4.0 + 512 + Client + + + true + full + false + bin\Debug\ + DEBUG;TRACE + prompt + 4 + + + pdbonly + true + ..\..\Output\NET40x\ + TRACE + prompt + 4 + ..\..\Output\NET40x\OxyPlot.XML + + + true + + + OxyPlot.snk + + + + + + + + + + + + + Properties\GlobalAssemblyInfo.cs + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + \ No newline at end of file diff -r 88d699a65cc2 -r 5be8f2773237 External/OxyPlot/OxyPlot/OxyPlot.snk Binary file External/OxyPlot/OxyPlot/OxyPlot.snk has changed diff -r 88d699a65cc2 -r 5be8f2773237 External/OxyPlot/OxyPlot/PlotModel/HitTestResult.cs --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/External/OxyPlot/OxyPlot/PlotModel/HitTestResult.cs Sat Jun 08 16:53:22 2013 +0000 @@ -0,0 +1,79 @@ +// -------------------------------------------------------------------------------------------------------------------- +// +// The MIT License (MIT) +// +// Copyright (c) 2012 Oystein Bjorke +// +// Permission is hereby granted, free of charge, to any person obtaining a +// copy of this software and associated documentation files (the +// "Software"), to deal in the Software without restriction, including +// without limitation the rights to use, copy, modify, merge, publish, +// distribute, sublicense, and/or sell copies of the Software, and to +// permit persons to whom the Software is furnished to do so, subject to +// the following conditions: +// +// The above copyright notice and this permission notice shall be included +// in all copies or substantial portions of the Software. +// +// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS +// OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF +// MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. +// IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY +// CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, +// TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE +// SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. +// +// +// Represents a hit test result. +// +// -------------------------------------------------------------------------------------------------------------------- +namespace OxyPlot +{ + /// + /// Represents a hit test result. + /// + public class HitTestResult + { + /// + /// Initializes a new instance of the class. + /// + public HitTestResult() + { + } + + /// + /// Initializes a new instance of the class. + /// + /// The nearest hit point. + /// The item. + /// The index. + public HitTestResult(ScreenPoint nhp, object item = null, double index = 0) + { + this.NearestHitPoint = nhp; + this.Item = item; + this.Index = index; + } + + /// + /// Gets or sets the index of the hit (if available). + /// + /// The index. + /// + /// If the hit was in the middle between point 1 and 2, index = 1.5. + /// + public double Index { get; set; } + + /// + /// Gets or sets the item of the hit. + /// + /// The item. + public object Item { get; set; } + + /// + /// Gets or sets the position of the nearest hit point. + /// + /// The nearest hit point. + public ScreenPoint NearestHitPoint { get; set; } + + } +} \ No newline at end of file diff -r 88d699a65cc2 -r 5be8f2773237 External/OxyPlot/OxyPlot/PlotModel/OxyMouseButton.cs --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/External/OxyPlot/OxyPlot/PlotModel/OxyMouseButton.cs Sat Jun 08 16:53:22 2013 +0000 @@ -0,0 +1,67 @@ +// -------------------------------------------------------------------------------------------------------------------- +// +// The MIT License (MIT) +// +// Copyright (c) 2012 Oystein Bjorke +// +// Permission is hereby granted, free of charge, to any person obtaining a +// copy of this software and associated documentation files (the +// "Software"), to deal in the Software without restriction, including +// without limitation the rights to use, copy, modify, merge, publish, +// distribute, sublicense, and/or sell copies of the Software, and to +// permit persons to whom the Software is furnished to do so, subject to +// the following conditions: +// +// The above copyright notice and this permission notice shall be included +// in all copies or substantial portions of the Software. +// +// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS +// OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF +// MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. +// IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY +// CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, +// TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE +// SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. +// +// +// The mouse buttons. +// +// -------------------------------------------------------------------------------------------------------------------- +namespace OxyPlot +{ + /// + /// Specifies constants that define which mouse button was pressed. + /// + public enum OxyMouseButton + { + /// + /// No mouse button. + /// + None = 0, + + /// + /// The left mouse button. + /// + Left = 1, + + /// + /// The middle mouse button. + /// + Middle = 2, + + /// + /// The right mouse button. + /// + Right = 3, + + /// + /// The first extended mouse button. + /// + XButton1 = 4, + + /// + /// The second extended mouse button. + /// + XButton2 = 5, + } +} \ No newline at end of file diff -r 88d699a65cc2 -r 5be8f2773237 External/OxyPlot/OxyPlot/PlotModel/OxyMouseEventArgs.cs --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/External/OxyPlot/OxyPlot/PlotModel/OxyMouseEventArgs.cs Sat Jun 08 16:53:22 2013 +0000 @@ -0,0 +1,87 @@ +// -------------------------------------------------------------------------------------------------------------------- +// +// The MIT License (MIT) +// +// Copyright (c) 2012 Oystein Bjorke +// +// Permission is hereby granted, free of charge, to any person obtaining a +// copy of this software and associated documentation files (the +// "Software"), to deal in the Software without restriction, including +// without limitation the rights to use, copy, modify, merge, publish, +// distribute, sublicense, and/or sell copies of the Software, and to +// permit persons to whom the Software is furnished to do so, subject to +// the following conditions: +// +// The above copyright notice and this permission notice shall be included +// in all copies or substantial portions of the Software. +// +// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS +// OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF +// MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. +// IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY +// CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, +// TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE +// SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. +// +// +// Represents event arguments for 3D mouse events events. +// +// -------------------------------------------------------------------------------------------------------------------- +namespace OxyPlot +{ + using System; + + /// + /// Provides data for the mouse events. + /// + public class OxyMouseEventArgs : EventArgs + { + /// + /// Gets or sets the mouse button that has changed. + /// + public OxyMouseButton ChangedButton { get; set; } + + /// + /// Gets or sets the click count. + /// + /// The click count. + public int ClickCount { get; set; } + + /// + /// Gets or sets a value indicating whether Handled. + /// + public bool Handled { get; set; } + + /// + /// Gets or sets a value indicating whether the alt key was pressed when the event was raised. + /// + public bool IsAltDown { get; set; } + + /// + /// Gets or sets a value indicating whether the control key was pressed when the event was raised. + /// + public bool IsControlDown { get; set; } + + /// + /// Gets or sets a value indicating whether the shift key was pressed when the event was raised. + /// + public bool IsShiftDown { get; set; } + + /// + /// Gets or sets the hit test result. + /// + public HitTestResult HitTestResult { get; set; } + + /// + /// Gets or sets the plot control. + /// + /// The plot control. + public IPlotControl PlotControl { get; set; } + + /// + /// Gets or sets the position. + /// + public ScreenPoint Position { get; set; } + + } +} \ No newline at end of file diff -r 88d699a65cc2 -r 5be8f2773237 External/OxyPlot/OxyPlot/PlotModel/PlotElement.cs --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/External/OxyPlot/OxyPlot/PlotModel/PlotElement.cs Sat Jun 08 16:53:22 2013 +0000 @@ -0,0 +1,142 @@ +// -------------------------------------------------------------------------------------------------------------------- +// +// The MIT License (MIT) +// +// Copyright (c) 2012 Oystein Bjorke +// +// Permission is hereby granted, free of charge, to any person obtaining a +// copy of this software and associated documentation files (the +// "Software"), to deal in the Software without restriction, including +// without limitation the rights to use, copy, modify, merge, publish, +// distribute, sublicense, and/or sell copies of the Software, and to +// permit persons to whom the Software is furnished to do so, subject to +// the following conditions: +// +// The above copyright notice and this permission notice shall be included +// in all copies or substantial portions of the Software. +// +// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS +// OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF +// MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. +// IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY +// CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, +// TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE +// SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. +// +// +// Abstract base class for all plottable elements (Axes, Annotations, Series). +// +// -------------------------------------------------------------------------------------------------------------------- +namespace OxyPlot +{ + using System; + + /// + /// Provides an abstract base class for elements contained in a . + /// + public abstract class PlotElement + { + /// + /// Initializes a new instance of the class. + /// + protected PlotElement() + { + this.Font = null; + this.FontSize = double.NaN; + this.FontWeight = FontWeights.Normal; + } + + /// + /// Gets or sets the font. + /// + /// The font. + /// + /// If the value is null, the parent PlotModel's DefaultFont will be used. + /// + public string Font { get; set; } + + /// + /// Gets or sets the size of the font. + /// + /// The size of the font. + /// + /// If the value is NaN, the parent PlotModel's DefaultFontSize will be used. + /// + public double FontSize { get; set; } + + /// + /// Gets or sets the font weight. + /// + /// The font weight. + public double FontWeight { get; set; } + + /// + /// Gets the parent plot model. + /// + public PlotModel PlotModel { get; internal set; } + + /// + /// Gets or sets an arbitrary object value that can be used to store custom information about this plot element. + /// + /// The intended value. This property has no default value. + /// + /// This property is analogous to Tag properties in other Microsoft programming models. Tag is intended to provide a pre-existing property location where you can store some basic custom information about any PlotElement without requiring you to subclass an element. + /// + public object Tag { get; set; } + + /// + /// Gets or sets the color of the text. + /// + /// The color of the text. + /// + /// If the value is null, the TextColor of the parent PlotModel will be used. + /// + public OxyColor TextColor { get; set; } + + /// + /// Gets the actual font. + /// + protected internal string ActualFont + { + get + { + return this.Font ?? this.PlotModel.DefaultFont; + } + } + + /// + /// Gets the actual size of the font. + /// + /// The actual size of the font. + protected internal double ActualFontSize + { + get + { + return !double.IsNaN(this.FontSize) ? this.FontSize : this.PlotModel.DefaultFontSize; + } + } + + /// + /// Gets the actual font weight. + /// + protected internal double ActualFontWeight + { + get + { + return this.FontWeight; + } + } + + /// + /// Gets the actual color of the text. + /// + /// The actual color of the text. + protected internal OxyColor ActualTextColor + { + get + { + return this.TextColor ?? this.PlotModel.TextColor; + } + } + } +} \ No newline at end of file diff -r 88d699a65cc2 -r 5be8f2773237 External/OxyPlot/OxyPlot/PlotModel/PlotModel.Legends.cs --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/External/OxyPlot/OxyPlot/PlotModel/PlotModel.Legends.cs Sat Jun 08 16:53:22 2013 +0000 @@ -0,0 +1,507 @@ +// -------------------------------------------------------------------------------------------------------------------- +// +// The MIT License (MIT) +// +// Copyright (c) 2012 Oystein Bjorke +// +// Permission is hereby granted, free of charge, to any person obtaining a +// copy of this software and associated documentation files (the +// "Software"), to deal in the Software without restriction, including +// without limitation the rights to use, copy, modify, merge, publish, +// distribute, sublicense, and/or sell copies of the Software, and to +// permit persons to whom the Software is furnished to do so, subject to +// the following conditions: +// +// The above copyright notice and this permission notice shall be included +// in all copies or substantial portions of the Software. +// +// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS +// OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF +// MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. +// IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY +// CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, +// TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE +// SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. +// +// +// Partial PlotModel class - this file contains methods related to the series legends. +// +// -------------------------------------------------------------------------------------------------------------------- +namespace OxyPlot +{ + using System; + using System.Collections.Generic; + using System.Linq; + + using OxyPlot.Series; + + public partial class PlotModel + { + /// + /// Makes the LegendOrientation property safe. + /// + /// + /// If Legend is positioned left or right, force it to vertical orientation + /// + private void EnsureLegendProperties() + { + switch (this.LegendPosition) + { + case LegendPosition.LeftTop: + case LegendPosition.LeftMiddle: + case LegendPosition.LeftBottom: + case LegendPosition.RightTop: + case LegendPosition.RightMiddle: + case LegendPosition.RightBottom: + if (this.LegendOrientation == LegendOrientation.Horizontal) + { + this.LegendOrientation = LegendOrientation.Vertical; + } + + break; + } + } + + /// + /// Gets the rectangle of the legend box. + /// + /// Size of the legend box. + /// A rectangle. + private OxyRect GetLegendRectangle(OxySize legendSize) + { + double top = 0; + double left = 0; + if (this.LegendPlacement == LegendPlacement.Outside) + { + switch (this.LegendPosition) + { + case LegendPosition.LeftTop: + case LegendPosition.LeftMiddle: + case LegendPosition.LeftBottom: + left = this.PlotAndAxisArea.Left - legendSize.Width - this.LegendMargin; + break; + case LegendPosition.RightTop: + case LegendPosition.RightMiddle: + case LegendPosition.RightBottom: + left = this.PlotAndAxisArea.Right + this.LegendMargin; + break; + case LegendPosition.TopLeft: + case LegendPosition.TopCenter: + case LegendPosition.TopRight: + top = this.PlotAndAxisArea.Top - legendSize.Height - this.LegendMargin; + break; + case LegendPosition.BottomLeft: + case LegendPosition.BottomCenter: + case LegendPosition.BottomRight: + top = this.PlotAndAxisArea.Bottom + this.LegendMargin; + break; + } + + switch (this.LegendPosition) + { + case LegendPosition.TopLeft: + case LegendPosition.BottomLeft: + left = this.PlotArea.Left; + break; + case LegendPosition.TopRight: + case LegendPosition.BottomRight: + left = this.PlotArea.Right - legendSize.Width; + break; + case LegendPosition.LeftTop: + case LegendPosition.RightTop: + top = this.PlotArea.Top; + break; + case LegendPosition.LeftBottom: + case LegendPosition.RightBottom: + top = this.PlotArea.Bottom - legendSize.Height; + break; + case LegendPosition.LeftMiddle: + case LegendPosition.RightMiddle: + top = (this.PlotArea.Top + this.PlotArea.Bottom - legendSize.Height) * 0.5; + break; + case LegendPosition.TopCenter: + case LegendPosition.BottomCenter: + left = (this.PlotArea.Left + this.PlotArea.Right - legendSize.Width) * 0.5; + break; + } + } + else + { + switch (this.LegendPosition) + { + case LegendPosition.LeftTop: + case LegendPosition.LeftMiddle: + case LegendPosition.LeftBottom: + left = this.PlotArea.Left + this.LegendMargin; + break; + case LegendPosition.RightTop: + case LegendPosition.RightMiddle: + case LegendPosition.RightBottom: + left = this.PlotArea.Right - legendSize.Width - this.LegendMargin; + break; + case LegendPosition.TopLeft: + case LegendPosition.TopCenter: + case LegendPosition.TopRight: + top = this.PlotArea.Top + this.LegendMargin; + break; + case LegendPosition.BottomLeft: + case LegendPosition.BottomCenter: + case LegendPosition.BottomRight: + top = this.PlotArea.Bottom - legendSize.Height - this.LegendMargin; + break; + } + + switch (this.LegendPosition) + { + case LegendPosition.TopLeft: + case LegendPosition.BottomLeft: + left = this.PlotArea.Left + this.LegendMargin; + break; + case LegendPosition.TopRight: + case LegendPosition.BottomRight: + left = this.PlotArea.Right - legendSize.Width - this.LegendMargin; + break; + case LegendPosition.LeftTop: + case LegendPosition.RightTop: + top = this.PlotArea.Top + this.LegendMargin; + break; + case LegendPosition.LeftBottom: + case LegendPosition.RightBottom: + top = this.PlotArea.Bottom - legendSize.Height - this.LegendMargin; + break; + + case LegendPosition.LeftMiddle: + case LegendPosition.RightMiddle: + top = (this.PlotArea.Top + this.PlotArea.Bottom - legendSize.Height) * 0.5; + break; + case LegendPosition.TopCenter: + case LegendPosition.BottomCenter: + left = (this.PlotArea.Left + this.PlotArea.Right - legendSize.Width) * 0.5; + break; + } + } + + return new OxyRect(left, top, legendSize.Width, legendSize.Height); + } + + /// + /// Renders the legend for the specified series. + /// + /// + /// The render context. + /// + /// + /// The series. + /// + /// + /// The position and size of the legend. + /// + private void RenderLegend(IRenderContext rc, Series.Series s, OxyRect rect) + { + double x = rect.Left; + switch (this.LegendItemAlignment) + { + case HorizontalAlignment.Center: + x = (rect.Left + rect.Right) / 2; + if (this.LegendSymbolPlacement == LegendSymbolPlacement.Left) + { + x -= (this.LegendSymbolLength + this.LegendSymbolMargin) / 2; + } + else + { + x -= (this.LegendSymbolLength + this.LegendSymbolMargin) / 2; + } + + break; + case HorizontalAlignment.Right: + x = rect.Right; + + // if (LegendSymbolPlacement == LegendSymbolPlacement.Right) + x -= this.LegendSymbolLength + this.LegendSymbolMargin; + break; + } + + if (this.LegendSymbolPlacement == LegendSymbolPlacement.Left) + { + x += this.LegendSymbolLength + this.LegendSymbolMargin; + } + + double y = rect.Top; + var maxsize = new OxySize(Math.Max(rect.Right - x, 0), Math.Max(rect.Bottom - y, 0)); + + var textSize = rc.DrawMathText( + new ScreenPoint(x, y), + s.Title, + this.LegendTextColor ?? this.TextColor, + this.LegendFont ?? this.DefaultFont, + this.LegendFontSize, + this.LegendFontWeight, + 0, + this.LegendItemAlignment, + VerticalAlignment.Top, + maxsize, + true); + double x0 = x; + switch (this.LegendItemAlignment) + { + case HorizontalAlignment.Center: + x0 = x - (textSize.Width * 0.5); + break; + case HorizontalAlignment.Right: + x0 = x - textSize.Width; + break; + } + + var symbolRect = + new OxyRect( + this.LegendSymbolPlacement == LegendSymbolPlacement.Right + ? x0 + textSize.Width + this.LegendSymbolMargin + : x0 - this.LegendSymbolMargin - this.LegendSymbolLength, + rect.Top, + this.LegendSymbolLength, + textSize.Height); + + s.RenderLegend(rc, symbolRect); + } + + /// + /// Measures the legends. + /// + /// + /// The render context. + /// + /// + /// The available size for the legend box. + /// + /// + /// The size of the legend box. + /// + private OxySize MeasureLegends(IRenderContext rc, OxySize availableSize) + { + return this.RenderOrMeasureLegends(rc, new OxyRect(0, 0, availableSize.Width, availableSize.Height), true); + } + + /// + /// Renders or measures the legends. + /// + /// + /// The render context. + /// + /// + /// The rectangle. + /// + private void RenderLegends(IRenderContext rc, OxyRect rect) + { + this.RenderOrMeasureLegends(rc, rect); + } + + /// + /// Renders or measures the legends. + /// + /// + /// The render context. + /// + /// + /// Provides the available size if measuring, otherwise it provides the position and size of the legend. + /// + /// + /// Specify if the size of the legend box should be measured only (not rendered). + /// + /// + /// The size of the legend box. + /// + private OxySize RenderOrMeasureLegends(IRenderContext rc, OxyRect rect, bool measureOnly = false) + { + // Render background and border around legend + if (!measureOnly && rect.Width > 0 && rect.Height > 0) + { + rc.DrawRectangleAsPolygon(rect, this.LegendBackground, this.LegendBorder, this.LegendBorderThickness); + } + + double availableWidth = rect.Width; + double availableHeight = rect.Height; + + double x = this.LegendPadding; + double top = this.LegendPadding; + + var size = new OxySize(); + + // Render/measure the legend title + if (!string.IsNullOrEmpty(this.LegendTitle)) + { + OxySize titleSize; + if (measureOnly) + { + titleSize = rc.MeasureMathText( + this.LegendTitle, + this.LegendTitleFont ?? DefaultFont, + this.LegendTitleFontSize, + this.LegendTitleFontWeight); + } + else + { + titleSize = rc.DrawMathText( + new ScreenPoint(rect.Left + x, rect.Top + top), + this.LegendTitle, + this.LegendTitleColor ?? this.TextColor, + this.LegendTitleFont ?? this.DefaultFont, + this.LegendTitleFontSize, + this.LegendTitleFontWeight, + 0, + HorizontalAlignment.Left, + VerticalAlignment.Top, + null, + true); + } + + top += titleSize.Height; + size.Width = x + titleSize.Width + this.LegendPadding; + size.Height = top + titleSize.Height; + } + + double y = top; + + double lineHeight = 0; + + // tolerance for floating-point number comparisons + const double Epsilon = 1e-3; + + // the maximum item with in the column being rendered (only used for vertical orientation) + double maxItemWidth = 0; + + var items = this.LegendItemOrder == LegendItemOrder.Reverse ? this.VisibleSeries.Reverse() : this.VisibleSeries; + + // When orientation is vertical and alignment is center or right, the items cannot be rendered before + // the max item width has been calculated. Render the items for each column, and at the end. + var seriesToRender = new Dictionary(); + Action renderItems = () => + { + foreach (var sr in seriesToRender) + { + var itemRect = sr.Value; + var itemSeries = sr.Key; + + double rwidth = itemRect.Width; + if (itemRect.Left + rwidth + this.LegendPadding > rect.Left + availableWidth) + { + rwidth = rect.Left + availableWidth - itemRect.Left - this.LegendPadding; + } + + double rheight = itemRect.Height; + if (rect.Top + rheight + this.LegendPadding > rect.Top + availableHeight) + { + rheight = rect.Top + availableHeight - rect.Top - this.LegendPadding; + } + + var r = new OxyRect(itemRect.Left, itemRect.Top, Math.Max(rwidth, 0), Math.Max(rheight, 0)); + this.RenderLegend(rc, itemSeries, r); + } + + seriesToRender.Clear(); + }; + + foreach (var s in items) + { + // Skip series with empty title + if (string.IsNullOrEmpty(s.Title)) + { + continue; + } + + var textSize = rc.MeasureMathText(s.Title, this.LegendFont ?? DefaultFont, this.LegendFontSize, this.LegendFontWeight); + double itemWidth = this.LegendSymbolLength + this.LegendSymbolMargin + textSize.Width; + double itemHeight = textSize.Height; + + if (this.LegendOrientation == LegendOrientation.Horizontal) + { + // Add spacing between items + if (x > this.LegendPadding) + { + x += this.LegendItemSpacing; + } + + // Check if the item is too large to fit within the available width + if (x + itemWidth > availableWidth - this.LegendPadding + Epsilon) + { + // new line + x = this.LegendPadding; + y += lineHeight; + lineHeight = 0; + } + + // Update the max size of the current line + lineHeight = Math.Max(lineHeight, textSize.Height); + + if (!measureOnly) + { + seriesToRender.Add(s, new OxyRect(rect.Left + x, rect.Top + y, itemWidth, itemHeight)); + } + + x += itemWidth; + + // Update the max width of the legend box + size.Width = Math.Max(size.Width, x); + + // Update the max height of the legend box + size.Height = Math.Max(size.Height, y + textSize.Height); + } + else + { + if (y + itemHeight > availableHeight - this.LegendPadding + Epsilon) + { + renderItems(); + + y = top; + x += maxItemWidth + this.LegendColumnSpacing; + maxItemWidth = 0; + } + + if (!measureOnly) + { + seriesToRender.Add(s, new OxyRect(rect.Left + x, rect.Top + y, itemWidth, itemHeight)); + } + + y += itemHeight; + + // Update the max size of the items in the current column + maxItemWidth = Math.Max(maxItemWidth, itemWidth); + + // Update the max width of the legend box + size.Width = Math.Max(size.Width, x + itemWidth); + + // Update the max height of the legend box + size.Height = Math.Max(size.Height, y); + } + } + + renderItems(); + + if (size.Width > 0) + { + size.Width += this.LegendPadding; + } + + if (size.Height > 0) + { + size.Height += this.LegendPadding; + } + + if (size.Width > availableWidth) + { + size.Width = availableWidth; + } + + if (size.Height > availableHeight) + { + size.Height = availableHeight; + } + + if (!double.IsNaN(LegendMaxWidth) && size.Width > this.LegendMaxWidth) + { + size.Width = this.LegendMaxWidth; + } + + return size; + } + } +} \ No newline at end of file diff -r 88d699a65cc2 -r 5be8f2773237 External/OxyPlot/OxyPlot/PlotModel/PlotModel.MouseEvents.cs --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/External/OxyPlot/OxyPlot/PlotModel/PlotModel.MouseEvents.cs Sat Jun 08 16:53:22 2013 +0000 @@ -0,0 +1,202 @@ +// -------------------------------------------------------------------------------------------------------------------- +// +// The MIT License (MIT) +// +// Copyright (c) 2012 Oystein Bjorke +// +// Permission is hereby granted, free of charge, to any person obtaining a +// copy of this software and associated documentation files (the +// "Software"), to deal in the Software without restriction, including +// without limitation the rights to use, copy, modify, merge, publish, +// distribute, sublicense, and/or sell copies of the Software, and to +// permit persons to whom the Software is furnished to do so, subject to +// the following conditions: +// +// The above copyright notice and this permission notice shall be included +// in all copies or substantial portions of the Software. +// +// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS +// OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF +// MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. +// IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY +// CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, +// TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE +// SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. +// +// +// Partial PlotModel class - this file contains mouse events and handlers. +// +// -------------------------------------------------------------------------------------------------------------------- +namespace OxyPlot +{ + using System; + using System.Linq; + + public partial class PlotModel + { + /// + /// The mouse hit tolerance. + /// + private const double MouseHitTolerance = 10; + + /// + /// The current mouse events element. + /// + private UIPlotElement currentMouseEventElement; + + /// + /// Occurs when a mouse button is pressed down on the model. + /// + public event EventHandler MouseDown; + + /// + /// Occurs when the mouse is moved on the plot element (only occurs after MouseDown). + /// + public event EventHandler MouseMove; + + /// + /// Occurs when the mouse button is released on the plot element. + /// + public event EventHandler MouseUp; + + /// + /// Handles the mouse down event. + /// + /// + /// The sender. + /// + /// + /// The instance containing the event data. + /// + public void HandleMouseDown(object sender, OxyMouseEventArgs e) + { + // Revert the order to handle the top-level elements first + foreach (var element in this.GetElements().Reverse()) + { + var uiElement = element as UIPlotElement; + if (uiElement == null) + { + continue; + } + + var result = uiElement.HitTest(e.Position, MouseHitTolerance); + if (result != null) + { + e.HitTestResult = result; + uiElement.OnMouseDown(sender, e); + if (e.Handled) + { + this.currentMouseEventElement = uiElement; + } + } + + if (e.Handled) + { + break; + } + } + + if (!e.Handled) + { + this.OnMouseDown(sender, e); + } + } + + /// + /// Handles the mouse move event. + /// + /// + /// The sender. + /// + /// + /// The instance containing the event data. + /// + public void HandleMouseMove(object sender, OxyMouseEventArgs e) + { + if (this.currentMouseEventElement != null) + { + this.currentMouseEventElement.OnMouseMove(sender, e); + } + + if (!e.Handled) + { + this.OnMouseMove(sender, e); + } + } + + /// + /// Handles the mouse up event. + /// + /// + /// The sender. + /// + /// + /// The instance containing the event data. + /// + public void HandleMouseUp(object sender, OxyMouseEventArgs e) + { + if (this.currentMouseEventElement != null) + { + this.currentMouseEventElement.OnMouseUp(sender, e); + this.currentMouseEventElement = null; + } + + if (!e.Handled) + { + this.OnMouseUp(sender, e); + } + } + + /// + /// Raises the event. + /// + /// + /// The sender. + /// + /// + /// The instance containing the event data. + /// + protected virtual void OnMouseDown(object sender, OxyMouseEventArgs e) + { + if (this.MouseDown != null && !e.Handled) + { + this.MouseDown(sender, e); + } + } + + /// + /// Raises the event. + /// + /// + /// The sender. + /// + /// + /// The instance containing the event data. + /// + protected virtual void OnMouseMove(object sender, OxyMouseEventArgs e) + { + if (this.MouseMove != null) + { + this.MouseMove(sender, e); + } + } + + /// + /// Raises the event. + /// + /// + /// The sender. + /// + /// + /// The instance containing the event data. + /// + protected virtual void OnMouseUp(object sender, OxyMouseEventArgs e) + { + if (this.MouseUp != null) + { + this.MouseUp(sender, e); + } + } + + } +} \ No newline at end of file diff -r 88d699a65cc2 -r 5be8f2773237 External/OxyPlot/OxyPlot/PlotModel/PlotModel.Rendering.cs --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/External/OxyPlot/OxyPlot/PlotModel/PlotModel.Rendering.cs Sat Jun 08 16:53:22 2013 +0000 @@ -0,0 +1,481 @@ +// -------------------------------------------------------------------------------------------------------------------- +// +// The MIT License (MIT) +// +// Copyright (c) 2012 Oystein Bjorke +// +// Permission is hereby granted, free of charge, to any person obtaining a +// copy of this software and associated documentation files (the +// "Software"), to deal in the Software without restriction, including +// without limitation the rights to use, copy, modify, merge, publish, +// distribute, sublicense, and/or sell copies of the Software, and to +// permit persons to whom the Software is furnished to do so, subject to +// the following conditions: +// +// The above copyright notice and this permission notice shall be included +// in all copies or substantial portions of the Software. +// +// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS +// OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF +// MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. +// IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY +// CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, +// TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE +// SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. +// +// +// Partial PlotModel class - this file contains rendering methods. +// +// -------------------------------------------------------------------------------------------------------------------- +namespace OxyPlot +{ + using System; + using System.Collections.Generic; + using System.Linq; + + using OxyPlot.Annotations; + using OxyPlot.Axes; + using OxyPlot.Series; + + public partial class PlotModel + { + /// + /// Renders the plot with the specified rendering context. + /// + /// The rendering context. + /// The width. + /// The height. + public void Render(IRenderContext rc, double width, double height) + { + lock (this.syncRoot) + { + if (width <= 0 || height <= 0) + { + return; + } + + this.Width = width; + this.Height = height; + + this.ActualPlotMargins = this.PlotMargins; + this.EnsureLegendProperties(); + + while (true) + { + this.UpdatePlotArea(rc); + this.UpdateAxisTransforms(); + this.UpdateIntervals(); + if (!this.AutoAdjustPlotMargins) + { + break; + } + + if (!this.AdjustPlotMargins(rc)) + { + break; + } + } + + if (this.PlotType == PlotType.Cartesian) + { + this.EnforceCartesianTransforms(); + this.UpdateIntervals(); + } + + this.RenderBackgrounds(rc); + this.RenderAnnotations(rc, AnnotationLayer.BelowAxes); + this.RenderAxes(rc, AxisLayer.BelowSeries); + this.RenderAnnotations(rc, AnnotationLayer.BelowSeries); + this.RenderSeries(rc); + this.RenderAnnotations(rc, AnnotationLayer.AboveSeries); + this.RenderTitle(rc); + this.RenderBox(rc); + this.RenderAxes(rc, AxisLayer.AboveSeries); + + if (this.IsLegendVisible) + { + this.RenderLegends(rc, this.LegendArea); + } + } + } + + /// + /// Calculates the maximum size of the specified axes. + /// + /// + /// The render context. + /// + /// + /// The axes of position tier. + /// + /// + /// The maximum size. + /// + private static double MaxSizeOfPositionTier(IRenderContext rc, IEnumerable axesOfPositionTier) + { + double maxSizeOfPositionTier = 0; + foreach (var axis in axesOfPositionTier) + { + OxySize size = axis.Measure(rc); + if (axis.IsHorizontal()) + { + if (size.Height > maxSizeOfPositionTier) + { + maxSizeOfPositionTier = size.Height; + } + } + else + { + if (size.Width > maxSizeOfPositionTier) + { + maxSizeOfPositionTier = size.Width; + } + } + } + + return maxSizeOfPositionTier; + } + + /// + /// Adjust the plot margins. + /// + /// + /// The render context. + /// + /// + /// The adjust plot margins. + /// + private bool AdjustPlotMargins(IRenderContext rc) + { + bool isAdjusted = false; + var newPlotMargins = new Dictionary + { + { AxisPosition.Left, this.ActualPlotMargins.Left }, + { AxisPosition.Top, this.ActualPlotMargins.Top }, + { AxisPosition.Right, this.ActualPlotMargins.Right }, + { AxisPosition.Bottom, this.ActualPlotMargins.Bottom } + }; + + for (var position = AxisPosition.Left; position <= AxisPosition.Bottom; position++) + { + double maxValueOfPositionTier = 0; + var axesOfPosition = this.Axes.Where(a => a.Position == position).ToList(); + foreach (var positionTier in axesOfPosition.Select(a => a.PositionTier).Distinct().OrderBy(l => l)) + { + var axesOfPositionTier = axesOfPosition.Where(a => a.PositionTier == positionTier).ToList(); + double maxSizeOfPositionTier = MaxSizeOfPositionTier(rc, axesOfPositionTier); + double minValueOfPositionTier = maxValueOfPositionTier; + + if (Math.Abs(maxValueOfPositionTier) > 1e-5) + { + maxValueOfPositionTier += this.AxisTierDistance; + } + + maxValueOfPositionTier += maxSizeOfPositionTier; + + foreach (Axis axis in axesOfPositionTier) + { + axis.PositionTierSize = maxSizeOfPositionTier; + axis.PositionTierMinShift = minValueOfPositionTier; + axis.PositionTierMaxShift = maxValueOfPositionTier; + } + } + + if (maxValueOfPositionTier > newPlotMargins[position]) + { + newPlotMargins[position] = maxValueOfPositionTier; + isAdjusted = true; + } + } + + if (isAdjusted) + { + this.ActualPlotMargins = new OxyThickness( + newPlotMargins[AxisPosition.Left], + newPlotMargins[AxisPosition.Top], + newPlotMargins[AxisPosition.Right], + newPlotMargins[AxisPosition.Bottom]); + } + + return isAdjusted; + } + + /// + /// Measures the size of the title and subtitle. + /// + /// + /// The rendering context. + /// + /// + /// Size of the titles. + /// + private OxySize MeasureTitles(IRenderContext rc) + { + OxySize size1 = rc.MeasureText(this.Title, this.ActualTitleFont, this.TitleFontSize, this.TitleFontWeight); + OxySize size2 = rc.MeasureText( + this.Subtitle, this.SubtitleFont ?? this.ActualSubtitleFont, this.SubtitleFontSize, this.SubtitleFontWeight); + double height = size1.Height + size2.Height; + double width = Math.Max(size1.Width, size2.Width); + return new OxySize(width, height); + } + + /// + /// Renders the annotations. + /// + /// + /// The render context. + /// + /// + /// The layer. + /// + private void RenderAnnotations(IRenderContext rc, AnnotationLayer layer) + { + foreach (var a in this.Annotations.Where(a => a.Layer == layer)) + { + a.Render(rc, this); + } + } + + /// + /// Renders the axes. + /// + /// + /// The render context. + /// + /// + /// The layer. + /// + private void RenderAxes(IRenderContext rc, AxisLayer layer) + { + for (int i = 0; i < 2; i++) + { + foreach (var a in this.Axes) + { + if (a.IsAxisVisible && a.Layer == layer) + { + a.Render(rc, this, layer, i); + } + } + } + } + + /// + /// Renders the series backgrounds. + /// + /// + /// The render context. + /// + private void RenderBackgrounds(IRenderContext rc) + { + // Render the main background of the plot area (only if there are axes) + // The border is rendered by DrawRectangleAsPolygon to ensure that it is pixel aligned with the tick marks. + if (this.Axes.Count > 0 && this.PlotAreaBackground != null) + { + rc.DrawRectangleAsPolygon(this.PlotArea, this.PlotAreaBackground, null, 0); + } + + foreach (var s in this.VisibleSeries) + { + var s2 = s as XYAxisSeries; + if (s2 == null || s2.Background == null) + { + continue; + } + + rc.DrawRectangle(s2.GetScreenRectangle(), s2.Background, null, 0); + } + } + + /// + /// Renders the border around the plot area. + /// + /// + /// The border will only by rendered if there are axes in the plot. + /// + /// + /// The render context. + /// + private void RenderBox(IRenderContext rc) + { + // The border is rendered by DrawBox to ensure that it is pixel aligned with the tick marks (cannot use DrawRectangle here). + if (this.Axes.Count > 0) + { + rc.DrawRectangleAsPolygon(this.PlotArea, null, this.PlotAreaBorderColor, this.PlotAreaBorderThickness); + } + } + + /// + /// Renders the series. + /// + /// + /// The render context. + /// + private void RenderSeries(IRenderContext rc) + { + // Update undefined colors + this.ResetDefaultColor(); + foreach (var s in this.VisibleSeries) + { + s.SetDefaultValues(this); + } + + foreach (var s in this.VisibleSeries) + { + s.Render(rc, this); + } + } + + /// + /// Renders the title and subtitle. + /// + /// + /// The render context. + /// + private void RenderTitle(IRenderContext rc) + { + OxySize size1 = rc.MeasureText(this.Title, this.ActualTitleFont, this.TitleFontSize, this.TitleFontWeight); + rc.MeasureText( + this.Subtitle, this.SubtitleFont ?? this.ActualSubtitleFont, this.SubtitleFontSize, this.SubtitleFontWeight); + + // double height = size1.Height + size2.Height; + // double dy = (TitleArea.Top+TitleArea.Bottom-height)*0.5; + double dy = this.TitleArea.Top; + double dx = (this.TitleArea.Left + this.TitleArea.Right) * 0.5; + + if (!string.IsNullOrEmpty(this.Title)) + { + rc.DrawMathText( + new ScreenPoint(dx, dy), + this.Title, + this.TitleColor ?? this.TextColor, + this.ActualTitleFont, + this.TitleFontSize, + this.TitleFontWeight, + 0, + HorizontalAlignment.Center, + VerticalAlignment.Top); + dy += size1.Height; + } + + if (!string.IsNullOrEmpty(this.Subtitle)) + { + rc.DrawMathText( + new ScreenPoint(dx, dy), + this.Subtitle, + this.SubtitleColor ?? this.TextColor, + this.ActualSubtitleFont, + this.SubtitleFontSize, + this.SubtitleFontWeight, + 0, + HorizontalAlignment.Center, + VerticalAlignment.Top); + } + } + + /// + /// Calculates the plot area (subtract padding, title size and outside legends) + /// + /// + /// The rendering context. + /// + private void UpdatePlotArea(IRenderContext rc) + { + var plotArea = new OxyRect( + this.Padding.Left, + this.Padding.Top, + this.Width - this.Padding.Left - this.Padding.Right, + this.Height - this.Padding.Top - this.Padding.Bottom); + + var titleSize = this.MeasureTitles(rc); + + if (titleSize.Height > 0) + { + double titleHeight = titleSize.Height + this.TitlePadding; + plotArea.Height -= titleHeight; + plotArea.Top += titleHeight; + } + + plotArea.Top += this.ActualPlotMargins.Top; + plotArea.Height -= this.ActualPlotMargins.Top; + + plotArea.Height -= this.ActualPlotMargins.Bottom; + + plotArea.Left += this.ActualPlotMargins.Left; + plotArea.Width -= this.ActualPlotMargins.Left; + + plotArea.Width -= this.ActualPlotMargins.Right; + + // Find the available size for the legend box + double availableLegendWidth = plotArea.Width; + double availableLegendHeight = plotArea.Height; + if (this.LegendPlacement == LegendPlacement.Inside) + { + availableLegendWidth -= this.LegendMargin * 2; + availableLegendHeight -= this.LegendMargin * 2; + } + + if (availableLegendWidth < 0) + { + availableLegendWidth = 0; + } + + if (availableLegendHeight < 0) + { + availableLegendHeight = 0; + } + + // Calculate the size of the legend box + var legendSize = this.MeasureLegends(rc, new OxySize(availableLegendWidth, availableLegendHeight)); + + // Adjust the plot area after the size of the legend box has been calculated + if (this.IsLegendVisible && this.LegendPlacement == LegendPlacement.Outside) + { + switch (this.LegendPosition) + { + case LegendPosition.LeftTop: + case LegendPosition.LeftMiddle: + case LegendPosition.LeftBottom: + plotArea.Left += legendSize.Width + this.LegendMargin; + plotArea.Width -= legendSize.Width + this.LegendMargin; + break; + case LegendPosition.RightTop: + case LegendPosition.RightMiddle: + case LegendPosition.RightBottom: + plotArea.Width -= legendSize.Width + this.LegendMargin; + break; + case LegendPosition.TopLeft: + case LegendPosition.TopCenter: + case LegendPosition.TopRight: + plotArea.Top += legendSize.Height + this.LegendMargin; + plotArea.Height -= legendSize.Height + this.LegendMargin; + break; + case LegendPosition.BottomLeft: + case LegendPosition.BottomCenter: + case LegendPosition.BottomRight: + plotArea.Height -= legendSize.Height + this.LegendMargin; + break; + } + } + + // Ensure the plot area is valid + if (plotArea.Height < 0) + { + plotArea.Bottom = plotArea.Top + 1; + } + + if (plotArea.Width < 0) + { + plotArea.Right = plotArea.Left + 1; + } + + this.PlotArea = plotArea; + this.PlotAndAxisArea = new OxyRect( + plotArea.Left - this.ActualPlotMargins.Left, + plotArea.Top - this.ActualPlotMargins.Top, + plotArea.Width + this.ActualPlotMargins.Left + this.ActualPlotMargins.Right, + plotArea.Height + this.ActualPlotMargins.Top + this.ActualPlotMargins.Bottom); + this.TitleArea = new OxyRect(this.PlotArea.Left, this.Padding.Top, this.PlotArea.Width, titleSize.Height + (this.TitlePadding * 2)); + this.LegendArea = this.GetLegendRectangle(legendSize); + } + } +} \ No newline at end of file diff -r 88d699a65cc2 -r 5be8f2773237 External/OxyPlot/OxyPlot/PlotModel/PlotModel.cs --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/External/OxyPlot/OxyPlot/PlotModel/PlotModel.cs Sat Jun 08 16:53:22 2013 +0000 @@ -0,0 +1,1485 @@ +// -------------------------------------------------------------------------------------------------------------------- +// +// The MIT License (MIT) +// +// Copyright (c) 2012 Oystein Bjorke +// +// Permission is hereby granted, free of charge, to any person obtaining a +// copy of this software and associated documentation files (the +// "Software"), to deal in the Software without restriction, including +// without limitation the rights to use, copy, modify, merge, publish, +// distribute, sublicense, and/or sell copies of the Software, and to +// permit persons to whom the Software is furnished to do so, subject to +// the following conditions: +// +// The above copyright notice and this permission notice shall be included +// in all copies or substantial portions of the Software. +// +// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS +// OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF +// MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. +// IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY +// CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, +// TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE +// SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. +// +// +// Plot coordinate system type +// +// -------------------------------------------------------------------------------------------------------------------- +namespace OxyPlot +{ + using System; + using System.Collections.Generic; + using System.Collections.ObjectModel; + using System.Diagnostics; + using System.Globalization; + using System.IO; + using System.Linq; + using System.Reflection; + + using OxyPlot.Annotations; + using OxyPlot.Axes; + using OxyPlot.Reporting; + using OxyPlot.Series; + + /// + /// Specifies the coordinate system type. + /// + public enum PlotType + { + /// + /// XY coordinate system - two perpendicular axes + /// + XY, + + /// + /// Cartesian coordinate system - perpendicular axes with the same scaling. + /// + /// + /// See http://en.wikipedia.org/wiki/Cartesian_coordinate_system + /// + Cartesian, + + /// + /// Polar coordinate system - with radial and angular axes + /// + /// + /// See http://en.wikipedia.org/wiki/Polar_coordinate_system + /// + Polar + } + + /// + /// Specifies the placement of the legend box. + /// + public enum LegendPlacement + { + /// + /// Place the legends inside the plot area. + /// + Inside, + + /// + /// Place the legends outside the plot area. + /// + Outside + } + + /// + /// Specifies the position of the legend box. + /// + public enum LegendPosition + { + /// + /// Place the legend box in the top-left corner. + /// + TopLeft, + + /// + /// Place the legend box centered at the top. + /// + TopCenter, + + /// + /// Place the legend box in the top-right corner. + /// + TopRight, + + /// + /// Place the legend box in the bottom-left corner. + /// + BottomLeft, + + /// + /// Place the legend box centered at the bottom. + /// + BottomCenter, + + /// + /// Place the legend box in the bottom-right corner. + /// + BottomRight, + + /// + /// Place the legend box in the left-top corner. + /// + LeftTop, + + /// + /// Place the legend box centered at the left. + /// + LeftMiddle, + + /// + /// Place the legend box in the left-bottom corner. + /// + LeftBottom, + + /// + /// Place the legend box in the right-top corner. + /// + RightTop, + + /// + /// Place the legend box centered at the right. + /// + RightMiddle, + + /// + /// Place the legend box in the right-bottom corner. + /// + RightBottom + } + + /// + /// Specifies the orientation of the items in the legend box. + /// + public enum LegendOrientation + { + /// + /// Orient the items horizontally. + /// + Horizontal, + + /// + /// Orient the items vertically. + /// + Vertical + } + + /// + /// Specifies the item order of the legends. + /// + public enum LegendItemOrder + { + /// + /// Render the items in the normal order. + /// + Normal, + + /// + /// Render the items in the reverse order. + /// + Reverse + } + + /// + /// Specifies the placement of the legend symbols. + /// + public enum LegendSymbolPlacement + { + /// + /// Render symbols to the left of the labels. + /// + Left, + + /// + /// Render symbols to the right of the labels. + /// + Right + } + + /// + /// Represents a plot (including axes, series and annotations). + /// + public partial class PlotModel + { + /// + /// The default selection color. + /// + internal static readonly OxyColor DefaultSelectionColor = OxyColors.Yellow; + + /// + /// The default font. + /// + private const string PrivateDefaultFont = "Segoe UI"; + + /// + /// The current color index. + /// + private int currentColorIndex; + + /// + /// Initializes a new instance of the class. + /// + public PlotModel() + { + this.Axes = new Collection(); + this.Series = new Collection(); + this.Annotations = new Collection(); + + this.PlotType = PlotType.XY; + + this.PlotMargins = new OxyThickness(60, 4, 4, 40); + this.Padding = new OxyThickness(8, 8, 16, 8); + this.AutoAdjustPlotMargins = true; + + this.DefaultFont = PrivateDefaultFont; + this.DefaultFontSize = 12; + + this.TitleFont = null; + this.TitleFontSize = 18; + this.TitleFontWeight = FontWeights.Bold; + this.SubtitleFont = null; + this.SubtitleFontSize = 14; + this.SubtitleFontWeight = FontWeights.Normal; + this.TitlePadding = 6; + + this.TextColor = OxyColors.Black; + this.PlotAreaBorderColor = OxyColors.Black; + this.PlotAreaBorderThickness = 1; + + this.IsLegendVisible = true; + this.LegendTitleFont = null; + this.LegendTitleFontSize = 12; + this.LegendTitleFontWeight = FontWeights.Bold; + this.LegendFont = null; + this.LegendFontSize = 12; + this.LegendFontWeight = FontWeights.Normal; + this.LegendSymbolLength = 16; + this.LegendSymbolMargin = 4; + this.LegendPadding = 8; + this.LegendColumnSpacing = 8; + this.LegendItemSpacing = 24; + this.LegendMargin = 8; + + this.LegendBackground = null; + this.LegendBorder = null; + this.LegendBorderThickness = 1; + + this.LegendMaxWidth = double.NaN; + this.LegendPlacement = LegendPlacement.Inside; + this.LegendPosition = LegendPosition.RightTop; + this.LegendOrientation = LegendOrientation.Vertical; + this.LegendItemOrder = LegendItemOrder.Normal; + this.LegendItemAlignment = HorizontalAlignment.Left; + this.LegendSymbolPlacement = LegendSymbolPlacement.Left; + + this.DefaultColors = new List + { + OxyColor.FromRgb(0x4E, 0x9A, 0x06), + OxyColor.FromRgb(0xC8, 0x8D, 0x00), + OxyColor.FromRgb(0xCC, 0x00, 0x00), + OxyColor.FromRgb(0x20, 0x4A, 0x87), + OxyColors.Red, + OxyColors.Orange, + OxyColors.Yellow, + OxyColors.Green, + OxyColors.Blue, + OxyColors.Indigo, + OxyColors.Violet + }; + + this.AxisTierDistance = 4.0; + } + + /// + /// Initializes a new instance of the class. + /// + /// + /// The title. + /// + /// + /// The subtitle. + /// + public PlotModel(string title, string subtitle = null) + : this() + { + this.Title = title; + this.Subtitle = subtitle; + } + + /// + /// The synchronization root object. + /// + private object syncRoot = new object(); + + /// + /// Gets an object that can be used to synchronize access to the PlotModel. + /// + /// The sync root. + public object SyncRoot { get { return this.syncRoot; } } + + /// + /// Occurs when the plot has been updated. + /// + public event EventHandler Updated; + + /// + /// Occurs when the plot is about to be updated. + /// + public event EventHandler Updating; + + /// + /// Gets or sets the default font. + /// + /// The default font. + /// + /// This font is used for text on axes, series, legends and plot titles unless other fonts are specified. + /// + public string DefaultFont { get; set; } + + /// + /// Gets or sets the default size of the fonts. + /// + /// + /// The default size of the font. + /// + public double DefaultFontSize { get; set; } + + /// + /// Gets the actual culture. + /// + public CultureInfo ActualCulture + { + get + { + return this.Culture ?? CultureInfo.CurrentCulture; + } + } + + /// + /// Gets the actual plot margins. + /// + /// The actual plot margins. + public OxyThickness ActualPlotMargins { get; private set; } + + /// + /// Gets the plot control that renders this plot. + /// + /// + /// Only one PlotControl can render the plot at the same time. + /// + /// The plot control. + public IPlotControl PlotControl { get; private set; } + + /// + /// Gets or sets the annotations. + /// + /// The annotations. + public Collection Annotations { get; set; } + + /// + /// Gets or sets a value indicating whether to auto adjust plot margins. + /// + public bool AutoAdjustPlotMargins { get; set; } + + /// + /// Gets or sets the axes. + /// + /// The axes. + public Collection Axes { get; set; } + + /// + /// Gets or sets the color of the background of the plot. + /// + public OxyColor Background { get; set; } + + /// + /// Gets or sets the culture. + /// + /// The culture. + public CultureInfo Culture { get; set; } + + /// + /// Gets or sets the default colors. + /// + /// The default colors. + public IList DefaultColors { get; set; } + + /// + /// Gets or sets a value indicating whether the legend is visible. The titles of the series must be set to use the legend. + /// + public bool IsLegendVisible { get; set; } + + /// + /// Gets the legend area. + /// + /// The legend area. + public OxyRect LegendArea { get; private set; } + + /// + /// Gets or sets the background color of the legend. Use null for no background. + /// + /// The legend background. + public OxyColor LegendBackground { get; set; } + + /// + /// Gets or sets the border color of the legend. + /// + /// The legend border. + public OxyColor LegendBorder { get; set; } + + /// + /// Gets or sets the thickness of the legend border. Use 0 for no border. + /// + /// The legend border thickness. + public double LegendBorderThickness { get; set; } + + /// + /// Gets or sets the legend column spacing. + /// + /// The legend column spacing. + public double LegendColumnSpacing { get; set; } + + /// + /// Gets or sets the legend font. + /// + /// The legend font. + public string LegendFont { get; set; } + + /// + /// Gets or sets the size of the legend font. + /// + /// The size of the legend font. + public double LegendFontSize { get; set; } + + /// + /// Gets or sets the color of the legend text. + /// + /// + /// The color of the legend text. + /// + /// + /// If this value is null, the TextColor will be used. + /// + public OxyColor LegendTextColor { get; set; } + + /// + /// Gets or sets the legend font weight. + /// + /// The legend font weight. + public double LegendFontWeight { get; set; } + + /// + /// Gets or sets the legend item alignment. + /// + /// The legend item alignment. + public HorizontalAlignment LegendItemAlignment { get; set; } + + /// + /// Gets or sets the legend item order. + /// + /// The legend item order. + public LegendItemOrder LegendItemOrder { get; set; } + + /// + /// Gets or sets the legend spacing. + /// + /// The legend spacing. + public double LegendItemSpacing { get; set; } + + /// + /// Gets or sets the legend margin. + /// + /// The legend margin. + public double LegendMargin { get; set; } + + /// + /// Gets or sets the max width of the legend. + /// + /// The max width of the legend. + public double LegendMaxWidth { get; set; } + + /// + /// Gets or sets the legend orientation. + /// + /// The legend orientation. + public LegendOrientation LegendOrientation { get; set; } + + /// + /// Gets or sets the legend padding. + /// + /// The legend padding. + public double LegendPadding { get; set; } + + /// + /// Gets or sets the legend placement. + /// + /// The legend placement. + public LegendPlacement LegendPlacement { get; set; } + + /// + /// Gets or sets the legend position. + /// + /// The legend position. + public LegendPosition LegendPosition { get; set; } + + /// + /// Gets or sets the length of the legend symbols (the default value is 16). + /// + public double LegendSymbolLength { get; set; } + + /// + /// Gets or sets the legend symbol margins (distance between the symbol and the text). + /// + /// The legend symbol margin. + public double LegendSymbolMargin { get; set; } + + /// + /// Gets or sets the legend symbol placement. + /// + /// The legend symbol placement. + public LegendSymbolPlacement LegendSymbolPlacement { get; set; } + + /// + /// Gets or sets the legend title. + /// + /// The legend title. + public string LegendTitle { get; set; } + + /// + /// Gets or sets the color of the legend title. + /// + /// + /// The color of the legend title. + /// + /// + /// If this value is null, the TextColor will be used. + /// + public OxyColor LegendTitleColor { get; set; } + + /// + /// Gets or sets the legend title font. + /// + /// The legend title font. + public string LegendTitleFont { get; set; } + + /// + /// Gets or sets the size of the legend title font. + /// + /// The size of the legend title font. + public double LegendTitleFontSize { get; set; } + + /// + /// Gets or sets the legend title font weight. + /// + /// The legend title font weight. + public double LegendTitleFontWeight { get; set; } + + /// + /// Gets or sets the padding around the plot. + /// + /// The padding. + public OxyThickness Padding { get; set; } + + /// + /// Gets the total width of the plot (in device units). + /// + public double Width { get; private set; } + + /// + /// Gets the total height of the plot (in device units). + /// + public double Height { get; private set; } + + /// + /// Gets the area including both the plot and the axes. Outside legends are rendered outside this rectangle. + /// + /// The plot and axis area. + public OxyRect PlotAndAxisArea { get; private set; } + + /// + /// Gets the plot area. This area is used to draw the series (not including axes or legends). + /// + /// The plot area. + public OxyRect PlotArea { get; private set; } + + /// + /// Gets or sets the distance between two neighbourhood tiers of the same AxisPosition. + /// + public double AxisTierDistance { get; set; } + + /// + /// Gets or sets the color of the background of the plot area. + /// + public OxyColor PlotAreaBackground { get; set; } + + /// + /// Gets or sets the color of the border around the plot area. + /// + /// The color of the box. + public OxyColor PlotAreaBorderColor { get; set; } + + /// + /// Gets or sets the thickness of the border around the plot area. + /// + /// The box thickness. + public double PlotAreaBorderThickness { get; set; } + + /// + /// Gets or sets the minimum margins around the plot (this should be large enough to fit the axes). The default value is (60, 4, 4, 40). Set AutoAdjustPlotMargins if you want the margins to be adjusted when the axes require more space. + /// + public OxyThickness PlotMargins { get; set; } + + /// + /// Gets or sets the type of the coordinate system. + /// + /// The type of the plot. + public PlotType PlotType { get; set; } + + /// + /// Gets or sets the color of the selection. + /// + /// + /// The color of the selection. + /// + public OxyColor SelectionColor { get; set; } + + /// + /// Gets or sets the series. + /// + /// The series. + public Collection Series { get; set; } + + /// + /// Gets or sets the subtitle. + /// + /// The subtitle. + public string Subtitle { get; set; } + + /// + /// Gets or sets the subtitle font. If this property is null, the Title font will be used. + /// + /// The subtitle font. + public string SubtitleFont { get; set; } + + /// + /// Gets or sets the size of the subtitle font. + /// + /// The size of the subtitle font. + public double SubtitleFontSize { get; set; } + + /// + /// Gets or sets the subtitle font weight. + /// + /// The subtitle font weight. + public double SubtitleFontWeight { get; set; } + + /// + /// Gets or sets the default color of the text in the plot (titles, legends, annotations, axes). + /// + /// The color of the text. + public OxyColor TextColor { get; set; } + + /// + /// Gets or sets the title. + /// + /// The title. + public string Title { get; set; } + + /// + /// Gets or sets the color of the title. + /// + /// + /// The color of the title. + /// + /// + /// If the value is null, the TextColor will be used. + /// + public OxyColor TitleColor { get; set; } + + /// + /// Gets or sets the color of the subtitle. + /// + /// + /// The color of the subtitle. + /// + public OxyColor SubtitleColor { get; set; } + + /// + /// Gets the title area. + /// + /// The title area. + public OxyRect TitleArea { get; private set; } + + /// + /// Gets or sets the title font. + /// + /// The title font. + public string TitleFont { get; set; } + + /// + /// Gets or sets the size of the title font. + /// + /// The size of the title font. + public double TitleFontSize { get; set; } + + /// + /// Gets or sets the title font weight. + /// + /// The title font weight. + public double TitleFontWeight { get; set; } + + /// + /// Gets or sets the padding around the title. + /// + /// The title padding. + public double TitlePadding { get; set; } + + /// + /// Gets the default angle axis. + /// + /// The default angle axis. + public AngleAxis DefaultAngleAxis { get; private set; } + + /// + /// Gets the default magnitude axis. + /// + /// The default magnitude axis. + public MagnitudeAxis DefaultMagnitudeAxis { get; private set; } + + /// + /// Gets the default X axis. + /// + /// The default X axis. + public Axis DefaultXAxis { get; private set; } + + /// + /// Gets the default Y axis. + /// + /// The default Y axis. + public Axis DefaultYAxis { get; private set; } + + /// + /// Gets the default color axis. + /// + /// The default color axis. + public ColorAxis DefaultColorAxis { get; private set; } + + /// + /// Gets the actual title font. + /// + protected string ActualTitleFont + { + get + { + return this.TitleFont ?? this.DefaultFont; + } + } + + /// + /// Gets the actual subtitle font. + /// + protected string ActualSubtitleFont + { + get + { + return this.SubtitleFont ?? this.DefaultFont; + } + } + + /// + /// Gets the visible series. + /// + /// The visible series. + private IEnumerable VisibleSeries + { + get + { + return this.Series.Where(s => s.IsVisible); + } + } + + /// + /// Attaches this model to the specified plot control. + /// + /// The plot control. + /// + /// Only one plot control can be attached to the plot model. + /// The plot model contains data (e.g. axis scaling) that is only relevant to the current plot control. + /// + public void AttachPlotControl(IPlotControl plotControl) + { + this.PlotControl = plotControl; + } + + /// + /// Creates a report for the plot. + /// + /// + /// A report. + /// + public Report CreateReport() + { + var r = new Report { Culture = CultureInfo.InvariantCulture }; + + r.AddHeader(1, "P L O T R E P O R T"); + r.AddHeader(2, "=== PlotModel ==="); + r.AddPropertyTable("PlotModel", this); + + r.AddHeader(2, "=== Axes ==="); + foreach (Axis a in this.Axes) + { + r.AddPropertyTable(a.GetType().Name, a); + } + + r.AddHeader(2, "=== Annotations ==="); + foreach (var a in this.Annotations) + { + r.AddPropertyTable(a.GetType().Name, a); + } + + r.AddHeader(2, "=== Series ==="); + foreach (var s in this.Series) + { + r.AddPropertyTable(s.GetType().Name, s); + var ds = s as DataPointSeries; + if (ds != null) + { + var fields = new List { new ItemsTableField("X", "X"), new ItemsTableField("Y", "Y") }; + r.AddItemsTable("Data", ds.Points, fields); + } + } + + var assemblyName = new AssemblyName(Assembly.GetExecutingAssembly().FullName); + r.AddParagraph(string.Format("Report generated by OxyPlot {0}", assemblyName.Version.ToString(3))); + + return r; + } + + /// + /// Creates a text report for the plot. + /// + /// + /// The create text report. + /// + public string CreateTextReport() + { + using (var ms = new MemoryStream()) + { + var trw = new TextReportWriter(ms); + Report report = this.CreateReport(); + report.Write(trw); + trw.Flush(); + ms.Position = 0; + var r = new StreamReader(ms); + return r.ReadToEnd(); + } + } + + /// + /// Refreshes the plot. + /// + /// Updates all data sources if set to true. + public void RefreshPlot(bool updateData) + { + if (this.PlotControl == null) + { + return; + } + + this.PlotControl.RefreshPlot(updateData); + } + + /// + /// Invalidates the plot. + /// + /// Updates all data sources if set to true. + public void InvalidatePlot(bool updateData) + { + if (this.PlotControl == null) + { + return; + } + + this.PlotControl.InvalidatePlot(updateData); + } + + /// + /// Gets the first axes that covers the area of the specified point. + /// + /// + /// The point. + /// + /// + /// The xaxis. + /// + /// + /// The yaxis. + /// + public void GetAxesFromPoint(ScreenPoint pt, out Axis xaxis, out Axis yaxis) + { + xaxis = yaxis = null; + + // Get the axis position of the given point. Using null if the point is inside the plot area. + AxisPosition? position = null; + double plotAreaValue = 0; + if (pt.X < this.PlotArea.Left) + { + position = AxisPosition.Left; + plotAreaValue = this.PlotArea.Left; + } + + if (pt.X > this.PlotArea.Right) + { + position = AxisPosition.Right; + plotAreaValue = this.PlotArea.Right; + } + + if (pt.Y < this.PlotArea.Top) + { + position = AxisPosition.Top; + plotAreaValue = this.PlotArea.Top; + } + + if (pt.Y > this.PlotArea.Bottom) + { + position = AxisPosition.Bottom; + plotAreaValue = this.PlotArea.Bottom; + } + + foreach (var axis in this.Axes) + { + if (axis is ColorAxis) + { + continue; + } + + if (axis is MagnitudeAxis) + { + xaxis = axis; + continue; + } + + if (axis is AngleAxis) + { + yaxis = axis; + continue; + } + + double x = double.NaN; + if (axis.IsHorizontal()) + { + x = axis.InverseTransform(pt.X); + } + + if (axis.IsVertical()) + { + x = axis.InverseTransform(pt.Y); + } + + if (x >= axis.ActualMinimum && x <= axis.ActualMaximum) + { + if (position == null) + { + if (axis.IsHorizontal()) + { + if (xaxis == null) + { + xaxis = axis; + } + } + else if (axis.IsVertical()) + { + if (yaxis == null) + { + yaxis = axis; + } + } + } + else if (position == axis.Position) + { + // Choose right tier + double positionTierMinShift = axis.PositionTierMinShift; + double positionTierMaxShift = axis.PositionTierMaxShift; + + double posValue = axis.IsHorizontal() ? pt.Y : pt.X; + bool isLeftOrTop = position == AxisPosition.Top || position == AxisPosition.Left; + if ((posValue >= plotAreaValue + positionTierMinShift + && posValue < plotAreaValue + positionTierMaxShift && !isLeftOrTop) + || + (posValue <= plotAreaValue - positionTierMinShift + && posValue > plotAreaValue - positionTierMaxShift && isLeftOrTop)) + { + if (axis.IsHorizontal()) + { + if (xaxis == null) + { + xaxis = axis; + } + } + else if (axis.IsVertical()) + { + if (yaxis == null) + { + yaxis = axis; + } + } + } + } + } + } + } + + /// + /// Gets the default color from the DefaultColors palette. + /// + /// + /// The next default color. + /// + public OxyColor GetDefaultColor() + { + return this.DefaultColors[this.currentColorIndex++ % this.DefaultColors.Count]; + } + + /// + /// Gets the default line style. + /// + /// + /// The next default line style. + /// + public LineStyle GetDefaultLineStyle() + { + return (LineStyle)((this.currentColorIndex / this.DefaultColors.Count) % (int)LineStyle.None); + } + + /// + /// Gets a series from the specified point. + /// + /// + /// The point. + /// + /// + /// The limit. + /// + /// + /// The nearest series. + /// + public Series.Series GetSeriesFromPoint(ScreenPoint point, double limit) + { + double mindist = double.MaxValue; + Series.Series closest = null; + foreach (var s in this.VisibleSeries.Reverse()) + { + var ts = s as ITrackableSeries; + if (ts == null) + { + continue; + } + + var thr = ts.GetNearestPoint(point, true) ?? ts.GetNearestPoint(point, false); + + if (thr == null) + { + continue; + } + + // find distance to this point on the screen + double dist = point.DistanceTo(thr.Position); + if (dist < mindist) + { + closest = s; + mindist = dist; + } + } + + if (mindist < limit) + { + return closest; + } + + return null; + } + + /// + /// Generates C# code of the model. + /// + /// + /// C# code. + /// + public string ToCode() + { + var cg = new CodeGenerator(this); + return cg.ToCode(); + } + + /// + /// Returns a that represents this instance. + /// + /// + /// A that represents this instance. + /// + public override string ToString() + { + return this.Title; + } + + /// + /// Create an svg model and return it as a string. + /// + /// The width (points). + /// The height (points). + /// if set to true, the xml headers will be included (?xml and !DOCTYPE). + /// The text measurer. + /// The svg string. + public string ToSvg(double width, double height, bool isDocument, IRenderContext textMeasurer) + { + return SvgExporter.ExportToString(this, width, height, isDocument, textMeasurer); + } + + /// + /// Gets all elements of the plot model. + /// + /// An enumerator of the plot elements. + public IEnumerable GetElements() + { + foreach (var axis in this.Axes) + { + yield return axis; + } + + foreach (var annotation in this.Annotations) + { + yield return annotation; + } + + foreach (var s in this.Series) + { + yield return s; + } + } + + /// + /// Updates all axes and series. 0. Updates the owner PlotModel of all plot items (axes, series and annotations) + /// 1. Updates the data of each Series (only if updateData==true). + /// 2. Ensure that all series have axes assigned. + /// 3. Updates the max and min of the axes. + /// + /// + /// if set to true , all data collections will be updated. + /// + public void Update(bool updateData = true) + { + lock (this.syncRoot) + { + this.OnUpdating(); + + // update the owner PlotModel + foreach (var s in this.VisibleSeries) + { + s.PlotModel = this; + } + + foreach (var a in this.Annotations) + { + a.PlotModel = this; + } + + // Updates the default axes + this.EnsureDefaultAxes(); + + // Update data of the series + if (updateData) + { + foreach (var s in this.VisibleSeries) + { + s.UpdateData(); + } + } + + foreach (var a in this.Axes) + { + a.PlotModel = this; + } + + foreach (var c in this.Axes.OfType()) + { + c.UpdateLabels(this.VisibleSeries); + } + + // Update valid data of the series + if (updateData) + { + foreach (var s in this.VisibleSeries) + { + s.UpdateValidData(); + } + } + + // Updates axes with information from the series + // This is used by the category axis that need to know the number of series using the axis. + foreach (var a in this.Axes) + { + a.UpdateFromSeries(this.VisibleSeries); + } + + // Update the max and min of the axes + this.UpdateMaxMin(updateData); + this.OnUpdated(); + } + } + + /// + /// Updates the axis transforms. + /// + public void UpdateAxisTransforms() + { + // Update the axis transforms + foreach (var a in this.Axes) + { + a.UpdateTransform(this.PlotArea); + } + } + + /// + /// Gets the axis for the specified key. + /// + /// The key. + /// The default axis. + /// The axis, or the defaultAxis if the key is not found. + public Axis GetAxisOrDefault(string key, Axis defaultAxis) + { + if (key != null) + { + return this.Axes.FirstOrDefault(a => a.Key == key) ?? defaultAxis; + } + + return defaultAxis; + } + + /// + /// Raises the Updated event. + /// + protected virtual void OnUpdated() + { + var handler = this.Updated; + if (handler != null) + { + var args = new EventArgs(); + handler(this, args); + } + } + + /// + /// Raises the Updating event. + /// + protected virtual void OnUpdating() + { + var handler = this.Updating; + if (handler != null) + { + var args = new EventArgs(); + handler(this, args); + } + } + + /// + /// Enforces the same scale on all axes. + /// + private void EnforceCartesianTransforms() + { + // Set the same scaling on all axes + double sharedScale = this.Axes.Min(a => Math.Abs(a.Scale)); + foreach (var a in this.Axes) + { + a.Zoom(sharedScale); + } + + sharedScale = this.Axes.Max(a => Math.Abs(a.Scale)); + foreach (var a in this.Axes) + { + a.Zoom(sharedScale); + } + + foreach (var a in this.Axes) + { + a.UpdateTransform(this.PlotArea); + } + } + + /// + /// Updates the intervals (major and minor step values). + /// + private void UpdateIntervals() + { + // Update the intervals for all axes + foreach (var a in this.Axes) + { + a.UpdateIntervals(this.PlotArea); + } + } + + /// + /// Finds and sets the default horizontal and vertical axes (the first horizontal/vertical axes in the Axes collection). + /// + private void EnsureDefaultAxes() + { + this.DefaultXAxis = this.Axes.FirstOrDefault(a => a.IsHorizontal() && a.IsXyAxis()); + this.DefaultYAxis = this.Axes.FirstOrDefault(a => a.IsVertical() && a.IsXyAxis()); + this.DefaultMagnitudeAxis = this.Axes.FirstOrDefault(a => a is MagnitudeAxis) as MagnitudeAxis; + this.DefaultAngleAxis = this.Axes.FirstOrDefault(a => a is AngleAxis) as AngleAxis; + this.DefaultColorAxis = this.Axes.FirstOrDefault(a => a is ColorAxis) as ColorAxis; + + if (this.DefaultXAxis == null) + { + this.DefaultXAxis = this.DefaultMagnitudeAxis; + } + + if (this.DefaultYAxis == null) + { + this.DefaultYAxis = this.DefaultAngleAxis; + } + + if (this.PlotType == PlotType.Polar) + { + if (this.DefaultXAxis == null) + { + this.DefaultXAxis = this.DefaultMagnitudeAxis = new MagnitudeAxis(); + } + + if (this.DefaultYAxis == null) + { + this.DefaultYAxis = this.DefaultAngleAxis = new AngleAxis(); + } + } + else + { + bool createdlinearxaxis = false; + bool createdlinearyaxis = false; + if (this.DefaultXAxis == null) + { + if (this.Series.Any(series => series is ColumnSeries)) + { + this.DefaultXAxis = new CategoryAxis { Position = AxisPosition.Bottom }; + } + else + { + this.DefaultXAxis = new LinearAxis { Position = AxisPosition.Bottom }; + createdlinearxaxis = true; + } + } + + if (this.DefaultYAxis == null) + { + if (this.Series.Any(series => series is BarSeries)) + { + this.DefaultYAxis = new CategoryAxis { Position = AxisPosition.Left }; + } + else + { + this.DefaultYAxis = new LinearAxis { Position = AxisPosition.Left }; + createdlinearyaxis = true; + } + } + + if (createdlinearxaxis && this.DefaultYAxis is CategoryAxis) + { + this.DefaultXAxis.MinimumPadding = 0; + } + + if (createdlinearyaxis && this.DefaultXAxis is CategoryAxis) + { + this.DefaultYAxis.MinimumPadding = 0; + } + } + + bool areAxesRequired = false; + foreach (var s in this.VisibleSeries) + { + if (s.AreAxesRequired()) + { + areAxesRequired = true; + } + } + + if (areAxesRequired) + { + if (!this.Axes.Contains(this.DefaultXAxis)) + { + Debug.Assert(this.DefaultXAxis != null, "Default x-axis not created."); + if (this.DefaultXAxis != null) + { + this.Axes.Add(this.DefaultXAxis); + } + } + + if (!this.Axes.Contains(this.DefaultYAxis)) + { + Debug.Assert(this.DefaultYAxis != null, "Default y-axis not created."); + if (this.DefaultYAxis != null) + { + this.Axes.Add(this.DefaultYAxis); + } + } + } + + // Update the x/index axes of series without axes defined + foreach (var s in this.VisibleSeries) + { + if (s.AreAxesRequired()) + { + s.EnsureAxes(); + } + } + + // Update the x/index axes of annotations without axes defined + foreach (var a in this.Annotations) + { + a.EnsureAxes(); + } + } + + /// + /// Resets the default color index. + /// + private void ResetDefaultColor() + { + this.currentColorIndex = 0; + } + + /// + /// Updates maximum and minimum values of the axes from values of all data series. + /// + /// + /// if set to true , the data has been updated. + /// + private void UpdateMaxMin(bool isDataUpdated) + { + if (isDataUpdated) + { + foreach (var a in this.Axes) + { + a.ResetDataMaxMin(); + } + + // data has been updated, so we need to calculate the max/min of the series again + foreach (var s in this.VisibleSeries) + { + s.UpdateMaxMin(); + } + } + + foreach (var s in this.VisibleSeries) + { + s.UpdateAxisMaxMin(); + } + + foreach (var a in this.Axes) + { + a.UpdateActualMaxMin(); + } + } + } +} \ No newline at end of file diff -r 88d699a65cc2 -r 5be8f2773237 External/OxyPlot/OxyPlot/PlotModel/SelectablePlotElement.cs --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/External/OxyPlot/OxyPlot/PlotModel/SelectablePlotElement.cs Sat Jun 08 16:53:22 2013 +0000 @@ -0,0 +1,159 @@ +// -------------------------------------------------------------------------------------------------------------------- +// +// The MIT License (MIT) +// +// Copyright (c) 2012 Oystein Bjorke +// +// Permission is hereby granted, free of charge, to any person obtaining a +// copy of this software and associated documentation files (the +// "Software"), to deal in the Software without restriction, including +// without limitation the rights to use, copy, modify, merge, publish, +// distribute, sublicense, and/or sell copies of the Software, and to +// permit persons to whom the Software is furnished to do so, subject to +// the following conditions: +// +// The above copyright notice and this permission notice shall be included +// in all copies or substantial portions of the Software. +// +// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS +// OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF +// MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. +// IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY +// CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, +// TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE +// SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. +// +// +// Represents a plot element that supports selection. +// +// -------------------------------------------------------------------------------------------------------------------- +namespace OxyPlot +{ + using System; + + /// + /// Provides an abstract base class for plot elements that support selection. + /// + public abstract class SelectablePlotElement : PlotElement + { + /// + /// The is selected. + /// + private bool isSelected; + + /// + /// Initializes a new instance of the class. + /// + protected SelectablePlotElement() + { + this.Selectable = true; + this.IsSelected = false; + } + + /// + /// Occurs when the IsSelected property is changed. + /// + public event EventHandler Selected; + + /// + /// Gets or sets the index of the selected item (or -1 if all items are selected). + /// + /// + /// The index of the selected. + /// + public int SelectedIndex { get; set; } + + /// + /// Gets or sets a value indicating whether this plot element is selected. + /// + public bool IsSelected + { + get + { + return this.isSelected; + } + + set + { + if (value == this.isSelected) + { + return; + } + + this.isSelected = value; + this.OnIsSelectedChanged(); + } + } + + /// + /// Gets or sets a value indicating whether this plot element can be selected. + /// + public bool Selectable { get; set; } + + /// + /// Gets the actual selection color. + /// + /// The actual selection color. + protected OxyColor ActualSelectedColor + { + get + { + if (this.PlotModel != null) + { + return this.PlotModel.SelectionColor ?? PlotModel.DefaultSelectionColor; + } + + return PlotModel.DefaultSelectionColor; + } + } + + /// + /// Gets the selection color it the element is selected, or the specified color if it is not. + /// + /// The unselected color of the element. + /// The index of the item to check (use -1 for all items). + /// + /// A color. + /// + protected OxyColor GetSelectableColor(OxyColor originalColor, int index = -1) + { + if (originalColor == null) + { + return null; + } + + if (this.IsSelected && (index == -1 || index == this.SelectedIndex)) + { + return this.ActualSelectedColor; + } + + return originalColor; + } + + /// + /// Gets the selection fill color it the element is selected, or the specified fill color if it is not. + /// + /// The unselected fill color of the element. + /// The index of the item to check (use -1 for all items). + /// + /// A fill color. + /// + protected OxyColor GetSelectableFillColor(OxyColor originalColor, int index = -1) + { + return this.GetSelectableColor(originalColor, index); + } + + /// + /// Raises the Selected event. + /// + protected void OnIsSelectedChanged() + { + var eh = this.Selected; + if (eh != null) + { + eh(this, new EventArgs()); + } + } + + } +} \ No newline at end of file diff -r 88d699a65cc2 -r 5be8f2773237 External/OxyPlot/OxyPlot/PlotModel/UIPlotElement.cs --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/External/OxyPlot/OxyPlot/PlotModel/UIPlotElement.cs Sat Jun 08 16:53:22 2013 +0000 @@ -0,0 +1,116 @@ +// -------------------------------------------------------------------------------------------------------------------- +// +// The MIT License (MIT) +// +// Copyright (c) 2012 Oystein Bjorke +// +// Permission is hereby granted, free of charge, to any person obtaining a +// copy of this software and associated documentation files (the +// "Software"), to deal in the Software without restriction, including +// without limitation the rights to use, copy, modify, merge, publish, +// distribute, sublicense, and/or sell copies of the Software, and to +// permit persons to whom the Software is furnished to do so, subject to +// the following conditions: +// +// The above copyright notice and this permission notice shall be included +// in all copies or substantial portions of the Software. +// +// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS +// OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF +// MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. +// IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY +// CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, +// TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE +// SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. +// +// +// Represents a plot element that handles mouse events. +// +// -------------------------------------------------------------------------------------------------------------------- +namespace OxyPlot +{ + using System; + + /// + /// Provides an abstract base class for plot elements that handle mouse events. + /// + public abstract class UIPlotElement : SelectablePlotElement + { + /// + /// Occurs when a mouse button is pressed down on the model. + /// + public event EventHandler MouseDown; + + /// + /// Occurs when the mouse is moved on the plot element (only occurs after MouseDown). + /// + public event EventHandler MouseMove; + + /// + /// Occurs when the mouse button is released on the plot element. + /// + public event EventHandler MouseUp; + + /// + /// Raises the event. + /// + /// + /// The sender. + /// + /// + /// The instance containing the event data. + /// + protected internal virtual void OnMouseDown(object sender, OxyMouseEventArgs e) + { + if (this.MouseDown != null) + { + this.MouseDown(sender, e); + } + } + + /// + /// Raises the event. + /// + /// + /// The sender. + /// + /// + /// The instance containing the event data. + /// + protected internal virtual void OnMouseMove(object sender, OxyMouseEventArgs e) + { + if (this.MouseMove != null) + { + this.MouseMove(sender, e); + } + } + + /// + /// Raises the event. + /// + /// + /// The sender. + /// + /// + /// The instance containing the event data. + /// + protected internal virtual void OnMouseUp(object sender, OxyMouseEventArgs e) + { + if (this.MouseUp != null) + { + this.MouseUp(sender, e); + } + } + + /// + /// Tests if the plot element is hit by the specified point. + /// + /// The point. + /// The tolerance. + /// + /// A hit test result. + /// + protected internal abstract HitTestResult HitTest(ScreenPoint point, double tolerance); + + } +} \ No newline at end of file diff -r 88d699a65cc2 -r 5be8f2773237 External/OxyPlot/OxyPlot/Properties/AssemblyInfo.cs --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/External/OxyPlot/OxyPlot/Properties/AssemblyInfo.cs Sat Jun 08 16:53:22 2013 +0000 @@ -0,0 +1,10 @@ +// -------------------------------------------------------------------------------------------------------------------- +// +// http://oxyplot.codeplex.com, license: MIT +// +// -------------------------------------------------------------------------------------------------------------------- + +using System.Reflection; + +[assembly: AssemblyTitle("OxyPlot")] +[assembly: AssemblyDescription("OxyPlot core library")] \ No newline at end of file diff -r 88d699a65cc2 -r 5be8f2773237 External/OxyPlot/OxyPlot/Render/AngleAxisRenderer.cs --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/External/OxyPlot/OxyPlot/Render/AngleAxisRenderer.cs Sat Jun 08 16:53:22 2013 +0000 @@ -0,0 +1,166 @@ +// -------------------------------------------------------------------------------------------------------------------- +// +// The MIT License (MIT) +// +// Copyright (c) 2012 Oystein Bjorke +// +// Permission is hereby granted, free of charge, to any person obtaining a +// copy of this software and associated documentation files (the +// "Software"), to deal in the Software without restriction, including +// without limitation the rights to use, copy, modify, merge, publish, +// distribute, sublicense, and/or sell copies of the Software, and to +// permit persons to whom the Software is furnished to do so, subject to +// the following conditions: +// +// The above copyright notice and this permission notice shall be included +// in all copies or substantial portions of the Software. +// +// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS +// OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF +// MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. +// IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY +// CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, +// TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE +// SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. +// +// +// The angle axis renderer. +// +// -------------------------------------------------------------------------------------------------------------------- +namespace OxyPlot +{ + using System; + + using OxyPlot.Axes; + + /// + /// Provides functionality to render . + /// + public class AngleAxisRenderer : AxisRendererBase + { + /// + /// Initializes a new instance of the class. + /// + /// + /// The render context. + /// + /// + /// The plot. + /// + public AngleAxisRenderer(IRenderContext rc, PlotModel plot) + : base(rc, plot) + { + } + + /// + /// Renders the specified axis. + /// + /// The axis. + /// The render pass. + /// Magnitude axis not defined. + public override void Render(Axis axis, int pass) + { + base.Render(axis, pass); + + var magnitudeAxis = this.Plot.DefaultMagnitudeAxis; + + if (axis.RelatedAxis != null) + { + magnitudeAxis = axis.RelatedAxis as MagnitudeAxis; + } + + if (magnitudeAxis == null) + { + throw new InvalidOperationException("Magnitude axis not defined."); + } + + double eps = axis.MinorStep * 1e-3; + + if (axis.ShowMinorTicks) + { + foreach (double value in this.MinorTickValues) + { + if (value < axis.ActualMinimum - eps || value > axis.ActualMaximum + eps) + { + continue; + } + + if (this.MajorTickValues.Contains(value)) + { + continue; + } + + var pt = magnitudeAxis.Transform(magnitudeAxis.ActualMaximum, value, axis); + + if (this.MinorPen != null) + { + this.rc.DrawLine(magnitudeAxis.MidPoint.x, magnitudeAxis.MidPoint.y, pt.x, pt.y, this.MinorPen, false); + } + } + } + + var angleAxis = (AngleAxis)axis; + bool isFullCircle = Math.Abs(Math.Abs(angleAxis.EndAngle - angleAxis.StartAngle) - 360) < 1e-6; + + foreach (double value in this.MajorTickValues) + { + // skip the last value (overlapping with the first) + if (isFullCircle && value > axis.ActualMaximum - eps) + { + continue; + } + + if (value < axis.ActualMinimum - eps || value > axis.ActualMaximum + eps) + { + continue; + } + + ScreenPoint pt = magnitudeAxis.Transform(magnitudeAxis.ActualMaximum, value, axis); + if (this.MajorPen != null) + { + this.rc.DrawLine( + magnitudeAxis.MidPoint.x, magnitudeAxis.MidPoint.y, pt.x, pt.y, this.MajorPen, false); + } + } + + foreach (double value in this.MajorLabelValues) + { + // skip the last value (overlapping with the first) + if (isFullCircle && value > axis.ActualMaximum - eps) + { + continue; + } + + var pt = magnitudeAxis.Transform(magnitudeAxis.ActualMaximum, value, axis); + double angle = Math.Atan2(pt.y - magnitudeAxis.MidPoint.y, pt.x - magnitudeAxis.MidPoint.x); + + // add some margin + pt.x += Math.Cos(angle) * axis.AxisTickToLabelDistance; + pt.y += Math.Sin(angle) * axis.AxisTickToLabelDistance; + + // Convert to degrees + angle *= 180 / Math.PI; + + string text = axis.FormatValue(value); + + var ha = HorizontalAlignment.Left; + var va = VerticalAlignment.Middle; + + if (Math.Abs(Math.Abs(angle) - 90) < 10) + { + ha = HorizontalAlignment.Center; + va = angle > 90 ? VerticalAlignment.Top : VerticalAlignment.Bottom; + angle = 0; + } + else if (angle > 90 || angle < -90) + { + angle -= 180; + ha = HorizontalAlignment.Right; + } + + this.rc.DrawMathText( + pt, text, axis.ActualTextColor, axis.ActualFont, axis.ActualFontSize, axis.ActualFontWeight, angle, ha, va); + } + } + } +} \ No newline at end of file diff -r 88d699a65cc2 -r 5be8f2773237 External/OxyPlot/OxyPlot/Render/AxisRenderer.cs --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/External/OxyPlot/OxyPlot/Render/AxisRenderer.cs Sat Jun 08 16:53:22 2013 +0000 @@ -0,0 +1,532 @@ +// -------------------------------------------------------------------------------------------------------------------- +// +// The MIT License (MIT) +// +// Copyright (c) 2012 Oystein Bjorke +// +// Permission is hereby granted, free of charge, to any person obtaining a +// copy of this software and associated documentation files (the +// "Software"), to deal in the Software without restriction, including +// without limitation the rights to use, copy, modify, merge, publish, +// distribute, sublicense, and/or sell copies of the Software, and to +// permit persons to whom the Software is furnished to do so, subject to +// the following conditions: +// +// The above copyright notice and this permission notice shall be included +// in all copies or substantial portions of the Software. +// +// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS +// OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF +// MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. +// IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY +// CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, +// TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE +// SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. +// +// -------------------------------------------------------------------------------------------------------------------- +using System; +using System.Collections.Generic; + +namespace OxyPlot +{ + public class AxisRenderer + { + private const double AXIS_LEGEND_DIST = 4; // distance from axis number to axis legend + private const double TICK_DIST = 8; // distance from axis tick to number + + private OxyPen extraPen; + private OxyPen majorPen; + private OxyPen majorTickPen; + + private ICollection majorTickValues; + private OxyPen minorPen; + private OxyPen minorTickPen; + private ICollection minorTickValues; + private OxyPen zeroPen; + + protected readonly PlotModel Plot; + protected readonly IRenderContext rc; + + public AxisRenderer(IRenderContext rc, PlotModel plot) + { + this.Plot = plot; + this.rc = rc; + } + + public void Render(Axis axis) + { + if (axis == null) + return; + + axis.GetTickValues(out majorTickValues, out minorTickValues); + + CreatePens(axis); + + if (axis.IsHorizontal()) + { + RenderHorizontalAxis(axis, Plot.DefaultYAxis); + } + if (axis.IsVertical()) + { + RenderVerticalAxis(axis, Plot.DefaultXAxis); + } + if (axis.Position == AxisPosition.Angle) + { + RenderAngleAxis(axis, Plot.DefaultMagnitudeAxis); + } + if (axis.Position == AxisPosition.Magnitude) + { + RenderMagnitudeAxis(axis, Plot.DefaultAngleAxis); + } + } + + private void RenderMagnitudeAxis(Axis axis, Axis angleAxis) + { + if (axis.RelatedAxis != null) + angleAxis = axis.RelatedAxis; + + if (axis.ShowMinorTicks) + { + // GetVerticalTickPositions(axis, axis.TickStyle, axis.MinorTickSize, out y0, out y1); + + foreach (double xValue in minorTickValues) + { + if (xValue < axis.ActualMinimum || xValue > axis.ActualMaximum) + { + continue; + } + + if (majorTickValues.Contains(xValue)) + { + continue; + } + + var pts = new List(); + for (double th = angleAxis.ActualMinimum; + th <= angleAxis.ActualMaximum; + th += angleAxis.MinorStep*0.1) + { + pts.Add(axis.Transform(xValue, th, angleAxis)); + } + + if (minorPen != null) + { + rc.DrawLine(pts, minorPen.Color, minorPen.Thickness, minorPen.DashArray); + } + // RenderGridline(x, y + y0, x, y + y1, minorTickPen); + } + } + + // GetVerticalTickPositions(axis, axis.TickStyle, axis.MajorTickSize, out y0, out y1); + + foreach (double xValue in majorTickValues) + { + if (xValue < axis.ActualMinimum || xValue > axis.ActualMaximum) + { + continue; + } + + var pts = new List(); + for (double th = angleAxis.ActualMinimum; th <= angleAxis.ActualMaximum; th += angleAxis.MinorStep*0.1) + { + pts.Add(axis.Transform(xValue, th, angleAxis)); + } + + if (majorPen != null) + { + rc.DrawLine(pts, majorPen.Color, majorPen.Thickness, majorPen.DashArray); + } + + // RenderGridline(x, y + y0, x, y + y1, majorTickPen); + + //var pt = new ScreenPoint(x, istop ? y + y1 - TICK_DIST : y + y1 + TICK_DIST); + //string text = axis.FormatValue(xValue); + //double h = rc.MeasureText(text, axis.FontFamily, axis.FontSize, axis.FontWeight).Height; + + //rc.DrawText(pt, text, plot.TextColor, + // axis.FontFamily, axis.FontSize, axis.FontWeight, + // axis.Angle, + // HorizontalTextAlign.Center, istop ? VerticalTextAlign.Bottom : VerticalTextAlign.Top); + + //maxh = Math.Max(maxh, h); + } + } + + private void RenderAngleAxis(Axis axis, Axis magnitudeAxis) + { + if (axis.RelatedAxis != null) + magnitudeAxis = axis.RelatedAxis; + + if (axis.ShowMinorTicks) + { + // GetVerticalTickPositions(axis, axis.TickStyle, axis.MinorTickSize, out y0, out y1); + + foreach (double xValue in minorTickValues) + { + if (xValue < axis.ActualMinimum || xValue > axis.ActualMaximum) + { + continue; + } + + if (majorTickValues.Contains(xValue)) + { + continue; + } + + var pt = magnitudeAxis.Transform(magnitudeAxis.ActualMaximum, xValue, axis); + + if (minorPen != null) + { + RenderLine(axis.MidPoint.x, axis.MidPoint.y, pt.x, pt.y, minorPen, false); + } + // RenderGridline(x, y + y0, x, y + y1, minorTickPen); + } + } + + // GetVerticalTickPositions(axis, axis.TickStyle, axis.MajorTickSize, out y0, out y1); + + foreach (double xValue in majorTickValues) + { + if (xValue < axis.ActualMinimum || xValue > axis.ActualMaximum) + { + continue; + } + + var pt = magnitudeAxis.Transform(magnitudeAxis.ActualMaximum, xValue, axis); + + if (majorPen != null) + { + RenderLine(axis.MidPoint.x, axis.MidPoint.y, pt.x, pt.y, majorPen, false); + } + // RenderGridline(x, y + y0, x, y + y1, majorTickPen); + + //var pt = new ScreenPoint(x, istop ? y + y1 - TICK_DIST : y + y1 + TICK_DIST); + //string text = axis.FormatValue(xValue); + //double h = rc.MeasureText(text, axis.FontFamily, axis.FontSize, axis.FontWeight).Height; + + //rc.DrawText(pt, text, plot.TextColor, + // axis.FontFamily, axis.FontSize, axis.FontWeight, + // axis.Angle, + // HorizontalTextAlign.Center, istop ? VerticalTextAlign.Bottom : VerticalTextAlign.Top); + + //maxh = Math.Max(maxh, h); + } + } + + private void RenderLine(double x0, double y0, double x1, double y1, OxyPen pen, bool aliased = true) + { + if (pen == null) + return; + + rc.DrawLine(new[] + { + new ScreenPoint(x0, y0), + new ScreenPoint(x1, y1) + }, pen.Color, pen.Thickness, pen.DashArray, aliased); + } + + private void GetVerticalTickPositions(Axis axis, TickStyle glt, double ticksize, + out double y0, out double y1) + { + y0 = 0; + y1 = 0; + bool istop = axis.Position == AxisPosition.Top; + double topsign = istop ? -1 : 1; + switch (glt) + { + case TickStyle.Crossing: + y0 = -ticksize*topsign; + y1 = ticksize*topsign; + break; + case TickStyle.Inside: + y0 = -ticksize*topsign; + break; + case TickStyle.Outside: + y1 = ticksize*topsign; + break; + } + } + + private void GetHorizontalTickPositions(Axis axis, TickStyle glt, double ticksize, out double x0, + out double x1) + { + x0 = 0; + x1 = 0; + bool isLeft = axis.Position == AxisPosition.Left; + double leftSign = isLeft ? -1 : 1; + switch (glt) + { + case TickStyle.Crossing: + x0 = -ticksize*leftSign; + x1 = ticksize*leftSign; + break; + case TickStyle.Inside: + x0 = -ticksize*leftSign; + break; + case TickStyle.Outside: + x1 = ticksize*leftSign; + break; + } + } + + public void CreatePens(Axis axis) + { + minorPen = CreatePen(axis.MinorGridlineColor, axis.MinorGridlineThickness, axis.MinorGridlineStyle); + majorPen = CreatePen(axis.MajorGridlineColor, axis.MajorGridlineThickness, axis.MajorGridlineStyle); + minorTickPen = CreatePen(axis.TicklineColor, axis.MinorGridlineThickness, LineStyle.Solid); + majorTickPen = CreatePen(axis.TicklineColor, axis.MajorGridlineThickness, LineStyle.Solid); + zeroPen = CreatePen(axis.MajorGridlineColor, axis.MajorGridlineThickness, axis.MajorGridlineStyle); + extraPen = CreatePen(axis.ExtraGridlineColor, axis.ExtraGridlineThickness, axis.ExtraGridlineStyle); + } + + private void RenderHorizontalAxis(Axis axis, Axis perpendicularAxis) + { + double y = Plot.Bounds.Bottom; + switch (axis.Position) + { + case AxisPosition.Top: + y = Plot.Bounds.Top; + break; + case AxisPosition.Bottom: + y = Plot.Bounds.Bottom; + break; + } + if (axis.PositionAtZeroCrossing) + { + y = perpendicularAxis.TransformX(0); + } + + double y0, y1; + + if (axis.ShowMinorTicks) + { + GetVerticalTickPositions(axis, axis.TickStyle, axis.MinorTickSize, out y0, out y1); + + foreach (double xValue in minorTickValues) + { + if (xValue < axis.ActualMinimum || xValue > axis.ActualMaximum) + { + continue; + } + + if (majorTickValues.Contains(xValue)) + { + continue; + } + + double x = axis.TransformX(xValue); + if (minorPen != null) + { + RenderLine(x, Plot.Bounds.Top, x, Plot.Bounds.Bottom, minorPen); + } + RenderLine(x, y + y0, x, y + y1, minorTickPen); + } + } + + GetVerticalTickPositions(axis, axis.TickStyle, axis.MajorTickSize, out y0, out y1); + + double maxh = 0; + bool istop = axis.Position == AxisPosition.Top; + foreach (double xValue in majorTickValues) + { + if (xValue < axis.ActualMinimum || xValue > axis.ActualMaximum) + { + continue; + } + + double x = axis.TransformX(xValue); + + if (majorPen != null) + { + RenderLine(x, Plot.Bounds.Top, x, Plot.Bounds.Bottom, majorPen); + } + RenderLine(x, y + y0, x, y + y1, majorTickPen); + + if (xValue == 0 && axis.PositionAtZeroCrossing) + continue; + + var pt = new ScreenPoint(x, istop ? y + y1 - TICK_DIST : y + y1 + TICK_DIST); + string text = axis.FormatValue(xValue); + double h = rc.MeasureText(text, axis.FontFamily, axis.FontSize, axis.FontWeight).Height; + + rc.DrawText(pt, text, Plot.TextColor, + axis.FontFamily, axis.FontSize, axis.FontWeight, + axis.Angle, + HorizontalTextAlign.Center, istop ? VerticalTextAlign.Bottom : VerticalTextAlign.Top); + + maxh = Math.Max(maxh, h); + } + + if (axis.PositionAtZeroCrossing) + { + double x = axis.TransformX(0); + RenderLine(x, Plot.Bounds.Top, x, Plot.Bounds.Bottom, zeroPen); + } + + if (axis.ExtraGridlines != null) + { + foreach (double x in axis.ExtraGridlines) + { + if (!IsWithin(x, axis.ActualMinimum, axis.ActualMaximum)) + continue; + double sx = axis.TransformX(x); + RenderLine(sx, Plot.Bounds.Top, sx, Plot.Bounds.Bottom, extraPen); + } + } + + // The horizontal axis line + RenderLine(Plot.Bounds.Left, y, Plot.Bounds.Right, y, majorPen); + + // The horizontal axis legend (centered horizontally) + double legendX = axis.TransformX((axis.ActualMinimum + axis.ActualMaximum)/2); + HorizontalTextAlign halign = HorizontalTextAlign.Center; + VerticalTextAlign valign = VerticalTextAlign.Bottom; + + if (axis.PositionAtZeroCrossing) + { + legendX = perpendicularAxis.TransformX(perpendicularAxis.ActualMaximum); + } + + double legendY = rc.Height - AXIS_LEGEND_DIST; + if (istop) + { + legendY = AXIS_LEGEND_DIST; + valign = VerticalTextAlign.Top; + } + rc.DrawText(new ScreenPoint(legendX, legendY), + axis.Title, Plot.TextColor, + axis.FontFamily, axis.FontSize, axis.FontWeight, 0, halign, valign); + } + + private OxyPen CreatePen(OxyColor c, double th, LineStyle ls) + { + if (ls == LineStyle.None || th == 0) + return null; + return new OxyPen(c, th, ls); + } + + private void RenderVerticalAxis(Axis axis, Axis perpendicularAxis) + { + double x = Plot.Bounds.Left; + switch (axis.Position) + { + case AxisPosition.Left: + x = Plot.Bounds.Left; + break; + case AxisPosition.Right: + x = Plot.Bounds.Right; + break; + } + if (axis.PositionAtZeroCrossing) + x = perpendicularAxis.TransformX(0); + + double x0, x1; + + if (axis.ShowMinorTicks) + { + GetHorizontalTickPositions(axis, axis.TickStyle, axis.MinorTickSize, out x0, out x1); + foreach (double yValue in minorTickValues) + { + if (yValue < axis.ActualMinimum || yValue > axis.ActualMaximum) + { + continue; + } + + if (majorTickValues.Contains(yValue)) + { + continue; + } + double y = axis.TransformX(yValue); + + if (minorPen != null) + { + RenderLine(Plot.Bounds.Left, y, Plot.Bounds.Right, y, minorPen); + } + + RenderLine(x + x0, y, x + x1, y, minorTickPen); + } + } + + GetHorizontalTickPositions(axis, axis.TickStyle, axis.MajorTickSize, out x0, out x1); + double maxw = 0; + + bool isleft = axis.Position == AxisPosition.Left; + + foreach (double yValue in majorTickValues) + { + if (yValue < axis.ActualMinimum || yValue > axis.ActualMaximum) + continue; + + double y = axis.TransformX(yValue); + + if (majorPen != null) + { + RenderLine(Plot.Bounds.Left, y, Plot.Bounds.Right, y, majorPen); + } + + RenderLine(x + x0, y, x + x1, y, majorTickPen); + + if (yValue == 0 && axis.PositionAtZeroCrossing) + continue; + + var pt = new ScreenPoint(isleft ? x + x1 - TICK_DIST : x + x1 + TICK_DIST, y); + string text = axis.FormatValue(yValue); + double w = rc.MeasureText(text, axis.FontFamily, axis.FontSize, axis.FontWeight).Height; + rc.DrawText(pt, text, Plot.TextColor, + axis.FontFamily, axis.FontSize, axis.FontWeight, + axis.Angle, + isleft ? HorizontalTextAlign.Right : HorizontalTextAlign.Left, VerticalTextAlign.Middle); + maxw = Math.Max(maxw, w); + } + + if (axis.PositionAtZeroCrossing) + { + double y = axis.TransformX(0); + RenderLine(Plot.Bounds.Left, y, Plot.Bounds.Right, y, zeroPen); + } + + if (axis.ExtraGridlines != null) + foreach (double y in axis.ExtraGridlines) + { + if (!IsWithin(y, axis.ActualMinimum, axis.ActualMaximum)) + continue; + double sy = axis.TransformX(y); + RenderLine(Plot.Bounds.Left, sy, Plot.Bounds.Right, sy, extraPen); + } + + RenderLine(x, Plot.Bounds.Top, x, Plot.Bounds.Bottom, majorPen); + + double ymid = axis.TransformX((axis.ActualMinimum + axis.ActualMaximum)/2); + + HorizontalTextAlign halign = HorizontalTextAlign.Center; + VerticalTextAlign valign = VerticalTextAlign.Top; + + if (axis.PositionAtZeroCrossing) + { + ymid = perpendicularAxis.TransformX(perpendicularAxis.ActualMaximum); + // valign = axis.IsReversed ? VerticalTextAlign.Top : VerticalTextAlign.Bottom; + } + + if (isleft) + { + x = AXIS_LEGEND_DIST; + } + else + { + x = rc.Width - AXIS_LEGEND_DIST; + valign = VerticalTextAlign.Bottom; + } + + rc.DrawText(new ScreenPoint(x, ymid), axis.Title, Plot.TextColor, + axis.FontFamily, axis.FontSize, axis.FontWeight, + -90, halign, valign); + } + + private bool IsWithin(double d, double min, double max) + { + if (d < min) return false; + if (d > max) return false; + return true; + } + } +} \ No newline at end of file diff -r 88d699a65cc2 -r 5be8f2773237 External/OxyPlot/OxyPlot/Render/AxisRendererBase.cs --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/External/OxyPlot/OxyPlot/Render/AxisRendererBase.cs Sat Jun 08 16:53:22 2013 +0000 @@ -0,0 +1,217 @@ +// -------------------------------------------------------------------------------------------------------------------- +// +// The MIT License (MIT) +// +// Copyright (c) 2012 Oystein Bjorke +// +// Permission is hereby granted, free of charge, to any person obtaining a +// copy of this software and associated documentation files (the +// "Software"), to deal in the Software without restriction, including +// without limitation the rights to use, copy, modify, merge, publish, +// distribute, sublicense, and/or sell copies of the Software, and to +// permit persons to whom the Software is furnished to do so, subject to +// the following conditions: +// +// The above copyright notice and this permission notice shall be included +// in all copies or substantial portions of the Software. +// +// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS +// OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF +// MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. +// IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY +// CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, +// TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE +// SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. +// +// +// The axis renderer base. +// +// -------------------------------------------------------------------------------------------------------------------- +namespace OxyPlot +{ + using System.Collections.Generic; + + using OxyPlot.Axes; + + /// + /// Provides an abstract base class for axis renderers. + /// + public abstract class AxisRendererBase + { + /// + /// The plot. + /// + protected readonly PlotModel Plot; + + /// + /// The render context. + /// + protected readonly IRenderContext rc; + + /// + /// The axis lines pen. + /// + protected OxyPen AxislinePen; + + /// + /// The extra grid lines pen. + /// + protected OxyPen ExtraPen; + + /// + /// The major label values. + /// + protected IList MajorLabelValues; + + /// + /// The major grid lines pen. + /// + protected OxyPen MajorPen; + + /// + /// The major tick pen. + /// + protected OxyPen MajorTickPen; + + /// + /// The major tick values. + /// + protected IList MajorTickValues; + + /// + /// The minor grid lines pen. + /// + protected OxyPen MinorPen; + + /// + /// The minor tick pen. + /// + protected OxyPen MinorTickPen; + + /// + /// The minor tick values. + /// + protected IList MinorTickValues; + + /// + /// The zero grid line pen. + /// + protected OxyPen ZeroPen; + + /// + /// Initializes a new instance of the class. + /// + /// + /// The render context. + /// + /// + /// The plot. + /// + protected AxisRendererBase(IRenderContext rc, PlotModel plot) + { + this.Plot = plot; + this.rc = rc; + } + + /// + /// Renders the specified axis. + /// + /// The axis. + /// The pass. + public virtual void Render(Axis axis, int pass) + { + if (axis == null) + { + return; + } + + axis.GetTickValues(out this.MajorLabelValues, out this.MajorTickValues, out this.MinorTickValues); + this.CreatePens(axis); + } + + /// + /// The create pens. + /// + /// + /// The axis. + /// + protected void CreatePens(Axis axis) + { + this.MinorPen = OxyPen.Create(axis.MinorGridlineColor, axis.MinorGridlineThickness, axis.MinorGridlineStyle); + this.MajorPen = OxyPen.Create(axis.MajorGridlineColor, axis.MajorGridlineThickness, axis.MajorGridlineStyle); + this.MinorTickPen = OxyPen.Create(axis.TicklineColor, axis.MinorGridlineThickness); + this.MajorTickPen = OxyPen.Create(axis.TicklineColor, axis.MajorGridlineThickness); + this.ZeroPen = OxyPen.Create(axis.TicklineColor, axis.MajorGridlineThickness); + this.ExtraPen = OxyPen.Create(axis.ExtraGridlineColor, axis.ExtraGridlineThickness, axis.ExtraGridlineStyle); + this.AxislinePen = OxyPen.Create(axis.AxislineColor, axis.AxislineThickness, axis.AxislineStyle); + } + + /// + /// The get tick positions. + /// + /// + /// The axis. + /// + /// + /// The glt. + /// + /// + /// The ticksize. + /// + /// + /// The position. + /// + /// + /// The x 0. + /// + /// + /// The x 1. + /// + protected void GetTickPositions( + Axis axis, TickStyle glt, double ticksize, AxisPosition position, out double x0, out double x1) + { + x0 = 0; + x1 = 0; + bool isTopOrLeft = position == AxisPosition.Top || position == AxisPosition.Left; + double sign = isTopOrLeft ? -1 : 1; + switch (glt) + { + case TickStyle.Crossing: + x0 = -ticksize * sign * 0.75; + x1 = ticksize * sign * 0.75; + break; + case TickStyle.Inside: + x0 = -ticksize * sign; + break; + case TickStyle.Outside: + x1 = ticksize * sign; + break; + } + } + + /// + /// Determines whether the specified value is within the specified range. + /// + /// The value to check. + /// The minium value of the range. + /// The maximum value of the range. + /// + /// true if the specified value is within the range; otherwise, false. + /// + protected bool IsWithin(double d, double min, double max) + { + if (d < min) + { + return false; + } + + if (d > max) + { + return false; + } + + return true; + } + + } +} \ No newline at end of file diff -r 88d699a65cc2 -r 5be8f2773237 External/OxyPlot/OxyPlot/Render/HorizontalAndVerticalAxisRenderer.cs --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/External/OxyPlot/OxyPlot/Render/HorizontalAndVerticalAxisRenderer.cs Sat Jun 08 16:53:22 2013 +0000 @@ -0,0 +1,642 @@ +// -------------------------------------------------------------------------------------------------------------------- +// +// The MIT License (MIT) +// +// Copyright (c) 2012 Oystein Bjorke +// +// Permission is hereby granted, free of charge, to any person obtaining a copy of this software and +// associated documentation files (the "Software"), to deal in the Software without restriction, +// including without limitation the rights to use, copy, modify, merge, publish, distribute, +// sublicense, and/or sell copies of the Software, and to permit persons to whom the Software is +// furnished to do so, subject to the following conditions: +// +// The above copyright notice and this permission notice shall be included in all copies or substantial +// portions of the Software. +// +// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT +// NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. +// IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, +// WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE +// SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. +// +// +// Rendering helper class for horizontal and vertical axes (both linear and logarithmic) +// +// -------------------------------------------------------------------------------------------------------------------- +namespace OxyPlot +{ + using System; + using System.Collections.Generic; + using System.Diagnostics; + + using OxyPlot.Axes; + + /// + /// Preovides functionality to render horizontal and vertical axes. + /// + public class HorizontalAndVerticalAxisRenderer : AxisRendererBase + { + /// + /// Initializes a new instance of the class. + /// + /// + /// The render context. + /// + /// + /// The plot. + /// + public HorizontalAndVerticalAxisRenderer(IRenderContext rc, PlotModel plot) + : base(rc, plot) + { + } + + /// + /// Renders the specified axis. + /// + /// The axis. + /// The pass. + public override void Render(Axis axis, int pass) + { + base.Render(axis, pass); + + double totalShift = axis.PositionTierMinShift; + double tierSize = axis.PositionTierSize - this.Plot.AxisTierDistance; + + // store properties locally for performance + double plotAreaLeft = this.Plot.PlotArea.Left; + double plotAreaRight = this.Plot.PlotArea.Right; + double plotAreaTop = this.Plot.PlotArea.Top; + double plotAreaBottom = this.Plot.PlotArea.Bottom; + + // Axis position (x or y screen coordinate) + double axisPosition = 0; + double titlePosition = 0; + + switch (axis.Position) + { + case AxisPosition.Left: + axisPosition = plotAreaLeft - totalShift; + titlePosition = axisPosition - tierSize; + break; + case AxisPosition.Right: + axisPosition = plotAreaRight + totalShift; + titlePosition = axisPosition + tierSize; + break; + case AxisPosition.Top: + axisPosition = plotAreaTop - totalShift; + titlePosition = axisPosition - tierSize; + break; + case AxisPosition.Bottom: + axisPosition = plotAreaBottom + totalShift; + titlePosition = axisPosition + tierSize; + break; + } + + if (axis.PositionAtZeroCrossing) + { + var perpendicularAxis = axis.IsHorizontal() ? this.Plot.DefaultYAxis : this.Plot.DefaultXAxis; + axisPosition = perpendicularAxis.Transform(0); + } + + if (pass == 0) + { + this.RenderMinorItems(axis, axisPosition); + } + + if (pass == 1) + { + this.RenderMajorItems(axis, axisPosition, titlePosition); + } + } + + /// + /// Gets the axis title position, rotation and alignment. + /// + /// + /// The axis. + /// + /// + /// The title position. + /// + /// + /// The angle. + /// + /// + /// The horizontal alignment. + /// + /// + /// The vertical alignment. + /// + /// + /// The . + /// + protected virtual ScreenPoint GetAxisTitlePositionAndAlignment( + Axis axis, + double titlePosition, + ref double angle, + ref HorizontalAlignment halign, + ref VerticalAlignment valign) + { + double middle = axis.IsHorizontal() + ? Lerp(axis.ScreenMin.X, axis.ScreenMax.X, axis.TitlePosition) + : Lerp(axis.ScreenMax.Y, axis.ScreenMin.Y, axis.TitlePosition); + + if (axis.PositionAtZeroCrossing) + { + var perpendicularAxis = axis.IsHorizontal() ? this.Plot.DefaultYAxis : this.Plot.DefaultXAxis; + middle = perpendicularAxis.Transform(perpendicularAxis.ActualMaximum); + } + + switch (axis.Position) + { + case AxisPosition.Left: + return new ScreenPoint(titlePosition, middle); + case AxisPosition.Right: + valign = VerticalAlignment.Bottom; + return new ScreenPoint(titlePosition, middle); + case AxisPosition.Top: + halign = HorizontalAlignment.Center; + valign = VerticalAlignment.Top; + angle = 0; + return new ScreenPoint(middle, titlePosition); + case AxisPosition.Bottom: + halign = HorizontalAlignment.Center; + valign = VerticalAlignment.Bottom; + angle = 0; + return new ScreenPoint(middle, titlePosition); + default: + throw new ArgumentOutOfRangeException("axis"); + } + } + + /// + /// Gets the alignments given the specified rotation angle. + /// + /// + /// The angle. + /// + /// + /// The default horizontal alignment. + /// + /// + /// The default vertical alignment. + /// + /// + /// The rotated horizontal alignment. + /// + /// + /// The rotated vertical alignment. + /// + protected virtual void GetRotatedAlignments( + double angle, + HorizontalAlignment defaultHorizontalAlignment, + VerticalAlignment defaultVerticalAlignment, + out HorizontalAlignment ha, + out VerticalAlignment va) + { + ha = defaultHorizontalAlignment; + va = defaultVerticalAlignment; + + Debug.Assert(angle <= 180 && angle >= -180, "Axis angle should be in the interval [-180,180] degrees."); + + if (angle > -45 && angle < 45) + { + return; + } + + if (angle > 135 || angle < -135) + { + ha = (HorizontalAlignment)(-(int)defaultHorizontalAlignment); + va = (VerticalAlignment)(-(int)defaultVerticalAlignment); + return; + } + + if (angle > 45) + { + ha = (HorizontalAlignment)((int)defaultVerticalAlignment); + va = (VerticalAlignment)(-(int)defaultHorizontalAlignment); + return; + } + + if (angle < -45) + { + ha = (HorizontalAlignment)(-(int)defaultVerticalAlignment); + va = (VerticalAlignment)((int)defaultHorizontalAlignment); + } + } + + /// + /// Linear interpolation + /// http://en.wikipedia.org/wiki/Linear_interpolation + /// + /// + /// The x0. + /// + /// + /// The x1. + /// + /// + /// The interpolation factor. + /// + /// + /// The interpolated value. + /// + private static double Lerp(double x0, double x1, double f) + { + return (x0 * (1 - f)) + (x1 * f); + } + + /// + /// Snaps v to value if it is within the the specified distance. + /// + /// + /// The target value. + /// + /// + /// The value to snap. + /// + /// + /// The distance tolerance. + /// + private static void SnapTo(double target, ref double v, double eps = 0.5) + { + if (v > target - eps && v < target + eps) + { + v = target; + } + } + + /// + /// Renders the axis title. + /// + /// + /// The axis. + /// + /// + /// The title position. + /// + private void RenderAxisTitle(Axis axis, double titlePosition) + { + bool isHorizontal = axis.IsHorizontal(); + + OxySize? maxSize = null; + + if (axis.ClipTitle) + { + // Calculate the title clipping dimensions + double screenLength = isHorizontal + ? Math.Abs(axis.ScreenMax.X - axis.ScreenMin.X) + : Math.Abs(axis.ScreenMax.Y - axis.ScreenMin.Y); + + maxSize = new OxySize(screenLength * axis.TitleClippingLength, double.MaxValue); + } + + double angle = -90; + + var halign = HorizontalAlignment.Center; + var valign = VerticalAlignment.Top; + + var lpt = this.GetAxisTitlePositionAndAlignment(axis, titlePosition, ref angle, ref halign, ref valign); + + this.rc.SetToolTip(axis.ToolTip); + this.rc.DrawMathText( + lpt, + axis.ActualTitle, + axis.ActualTitleColor, + axis.ActualTitleFont, + axis.ActualTitleFontSize, + axis.ActualTitleFontWeight, + angle, + halign, + valign, + maxSize); + this.rc.SetToolTip(null); + } + + /// + /// Renders the major items. + /// + /// + /// The axis. + /// + /// + /// The axis position. + /// + /// + /// The title position. + /// + private void RenderMajorItems(Axis axis, double axisPosition, double titlePosition) + { + double eps = axis.ActualMinorStep * 1e-3; + + double actualMinimum = axis.ActualMinimum; + double actualMaximum = axis.ActualMaximum; + + double plotAreaLeft = this.Plot.PlotArea.Left; + double plotAreaRight = this.Plot.PlotArea.Right; + double plotAreaTop = this.Plot.PlotArea.Top; + double plotAreaBottom = this.Plot.PlotArea.Bottom; + bool isHorizontal = axis.IsHorizontal(); + + double a0; + double a1; + var majorSegments = new List(); + var majorTickSegments = new List(); + this.GetTickPositions(axis, axis.TickStyle, axis.MajorTickSize, axis.Position, out a0, out a1); + + foreach (double value in this.MajorTickValues) + { + if (value < actualMinimum - eps || value > actualMaximum + eps) + { + continue; + } + + if (axis.PositionAtZeroCrossing && Math.Abs(value) < eps) + { + continue; + } + + double transformedValue = axis.Transform(value); + if (isHorizontal) + { + SnapTo(plotAreaLeft, ref transformedValue); + SnapTo(plotAreaRight, ref transformedValue); + } + else + { + SnapTo(plotAreaTop, ref transformedValue); + SnapTo(plotAreaBottom, ref transformedValue); + } + + if (this.MajorPen != null) + { + if (isHorizontal) + { + majorSegments.Add(new ScreenPoint(transformedValue, plotAreaTop)); + majorSegments.Add(new ScreenPoint(transformedValue, plotAreaBottom)); + } + else + { + majorSegments.Add(new ScreenPoint(plotAreaLeft, transformedValue)); + majorSegments.Add(new ScreenPoint(plotAreaRight, transformedValue)); + } + } + + if (axis.TickStyle != TickStyle.None) + { + if (isHorizontal) + { + majorTickSegments.Add(new ScreenPoint(transformedValue, axisPosition + a0)); + majorTickSegments.Add(new ScreenPoint(transformedValue, axisPosition + a1)); + } + else + { + majorTickSegments.Add(new ScreenPoint(axisPosition + a0, transformedValue)); + majorTickSegments.Add(new ScreenPoint(axisPosition + a1, transformedValue)); + } + } + } + + // Render the axis labels (numbers or category names) + foreach (double value in this.MajorLabelValues) + { + if (value < actualMinimum - eps || value > actualMaximum + eps) + { + continue; + } + + if (axis.PositionAtZeroCrossing && Math.Abs(value) < eps) + { + continue; + } + + double transformedValue = axis.Transform(value); + if (isHorizontal) + { + SnapTo(plotAreaLeft, ref transformedValue); + SnapTo(plotAreaRight, ref transformedValue); + } + else + { + SnapTo(plotAreaTop, ref transformedValue); + SnapTo(plotAreaBottom, ref transformedValue); + } + + var pt = new ScreenPoint(); + var ha = HorizontalAlignment.Right; + var va = VerticalAlignment.Middle; + switch (axis.Position) + { + case AxisPosition.Left: + pt = new ScreenPoint(axisPosition + a1 - axis.AxisTickToLabelDistance, transformedValue); + this.GetRotatedAlignments( + axis.Angle, HorizontalAlignment.Right, VerticalAlignment.Middle, out ha, out va); + break; + case AxisPosition.Right: + pt = new ScreenPoint(axisPosition + a1 + axis.AxisTickToLabelDistance, transformedValue); + this.GetRotatedAlignments( + axis.Angle, HorizontalAlignment.Left, VerticalAlignment.Middle, out ha, out va); + break; + case AxisPosition.Top: + pt = new ScreenPoint(transformedValue, axisPosition + a1 - axis.AxisTickToLabelDistance); + this.GetRotatedAlignments( + axis.Angle, HorizontalAlignment.Center, VerticalAlignment.Bottom, out ha, out va); + break; + case AxisPosition.Bottom: + pt = new ScreenPoint(transformedValue, axisPosition + a1 + axis.AxisTickToLabelDistance); + this.GetRotatedAlignments( + axis.Angle, HorizontalAlignment.Center, VerticalAlignment.Top, out ha, out va); + break; + } + + string text = axis.FormatValue(value); + this.rc.DrawMathText( + pt, + text, + axis.ActualTextColor, + axis.ActualFont, + axis.ActualFontSize, + axis.ActualFontWeight, + axis.Angle, + ha, + va); + } + + // Draw the zero crossing line + if (axis.PositionAtZeroCrossing && this.ZeroPen != null) + { + double t0 = axis.Transform(0); + if (isHorizontal) + { + this.rc.DrawLine(t0, plotAreaTop, t0, plotAreaBottom, this.ZeroPen); + } + else + { + this.rc.DrawLine(plotAreaLeft, t0, plotAreaRight, t0, this.ZeroPen); + } + } + + // Draw extra grid lines + if (axis.ExtraGridlines != null && this.ExtraPen != null) + { + foreach (double value in axis.ExtraGridlines) + { + if (!this.IsWithin(value, actualMinimum, actualMaximum)) + { + continue; + } + + double transformedValue = axis.Transform(value); + if (isHorizontal) + { + this.rc.DrawLine(transformedValue, plotAreaTop, transformedValue, plotAreaBottom, this.ExtraPen); + } + else + { + this.rc.DrawLine(plotAreaLeft, transformedValue, plotAreaRight, transformedValue, this.ExtraPen); + } + } + } + + // Draw the axis line (across the tick marks) + if (isHorizontal) + { + this.rc.DrawLine( + axis.Transform(actualMinimum), + axisPosition, + axis.Transform(actualMaximum), + axisPosition, + this.AxislinePen); + } + else + { + this.rc.DrawLine( + axisPosition, + axis.Transform(actualMinimum), + axisPosition, + axis.Transform(actualMaximum), + this.AxislinePen); + } + + // Draw the axis title + if (!string.IsNullOrEmpty(axis.ActualTitle)) + { + this.RenderAxisTitle(axis, titlePosition); + } + + if (this.MajorPen != null) + { + this.rc.DrawLineSegments(majorSegments, this.MajorPen); + } + + if (this.MajorTickPen != null) + { + this.rc.DrawLineSegments(majorTickSegments, this.MajorTickPen); + } + } + + /// + /// Renders the minor items. + /// + /// + /// The axis. + /// + /// + /// The axis position. + /// + private void RenderMinorItems(Axis axis, double axisPosition) + { + double eps = axis.ActualMinorStep * 1e-3; + double actualMinimum = axis.ActualMinimum; + double actualMaximum = axis.ActualMaximum; + + double plotAreaLeft = this.Plot.PlotArea.Left; + double plotAreaRight = this.Plot.PlotArea.Right; + double plotAreaTop = this.Plot.PlotArea.Top; + double plotAreaBottom = this.Plot.PlotArea.Bottom; + bool isHorizontal = axis.IsHorizontal(); + + double a0; + double a1; + var minorSegments = new List(); + var minorTickSegments = new List(); + this.GetTickPositions(axis, axis.TickStyle, axis.MinorTickSize, axis.Position, out a0, out a1); + + foreach (double value in this.MinorTickValues) + { + if (value < actualMinimum - eps || value > actualMaximum + eps) + { + continue; + } + + if (this.MajorTickValues.Contains(value)) + { + continue; + } + + if (axis.PositionAtZeroCrossing && Math.Abs(value) < eps) + { + continue; + } + + double transformedValue = axis.Transform(value); + + if (isHorizontal) + { + SnapTo(plotAreaLeft, ref transformedValue); + SnapTo(plotAreaRight, ref transformedValue); + } + else + { + SnapTo(plotAreaTop, ref transformedValue); + SnapTo(plotAreaBottom, ref transformedValue); + } + + // Draw the minor grid line + if (this.MinorPen != null) + { + if (isHorizontal) + { + minorSegments.Add(new ScreenPoint(transformedValue, plotAreaTop)); + minorSegments.Add(new ScreenPoint(transformedValue, plotAreaBottom)); + } + else + { + if (transformedValue < plotAreaTop || transformedValue > plotAreaBottom) + { + } + + minorSegments.Add(new ScreenPoint(plotAreaLeft, transformedValue)); + minorSegments.Add(new ScreenPoint(plotAreaRight, transformedValue)); + } + } + + // Draw the minor tick + if (axis.TickStyle != TickStyle.None) + { + if (isHorizontal) + { + minorTickSegments.Add(new ScreenPoint(transformedValue, axisPosition + a0)); + minorTickSegments.Add(new ScreenPoint(transformedValue, axisPosition + a1)); + } + else + { + minorTickSegments.Add(new ScreenPoint(axisPosition + a0, transformedValue)); + minorTickSegments.Add(new ScreenPoint(axisPosition + a1, transformedValue)); + } + } + } + + // Draw all the line segments); + if (this.MinorPen != null) + { + this.rc.DrawLineSegments(minorSegments, this.MinorPen); + } + + if (this.MinorTickPen != null) + { + this.rc.DrawLineSegments(minorTickSegments, this.MinorTickPen); + } + } + } +} \ No newline at end of file diff -r 88d699a65cc2 -r 5be8f2773237 External/OxyPlot/OxyPlot/Render/IRenderContext.cs --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/External/OxyPlot/OxyPlot/Render/IRenderContext.cs Sat Jun 08 16:53:22 2013 +0000 @@ -0,0 +1,400 @@ +// -------------------------------------------------------------------------------------------------------------------- +// +// The MIT License (MIT) +// +// Copyright (c) 2012 Oystein Bjorke +// +// Permission is hereby granted, free of charge, to any person obtaining a +// copy of this software and associated documentation files (the +// "Software"), to deal in the Software without restriction, including +// without limitation the rights to use, copy, modify, merge, publish, +// distribute, sublicense, and/or sell copies of the Software, and to +// permit persons to whom the Software is furnished to do so, subject to +// the following conditions: +// +// The above copyright notice and this permission notice shall be included +// in all copies or substantial portions of the Software. +// +// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS +// OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF +// MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. +// IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY +// CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, +// TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE +// SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. +// +// +// Render context interface. +// +// -------------------------------------------------------------------------------------------------------------------- +namespace OxyPlot +{ + using System.Collections.Generic; + + /// + /// Defines rendering functionality. + /// + public interface IRenderContext + { + /// + /// Gets a value indicating whether the context renders to screen. + /// + /// + /// true if the context renders to screen; otherwise, false. + /// + bool RendersToScreen { get; } + + /// + /// Draws an ellipse. + /// + /// + /// The rectangle. + /// + /// + /// The fill color. + /// + /// + /// The stroke color. + /// + /// + /// The thickness. + /// + void DrawEllipse(OxyRect rect, OxyColor fill, OxyColor stroke, double thickness = 1.0); + + /// + /// Draws the collection of ellipses, where all have the same stroke and fill. + /// This performs better than calling DrawEllipse multiple times. + /// + /// + /// The rectangles. + /// + /// + /// The fill color. + /// + /// + /// The stroke color. + /// + /// + /// The stroke thickness. + /// + void DrawEllipses(IList rectangles, OxyColor fill, OxyColor stroke, double thickness = 1.0); + + /// + /// Draws the polyline from the specified points. + /// + /// + /// The points. + /// + /// + /// The stroke color. + /// + /// + /// The stroke thickness. + /// + /// + /// The dash array. + /// + /// + /// The line join type. + /// + /// + /// if set to true the shape will be aliased. + /// + void DrawLine( + IList points, + OxyColor stroke, + double thickness = 1.0, + double[] dashArray = null, + OxyPenLineJoin lineJoin = OxyPenLineJoin.Miter, + bool aliased = false); + + /// + /// Draws the multiple line segments defined by points (0,1) (2,3) (4,5) etc. + /// This should have better performance than calling DrawLine for each segment. + /// + /// + /// The points. + /// + /// + /// The stroke color. + /// + /// + /// The stroke thickness. + /// + /// + /// The dash array. + /// + /// + /// The line join type. + /// + /// + /// if set to true the shape will be aliased. + /// + void DrawLineSegments( + IList points, + OxyColor stroke, + double thickness = 1.0, + double[] dashArray = null, + OxyPenLineJoin lineJoin = OxyPenLineJoin.Miter, + bool aliased = false); + + /// + /// Draws the polygon from the specified points. The polygon can have stroke and/or fill. + /// + /// + /// The points. + /// + /// + /// The fill color. + /// + /// + /// The stroke color. + /// + /// + /// The stroke thickness. + /// + /// + /// The dash array. + /// + /// + /// The line join type. + /// + /// + /// if set to true the shape will be aliased. + /// + void DrawPolygon( + IList points, + OxyColor fill, + OxyColor stroke, + double thickness = 1.0, + double[] dashArray = null, + OxyPenLineJoin lineJoin = OxyPenLineJoin.Miter, + bool aliased = false); + + /// + /// Draws a collection of polygons, where all polygons have the same stroke and fill. + /// This performs better than calling DrawPolygon multiple times. + /// + /// + /// The polygons. + /// + /// + /// The fill color. + /// + /// + /// The stroke color. + /// + /// + /// The stroke thickness. + /// + /// + /// The dash array. + /// + /// + /// The line join type. + /// + /// + /// if set to true the shape will be aliased. + /// + void DrawPolygons( + IList> polygons, + OxyColor fill, + OxyColor stroke, + double thickness = 1.0, + double[] dashArray = null, + OxyPenLineJoin lineJoin = OxyPenLineJoin.Miter, + bool aliased = false); + + /// + /// Draws the rectangle. + /// + /// + /// The rectangle. + /// + /// + /// The fill color. + /// + /// + /// The stroke color. + /// + /// + /// The stroke thickness. + /// + void DrawRectangle(OxyRect rect, OxyColor fill, OxyColor stroke, double thickness = 1.0); + + /// + /// Draws a collection of rectangles, where all have the same stroke and fill. + /// This performs better than calling DrawRectangle multiple times. + /// + /// + /// The rectangles. + /// + /// + /// The fill color. + /// + /// + /// The stroke color. + /// + /// + /// The stroke thickness. + /// + void DrawRectangles(IList rectangles, OxyColor fill, OxyColor stroke, double thickness = 1.0); + + /// + /// Draws the text. + /// + /// + /// The position. + /// + /// + /// The text. + /// + /// + /// The fill color. + /// + /// + /// The font family. + /// + /// + /// Size of the font. + /// + /// + /// The font weight. + /// + /// + /// The rotation angle. + /// + /// + /// The horizontal alignment. + /// + /// + /// The vertical alignment. + /// + /// + /// The maximum size of the text. + /// + void DrawText( + ScreenPoint p, + string text, + OxyColor fill, + string fontFamily = null, + double fontSize = 10, + double fontWeight = 500, + double rotate = 0, + HorizontalAlignment halign = HorizontalAlignment.Left, + VerticalAlignment valign = VerticalAlignment.Top, + OxySize? maxSize = null); + + /// + /// Measures the text. + /// + /// + /// The text. + /// + /// + /// The font family. + /// + /// + /// Size of the font. + /// + /// + /// The font weight. + /// + /// + /// The text size. + /// + OxySize MeasureText(string text, string fontFamily = null, double fontSize = 10, double fontWeight = 500); + + /// + /// Sets the tool tip for the following items. + /// + /// + /// This is only used in the plot controls. + /// + /// + /// The text in the tooltip. + /// + void SetToolTip(string text); + + /// + /// Cleans up resources not in use. + /// + /// + /// This method is called at the end of each rendering. + /// + void CleanUp(); + + /// + /// Gets the size of the specified image. + /// + /// The image source. + /// The image info. + OxyImageInfo GetImageInfo(OxyImage source); + + /// + /// Draws the specified portion of the specified at the specified location and with the specified size. + /// + /// The source. + /// The x-coordinate of the upper-left corner of the portion of the source image to draw. + /// The y-coordinate of the upper-left corner of the portion of the source image to draw. + /// Width of the portion of the source image to draw. + /// Height of the portion of the source image to draw. + /// The x-coordinate of the upper-left corner of drawn image. + /// The y-coordinate of the upper-left corner of drawn image. + /// The width of the drawn image. + /// The height of the drawn image. + /// The opacity. + /// interpolate if set to true. + void DrawImage(OxyImage source, uint srcX, uint srcY, uint srcWidth, uint srcHeight, double destX, double destY, double destWidth, double destHeight, double opacity, bool interpolate); + + /// + /// Sets the clip rectangle. + /// + /// The clip rectangle. + /// True if the clip rectangle was set. + bool SetClip(OxyRect rect); + + /// + /// Resets the clip rectangle. + /// + void ResetClip(); + } + + /// + /// Provides information about the size of an image. + /// + public class OxyImageInfo + { + /// + /// Gets or sets the width in pixels. + /// + /// + /// The width. + /// + public uint Width { get; set; } + + /// + /// Gets or sets the height in pixels. + /// + /// + /// The height. + /// + public uint Height { get; set; } + + /// + /// Gets or sets the horizontal resolution in dpi. + /// + /// + /// The dpi X. + /// + public double DpiX { get; set; } + + /// + /// Gets or sets the vertical resolution in dpi. + /// + /// + /// The dpi Y. + /// + public double DpiY { get; set; } + } +} \ No newline at end of file diff -r 88d699a65cc2 -r 5be8f2773237 External/OxyPlot/OxyPlot/Render/MagnitudeAxisRenderer.cs --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/External/OxyPlot/OxyPlot/Render/MagnitudeAxisRenderer.cs Sat Jun 08 16:53:22 2013 +0000 @@ -0,0 +1,145 @@ +// -------------------------------------------------------------------------------------------------------------------- +// +// The MIT License (MIT) +// +// Copyright (c) 2012 Oystein Bjorke +// +// Permission is hereby granted, free of charge, to any person obtaining a +// copy of this software and associated documentation files (the +// "Software"), to deal in the Software without restriction, including +// without limitation the rights to use, copy, modify, merge, publish, +// distribute, sublicense, and/or sell copies of the Software, and to +// permit persons to whom the Software is furnished to do so, subject to +// the following conditions: +// +// The above copyright notice and this permission notice shall be included +// in all copies or substantial portions of the Software. +// +// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS +// OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF +// MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. +// IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY +// CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, +// TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE +// SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. +// +// +// The magnitude axis renderer. +// +// -------------------------------------------------------------------------------------------------------------------- +namespace OxyPlot +{ + using System; + using System.Collections.Generic; + + using OxyPlot.Axes; + + /// + /// Provides functionality to render . + /// + public class MagnitudeAxisRenderer : AxisRendererBase + { + /// + /// Initializes a new instance of the class. + /// + /// + /// The render context. + /// + /// + /// The plot. + /// + public MagnitudeAxisRenderer(IRenderContext rc, PlotModel plot) + : base(rc, plot) + { + } + + /// + /// Renders the specified axis. + /// + /// The axis. + /// The pass. + /// Angle axis should not be null. + public override void Render(Axis axis, int pass) + { + base.Render(axis, pass); + + var angleAxis = this.Plot.DefaultAngleAxis as Axis; + if (axis.RelatedAxis != null) + { + angleAxis = axis.RelatedAxis; + } + + if (angleAxis == null) + { + throw new NullReferenceException("Angle axis should not be null."); + } + + if (axis.ShowMinorTicks) + { + // GetVerticalTickPositions(axis, axis.TickStyle, axis.MinorTickSize, out y0, out y1); + + foreach (double xValue in this.MinorTickValues) + { + if (xValue < axis.ActualMinimum || xValue > axis.ActualMaximum) + { + continue; + } + + if (this.MajorTickValues.Contains(xValue)) + { + continue; + } + + var pts = new List(); + for (double th = angleAxis.ActualMinimum; + th <= angleAxis.ActualMaximum + angleAxis.MinorStep * 0.01; + th += angleAxis.MinorStep * 0.1) + { + pts.Add(axis.Transform(xValue, th, angleAxis)); + } + + if (this.MinorPen != null) + { + this.rc.DrawLine(pts, this.MinorPen.Color, this.MinorPen.Thickness, this.MinorPen.DashArray); + } + + // RenderGridline(x, y + y0, x, y + y1, minorTickPen); + } + } + + // GetVerticalTickPositions(axis, axis.TickStyle, axis.MajorTickSize, out y0, out y1); + + foreach (double xValue in this.MajorTickValues) + { + if (xValue < axis.ActualMinimum || xValue > axis.ActualMaximum) + { + continue; + } + + var pts = new List(); + for (double th = angleAxis.ActualMinimum; + th <= angleAxis.ActualMaximum + angleAxis.MinorStep * 0.01; + th += angleAxis.MinorStep * 0.1) + { + pts.Add(axis.Transform(xValue, th, angleAxis)); + } + + if (this.MajorPen != null) + { + this.rc.DrawLine(pts, this.MajorPen.Color, this.MajorPen.Thickness, this.MajorPen.DashArray); + } + + // RenderGridline(x, y + y0, x, y + y1, majorTickPen); + // var pt = new ScreenPoint(x, istop ? y + y1 - TICK_DIST : y + y1 + TICK_DIST); + // string text = axis.FormatValue(xValue); + // double h = rc.MeasureText(text, axis.Font, axis.FontSize, axis.FontWeight).Height; + // rc.DrawText(pt, text, axis.LabelColor ?? plot.TextColor, + // axis.Font, axis.FontSize, axis.FontWeight, + // axis.Angle, + // HorizontalAlignment.Center, istop ? VerticalAlignment.Bottom : VerticalAlignment.Top); + // maxh = Math.Max(maxh, h); + } + } + + } +} \ No newline at end of file diff -r 88d699a65cc2 -r 5be8f2773237 External/OxyPlot/OxyPlot/Render/MathRenderingExtensions.cs --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/External/OxyPlot/OxyPlot/Render/MathRenderingExtensions.cs Sat Jun 08 16:53:22 2013 +0000 @@ -0,0 +1,347 @@ +// -------------------------------------------------------------------------------------------------------------------- +// +// The MIT License (MIT) +// +// Copyright (c) 2012 Oystein Bjorke +// +// Permission is hereby granted, free of charge, to any person obtaining a +// copy of this software and associated documentation files (the +// "Software"), to deal in the Software without restriction, including +// without limitation the rights to use, copy, modify, merge, publish, +// distribute, sublicense, and/or sell copies of the Software, and to +// permit persons to whom the Software is furnished to do so, subject to +// the following conditions: +// +// The above copyright notice and this permission notice shall be included +// in all copies or substantial portions of the Software. +// +// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS +// OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF +// MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. +// IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY +// CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, +// TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE +// SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. +// +// +// The math rendering extensions. +// +// -------------------------------------------------------------------------------------------------------------------- +namespace OxyPlot +{ + using System; + + /// + /// Provides functionality to render mathematic expressions (TeX syntax). + /// + public static class MathRenderingExtensions + { + /// + /// Initializes static members of the class. + /// + static MathRenderingExtensions() + { + SubAlignment = 0.6; + SubSize = 0.62; + SuperAlignment = 0; + SuperSize = 0.62; + } + + /// + /// Gets or sets the subscript alignment. + /// + private static double SubAlignment { get; set; } + + /// + /// Gets or sets the subscript size. + /// + private static double SubSize { get; set; } + + /// + /// Gets or sets the superscript alignment. + /// + private static double SuperAlignment { get; set; } + + /// + /// Gets or sets the superscript size. + /// + private static double SuperSize { get; set; } + + /// + /// Draws or measures text containing sub- and superscript. + /// + /// The render context. + /// The point. + /// The text. + /// Color of the text. + /// The font family. + /// The font size. + /// The font weight. + /// The angle. + /// The horizontal alignment. + /// The vertical alignment. + /// The maximum size of the text. + /// Measure the size of the text if set to true. + /// The size of the text. + /// + /// Subscript: H_{2}O + /// Superscript: E=mc^{2} + /// Both: A^{2}_{i,j} + /// + public static OxySize DrawMathText( + this IRenderContext rc, + ScreenPoint pt, + string text, + OxyColor textColor, + string fontFamily, + double fontSize, + double fontWeight, + double angle, + HorizontalAlignment ha, + VerticalAlignment va, + OxySize? maxsize, + bool measure) + { + if (string.IsNullOrEmpty(text)) + { + return OxySize.Empty; + } + + if (angle.Equals(0) && (text.Contains("^{") || text.Contains("_{"))) + { + double x = pt.X; + double y = pt.Y; + + // Measure + var size = InternalDrawMathText(rc, x, y, text, textColor, fontFamily, fontSize, fontWeight, true); + + switch (ha) + { + case HorizontalAlignment.Right: + x -= size.Width; + break; + case HorizontalAlignment.Center: + x -= size.Width * 0.5; + break; + } + + switch (va) + { + case VerticalAlignment.Bottom: + y -= size.Height; + break; + case VerticalAlignment.Middle: + y -= size.Height * 0.5; + break; + } + + InternalDrawMathText(rc, x, y, text, textColor, fontFamily, fontSize, fontWeight, false); + return measure ? size : OxySize.Empty; + } + + rc.DrawText(pt, text, textColor, fontFamily, fontSize, fontWeight, angle, ha, va, maxsize); + if (measure) + { + return rc.MeasureText(text, fontFamily, fontSize, fontWeight); + } + + return OxySize.Empty; + } + + /// + /// Draws text containing sub- and superscript. + /// + /// The render context. + /// The point. + /// The text. + /// Color of the text. + /// The font family. + /// The font size. + /// The font weight. + /// The angle. + /// The horizontal alignment. + /// The vertical alignment. + /// The maximum size of the text. + /// + /// Subscript: H_{2}O + /// Superscript: E=mc^{2} + /// Both: A^{2}_{i,j} + /// + public static void DrawMathText( + this IRenderContext rc, + ScreenPoint pt, + string text, + OxyColor textColor, + string fontFamily, + double fontSize, + double fontWeight, + double angle, + HorizontalAlignment ha, + VerticalAlignment va, + OxySize? maxsize = null) + { + DrawMathText(rc, pt, text, textColor, fontFamily, fontSize, fontWeight, angle, ha, va, maxsize, false); + } + + /// + /// The measure math text. + /// + /// + /// The render context. + /// + /// + /// The text. + /// + /// + /// The font family. + /// + /// + /// The font size. + /// + /// + /// The font weight. + /// + /// + /// The size of the text. + /// + public static OxySize MeasureMathText( + this IRenderContext rc, string text, string fontFamily, double fontSize, double fontWeight) + { + if (text.Contains("^{") || text.Contains("_{")) + { + return InternalDrawMathText(rc, 0, 0, text, null, fontFamily, fontSize, fontWeight, true); + } + + return rc.MeasureText(text, fontFamily, fontSize, fontWeight); + } + + /// + /// The internal draw math text. + /// + /// + /// The render context. + /// + /// + /// The x. + /// + /// + /// The y. + /// + /// + /// The s. + /// + /// + /// The text color. + /// + /// + /// The font family. + /// + /// + /// The font size. + /// + /// + /// The font weight. + /// + /// + /// The measure only. + /// + /// + /// The size of the text. + /// + private static OxySize InternalDrawMathText( + IRenderContext rc, + double x, + double y, + string s, + OxyColor textColor, + string fontFamily, + double fontSize, + double fontWeight, + bool measureOnly) + { + int i = 0; + + double currentX = x; + double maximumX = x; + double maxHeight = 0; + + // http://en.wikipedia.org/wiki/Subscript_and_superscript + double superscriptY = y + fontSize * SuperAlignment; + double superscriptFontSize = fontSize * SuperSize; + double subscriptY = y + fontSize * SubAlignment; + double subscriptFontSize = fontSize * SubSize; + + Func drawText = (xb, yb, text, fSize) => + { + if (!measureOnly) + { + rc.DrawText(new ScreenPoint(xb, yb), text, textColor, fontFamily, fSize, fontWeight); + } + + return rc.MeasureText(text, fontFamily, fSize, fontWeight); + }; + + while (i < s.Length) + { + // Superscript + if (i + 1 < s.Length && s[i] == '^' && s[i + 1] == '{') + { + int i1 = s.IndexOf('}', i); + if (i1 != -1) + { + string supString = s.Substring(i + 2, i1 - i - 2); + i = i1 + 1; + OxySize size = drawText(currentX, superscriptY, supString, superscriptFontSize); + if (currentX + size.Width > maximumX) + { + maximumX = currentX + size.Width; + } + + continue; + } + } + + // Subscript + if (i + 1 < s.Length && s[i] == '_' && s[i + 1] == '{') + { + int i1 = s.IndexOf('}', i); + if (i1 != -1) + { + string subString = s.Substring(i + 2, i1 - i - 2); + i = i1 + 1; + OxySize size = drawText(currentX, subscriptY, subString, subscriptFontSize); + if (currentX + size.Width > maximumX) + { + maximumX = currentX + size.Width; + } + + continue; + } + } + + // Regular text + int i2 = s.IndexOfAny("^_".ToCharArray(), i); + string regularString; + if (i2 == -1) + { + regularString = s.Substring(i); + i = s.Length; + } + else + { + regularString = s.Substring(i, i2 - i); + i = i2; + } + + currentX = maximumX + 2; + OxySize size2 = drawText(currentX, y, regularString, fontSize); + currentX += size2.Width + 2; + maxHeight = Math.Max(maxHeight, size2.Height); + maximumX = currentX; + } + + return new OxySize(maximumX - x, maxHeight); + } + + } +} \ No newline at end of file diff -r 88d699a65cc2 -r 5be8f2773237 External/OxyPlot/OxyPlot/Render/PlotRenderer.cs --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/External/OxyPlot/OxyPlot/Render/PlotRenderer.cs Sat Jun 08 16:53:22 2013 +0000 @@ -0,0 +1,159 @@ +// -------------------------------------------------------------------------------------------------------------------- +// +// The MIT License (MIT) +// +// Copyright (c) 2012 Oystein Bjorke +// +// Permission is hereby granted, free of charge, to any person obtaining a +// copy of this software and associated documentation files (the +// "Software"), to deal in the Software without restriction, including +// without limitation the rights to use, copy, modify, merge, publish, +// distribute, sublicense, and/or sell copies of the Software, and to +// permit persons to whom the Software is furnished to do so, subject to +// the following conditions: +// +// The above copyright notice and this permission notice shall be included +// in all copies or substantial portions of the Software. +// +// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS +// OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF +// MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. +// IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY +// CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, +// TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE +// SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. +// +// -------------------------------------------------------------------------------------------------------------------- +using System; + +namespace OxyPlot +{ + public class PlotRenderer + { + protected readonly PlotModel plot; + protected readonly IRenderContext rc; + + public PlotRenderer(IRenderContext rc, PlotModel p) + { + this.rc = rc; + plot = p; + } + + public void RenderTitle(string title, string subtitle) + { + OxySize size1 = rc.MeasureText(title, plot.TitleFont, plot.TitleFontSize, plot.TitleFontWeight); + OxySize size2 = rc.MeasureText(subtitle, plot.TitleFont, plot.TitleFontSize, plot.TitleFontWeight); + double height = size1.Height + size2.Height; + double dy = (plot.AxisMargins.Top - height) * 0.5; + double dx = (plot.Bounds.Left + plot.Bounds.Right) * 0.5; + + if (!String.IsNullOrEmpty(title)) + rc.DrawText( + new ScreenPoint(dx, dy), title, plot.TextColor, + plot.TitleFont, plot.TitleFontSize, plot.TitleFontWeight, + 0, + HorizontalTextAlign.Center, VerticalTextAlign.Top); + if (!String.IsNullOrEmpty(subtitle)) + rc.DrawText(new ScreenPoint(dx, dy + size1.Height), subtitle, plot.TextColor, + plot.TitleFont, plot.SubtitleFontSize, plot.SubtitleFontWeight, 0, + HorizontalTextAlign.Center, VerticalTextAlign.Top); + } + + public void RenderRect(OxyRect bounds, OxyColor fill, OxyColor borderColor, double borderThickness) + { + var border = new[] + { + new ScreenPoint(bounds.Left, bounds.Top), new ScreenPoint(bounds.Right, bounds.Top), + new ScreenPoint(bounds.Right, bounds.Bottom), new ScreenPoint(bounds.Left, bounds.Bottom), + new ScreenPoint(bounds.Left, bounds.Top) + }; + + rc.DrawPolygon(border, fill, borderColor, borderThickness, null, true); + } + + private static readonly double LEGEND_PADDING = 8; + + public void RenderLegends() + { + double maxWidth = 0; + double maxHeight = 0; + double totalHeight = 0; + + // Measure + foreach (var s in plot.Series) + { + if (String.IsNullOrEmpty(s.Title)) + continue; + var oxySize = rc.MeasureText(s.Title, plot.LegendFont, plot.LegendFontSize); + if (oxySize.Width > maxWidth) maxWidth = oxySize.Width; + if (oxySize.Height > maxHeight) maxHeight = oxySize.Height; + totalHeight += oxySize.Height; + } + + double lineLength = plot.LegendSymbolLength; + + // Arrange + double x0 = double.NaN, x1 = double.NaN, y0 = double.NaN; + + // padding padding + // lineLength + // y0 -----o---- seriesName + // x0 x1 + + double sign = 1; + if (plot.IsLegendOutsidePlotArea) + sign = -1; + + // Horizontal alignment + HorizontalTextAlign ha = HorizontalTextAlign.Left; + switch (plot.LegendPosition) + { + case LegendPosition.TopRight: + case LegendPosition.BottomRight: + x0 = plot.Bounds.Right - LEGEND_PADDING * sign; + x1 = x0 - lineLength * sign - LEGEND_PADDING * sign; + ha = sign == 1 ? HorizontalTextAlign.Right : HorizontalTextAlign.Left; + break; + case LegendPosition.TopLeft: + case LegendPosition.BottomLeft: + x0 = plot.Bounds.Left + LEGEND_PADDING * sign; + x1 = x0 + lineLength * sign + LEGEND_PADDING * sign; + ha = sign == 1 ? HorizontalTextAlign.Left : HorizontalTextAlign.Right; + break; + } + + // Vertical alignment + VerticalTextAlign va = VerticalTextAlign.Middle; + switch (plot.LegendPosition) + { + case LegendPosition.TopRight: + case LegendPosition.TopLeft: + y0 = plot.Bounds.Top + LEGEND_PADDING + maxHeight / 2; + break; + case LegendPosition.BottomRight: + case LegendPosition.BottomLeft: + y0 = plot.Bounds.Bottom - maxHeight + LEGEND_PADDING; + break; + } + + foreach (var s in plot.Series) + { + if (String.IsNullOrEmpty(s.Title)) + continue; + rc.DrawText(new ScreenPoint(x1, y0), + s.Title, plot.TextColor, + plot.LegendFont, plot.LegendFontSize, 500, 0, + ha, va); + OxyRect rect = new OxyRect(x0 - lineLength, y0 - maxHeight / 2, lineLength, maxHeight); + if (ha == HorizontalTextAlign.Left) + rect = new OxyRect(x0, y0 - maxHeight / 2, lineLength, maxHeight); + + s.RenderLegend(rc, rect); + if (plot.LegendPosition == LegendPosition.TopLeft || plot.LegendPosition == LegendPosition.TopRight) + y0 += maxHeight; + else + y0 -= maxHeight; + } + } + } +} \ No newline at end of file diff -r 88d699a65cc2 -r 5be8f2773237 External/OxyPlot/OxyPlot/Render/RenderContextBase.cs --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/External/OxyPlot/OxyPlot/Render/RenderContextBase.cs Sat Jun 08 16:53:22 2013 +0000 @@ -0,0 +1,423 @@ +// -------------------------------------------------------------------------------------------------------------------- +// +// The MIT License (MIT) +// +// Copyright (c) 2012 Oystein Bjorke +// +// Permission is hereby granted, free of charge, to any person obtaining a +// copy of this software and associated documentation files (the +// "Software"), to deal in the Software without restriction, including +// without limitation the rights to use, copy, modify, merge, publish, +// distribute, sublicense, and/or sell copies of the Software, and to +// permit persons to whom the Software is furnished to do so, subject to +// the following conditions: +// +// The above copyright notice and this permission notice shall be included +// in all copies or substantial portions of the Software. +// +// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS +// OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF +// MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. +// IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY +// CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, +// TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE +// SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. +// +// +// The abstract render context base class. +// +// -------------------------------------------------------------------------------------------------------------------- +namespace OxyPlot +{ + using System.Collections.Generic; + + /// + /// Provides an abstract base class for rendering contexts. + /// + public abstract class RenderContextBase : IRenderContext + { + /// + /// Initializes a new instance of the class. + /// + protected RenderContextBase() + { + this.RendersToScreen = true; + } + + /// + /// Gets or sets a value indicating whether the context renders to screen. + /// + /// + /// true if the context renders to screen; otherwise, false. + /// + public bool RendersToScreen { get; set; } + + /// + /// Draws an ellipse. + /// + /// + /// The rectangle. + /// + /// + /// The fill color. + /// + /// + /// The stroke color. + /// + /// + /// The thickness. + /// + public abstract void DrawEllipse(OxyRect rect, OxyColor fill, OxyColor stroke, double thickness); + + /// + /// Draws the collection of ellipses, where all have the same stroke and fill. + /// This performs better than calling DrawEllipse multiple times. + /// + /// + /// The rectangles. + /// + /// + /// The fill color. + /// + /// + /// The stroke color. + /// + /// + /// The stroke thickness. + /// + public virtual void DrawEllipses(IList rectangles, OxyColor fill, OxyColor stroke, double thickness) + { + foreach (var r in rectangles) + { + this.DrawEllipse(r, fill, stroke, thickness); + } + } + + /// + /// Draws the polyline from the specified points. + /// + /// + /// The points. + /// + /// + /// The stroke color. + /// + /// + /// The stroke thickness. + /// + /// + /// The dash array. + /// + /// + /// The line join type. + /// + /// + /// if set to true the shape will be aliased. + /// + public abstract void DrawLine( + IList points, + OxyColor stroke, + double thickness, + double[] dashArray, + OxyPenLineJoin lineJoin, + bool aliased); + + /// + /// Draws the multiple line segments defined by points (0,1) (2,3) (4,5) etc. + /// This should have better performance than calling DrawLine for each segment. + /// + /// + /// The points. + /// + /// + /// The stroke color. + /// + /// + /// The stroke thickness. + /// + /// + /// The dash array. + /// + /// + /// The line join type. + /// + /// + /// if set to true the shape will be aliased. + /// + public virtual void DrawLineSegments( + IList points, + OxyColor stroke, + double thickness, + double[] dashArray, + OxyPenLineJoin lineJoin, + bool aliased) + { + for (int i = 0; i + 1 < points.Count; i += 2) + { + this.DrawLine(new[] { points[i], points[i + 1] }, stroke, thickness, dashArray, lineJoin, aliased); + } + } + + /// + /// Draws the polygon from the specified points. The polygon can have stroke and/or fill. + /// + /// + /// The points. + /// + /// + /// The fill color. + /// + /// + /// The stroke color. + /// + /// + /// The stroke thickness. + /// + /// + /// The dash array. + /// + /// + /// The line join type. + /// + /// + /// if set to true the shape will be aliased. + /// + public abstract void DrawPolygon( + IList points, + OxyColor fill, + OxyColor stroke, + double thickness, + double[] dashArray, + OxyPenLineJoin lineJoin, + bool aliased); + + /// + /// Draws a collection of polygons, where all polygons have the same stroke and fill. + /// This performs better than calling DrawPolygon multiple times. + /// + /// + /// The polygons. + /// + /// + /// The fill color. + /// + /// + /// The stroke color. + /// + /// + /// The stroke thickness. + /// + /// + /// The dash array. + /// + /// + /// The line join type. + /// + /// + /// if set to true the shape will be aliased. + /// + public virtual void DrawPolygons( + IList> polygons, + OxyColor fill, + OxyColor stroke, + double thickness, + double[] dashArray, + OxyPenLineJoin lineJoin, + bool aliased) + { + foreach (var polygon in polygons) + { + this.DrawPolygon(polygon, fill, stroke, thickness, dashArray, lineJoin, aliased); + } + } + + /// + /// Draws the rectangle. + /// + /// + /// The rectangle. + /// + /// + /// The fill color. + /// + /// + /// The stroke color. + /// + /// + /// The stroke thickness. + /// + public abstract void DrawRectangle(OxyRect rect, OxyColor fill, OxyColor stroke, double thickness); + + /// + /// Draws a collection of rectangles, where all have the same stroke and fill. + /// This performs better than calling DrawRectangle multiple times. + /// + /// + /// The rectangles. + /// + /// + /// The fill color. + /// + /// + /// The stroke color. + /// + /// + /// The stroke thickness. + /// + public virtual void DrawRectangles(IList rectangles, OxyColor fill, OxyColor stroke, double thickness) + { + foreach (var r in rectangles) + { + this.DrawRectangle(r, fill, stroke, thickness); + } + } + + /// + /// Draws the text. + /// + /// + /// The p. + /// + /// + /// The text. + /// + /// + /// The fill color. + /// + /// + /// The font family. + /// + /// + /// Size of the font. + /// + /// + /// The font weight. + /// + /// + /// The rotation angle. + /// + /// + /// The horizontal alignment. + /// + /// + /// The vertical alignment. + /// + /// + /// The maximum size of the text. + /// + public abstract void DrawText( + ScreenPoint p, + string text, + OxyColor fill, + string fontFamily, + double fontSize, + double fontWeight, + double rotate, + HorizontalAlignment halign, + VerticalAlignment valign, + OxySize? maxSize); + + /// + /// Measures the text. + /// + /// + /// The text. + /// + /// + /// The font family. + /// + /// + /// Size of the font. + /// + /// + /// The font weight. + /// + /// + /// The text size. + /// + public abstract OxySize MeasureText(string text, string fontFamily, double fontSize, double fontWeight); + + /// + /// Sets the tool tip for the following items. + /// + /// + /// The text in the tooltip. + /// + /// + /// This is only used in the plot controls. + /// + public virtual void SetToolTip(string text) + { + } + + /// + /// Cleans up resources not in use. + /// + /// + /// This method is called at the end of each rendering. + /// + public virtual void CleanUp() + { + } + + /// + /// Gets the size of the specified image. + /// + /// The image source. + /// + /// The image info. + /// + public virtual OxyImageInfo GetImageInfo(OxyImage source) + { + return null; + } + + /// + /// Draws the image. + /// + /// The source. + /// The SRC X. + /// The SRC Y. + /// Width of the SRC. + /// Height of the SRC. + /// The x. + /// The y. + /// The w. + /// The h. + /// The opacity. + /// interpolate if set to true. + public virtual void DrawImage( + OxyImage source, + uint srcX, + uint srcY, + uint srcWidth, + uint srcHeight, + double x, + double y, + double w, + double h, + double opacity, + bool interpolate) + { + } + + /// + /// Sets the clip rectangle. + /// + /// The clip rectangle. + /// + /// True if the clip rectangle was set. + /// + public virtual bool SetClip(OxyRect rect) + { + return false; + } + + /// + /// Resets the clip rectangle. + /// + public virtual void ResetClip() + { + } + } +} \ No newline at end of file diff -r 88d699a65cc2 -r 5be8f2773237 External/OxyPlot/OxyPlot/Render/RenderingExtensions.cs --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/External/OxyPlot/OxyPlot/Render/RenderingExtensions.cs Sat Jun 08 16:53:22 2013 +0000 @@ -0,0 +1,1109 @@ +// -------------------------------------------------------------------------------------------------------------------- +// +// The MIT License (MIT) +// +// Copyright (c) 2012 Oystein Bjorke +// +// Permission is hereby granted, free of charge, to any person obtaining a +// copy of this software and associated documentation files (the +// "Software"), to deal in the Software without restriction, including +// without limitation the rights to use, copy, modify, merge, publish, +// distribute, sublicense, and/or sell copies of the Software, and to +// permit persons to whom the Software is furnished to do so, subject to +// the following conditions: +// +// The above copyright notice and this permission notice shall be included +// in all copies or substantial portions of the Software. +// +// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS +// OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF +// MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. +// IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY +// CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, +// TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE +// SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. +// +// +// The rendering extensions. +// +// -------------------------------------------------------------------------------------------------------------------- + +namespace OxyPlot +{ + using System; + using System.Collections.Generic; + using System.Linq; + + /// + /// Provides extension methods for . + /// + public static class RenderingExtensions + { + /* Length constants used to draw triangles and stars + ___ + /\ | + / \ | + / \ | M2 + / \ | + / \ | + / + \ --- + / \ | + / \ | M1 + /________________\ _|_ + |--------|-------| + 1 1 + + | + \ | / --- + \ | / | M3 + \ | / | + ---------+-------- --- + / | \ | M3 + / | \ | + / | \ --- + | + |-----|-----| + M3 M3 + */ + + /// + /// The vertical distance to the bottom points of the triangles. + /// + private static readonly double M1 = Math.Tan(Math.PI / 6); + + /// + /// The vertical distance to the top points of the triangles . + /// + private static readonly double M2 = Math.Sqrt(1 + (M1 * M1)); + + /// + /// The horizontal/vertical distance to the end points of the stars. + /// + private static readonly double M3 = Math.Tan(Math.PI / 4); + + /// + /// Draws the clipped line. + /// + /// The render context. + /// The points. + /// The clipping rectangle. + /// The squared minimum distance. + /// The stroke. + /// The stroke thickness. + /// The line style. + /// The line join. + /// if set to true [aliased]. + /// The points rendered callback. + public static void DrawClippedLine( + this IRenderContext rc, + IList points, + OxyRect clippingRectangle, + double minDistSquared, + OxyColor stroke, + double strokeThickness, + LineStyle lineStyle, + OxyPenLineJoin lineJoin, + bool aliased, + Action> pointsRendered = null) + { + var clipping = new CohenSutherlandClipping(clippingRectangle.Left, clippingRectangle.Right, clippingRectangle.Top, clippingRectangle.Bottom); + + var pts = new List(); + int n = points.Count; + if (n > 0) + { + if (n == 1) + { + pts.Add(points[0]); + } + + var last = points[0]; + for (int i = 1; i < n; i++) + { + var s0 = points[i - 1]; + var s1 = points[i]; + + // Clipped version of this and next point. + var sc0 = s0; + var sc1 = s1; + bool isInside = clipping.ClipLine(ref sc0, ref sc1); + + if (!isInside) + { + // keep the previous coordinate + continue; + } + + // render from s0c-s1c + double dx = sc1.x - last.x; + double dy = sc1.y - last.y; + + if ((dx * dx) + (dy * dy) > minDistSquared || i == 1 || i == n - 1) + { + if (!sc0.Equals(last) || i == 1) + { + pts.Add(sc0); + } + + pts.Add(sc1); + last = sc1; + } + + // render the line if we are leaving the clipping region);); + if (!clipping.IsInside(s1)) + { + if (pts.Count > 0) + { + EnsureNonEmptyLineIsVisible(pts); + rc.DrawLine(pts, stroke, strokeThickness, lineStyle.GetDashArray(), lineJoin, aliased); + if (pointsRendered != null) + { + pointsRendered(pts); + } + + pts = new List(); + } + } + } + + if (pts.Count > 0) + { + EnsureNonEmptyLineIsVisible(pts); + rc.DrawLine(pts, stroke, strokeThickness, lineStyle.GetDashArray(), lineJoin, aliased); + + // Execute the 'callback'. + if (pointsRendered != null) + { + pointsRendered(pts); + } + } + } + } + + /// + /// Draws the clipped line segments. + /// + /// The render context. + /// The points. + /// The clipping rectangle. + /// The stroke. + /// The stroke thickness. + /// The line style. + /// The line join. + /// if set to true [aliased]. + public static void DrawClippedLineSegments( + this IRenderContext rc, + IList points, + OxyRect clippingRectangle, + OxyColor stroke, + double strokeThickness, + LineStyle lineStyle, + OxyPenLineJoin lineJoin, + bool aliased) + { + if (rc.SetClip(clippingRectangle)) + { + rc.DrawLineSegments(points, stroke, strokeThickness, lineStyle.GetDashArray(), lineJoin, aliased); + rc.ResetClip(); + return; + } + + var clipping = new CohenSutherlandClipping(clippingRectangle.Left, clippingRectangle.Right, clippingRectangle.Top, clippingRectangle.Bottom); + + var clippedPoints = new List(points.Count); + for (int i = 0; i + 1 < points.Count; i += 2) + { + var s0 = points[i]; + var s1 = points[i + 1]; + if (clipping.ClipLine(ref s0, ref s1)) + { + clippedPoints.Add(s0); + clippedPoints.Add(s1); + } + } + + rc.DrawLineSegments(clippedPoints, stroke, strokeThickness, lineStyle.GetDashArray(), lineJoin, aliased); + } + + /// + /// Draws the specified image. + /// + /// The render context. + /// The image. + /// The destination X position. + /// The destination Y position. + /// The width. + /// The height. + /// The opacity. + /// Interpolate the image if set to true. + public static void DrawImage( + this IRenderContext rc, + OxyImage image, + double x, + double y, + double w, + double h, + double opacity, + bool interpolate) + { + var info = rc.GetImageInfo(image); + if (info == null) + { + return; + } + + rc.DrawImage(image, 0, 0, info.Width, info.Height, x, y, w, h, opacity, interpolate); + } + + /// + /// Draws the clipped image. + /// + /// The render context. + /// The clipping rectangle. + /// The source. + /// The destination X position. + /// The destination Y position. + /// The width. + /// The height. + /// The opacity. + /// interpolate if set to true. + public static void DrawClippedImage( + this IRenderContext rc, + OxyRect clippingRect, + OxyImage source, + double x, + double y, + double w, + double h, + double opacity, + bool interpolate) + { + if (x > clippingRect.Right || x + w < clippingRect.Left || y > clippingRect.Bottom || y + h < clippingRect.Top) + { + return; + } + + if (rc.SetClip(clippingRect)) + { + // The render context supports clipping, then we can draw the whole image + rc.DrawImage(source, x, y, w, h, opacity, interpolate); + rc.ResetClip(); + return; + } + + // The render context does not support clipping, we must calculate the rectangle + var info = rc.GetImageInfo(source); + if (info == null) + { + return; + } + + // Fint the positions of the clipping rectangle normalized to image coordinates (0,1) + var i0 = (clippingRect.Left - x) / w; + var i1 = (clippingRect.Right - x) / w; + var j0 = (clippingRect.Top - y) / h; + var j1 = (clippingRect.Bottom - y) / h; + + // Find the origin of the clipped source rectangle + var srcx = i0 < 0 ? 0u : i0 * info.Width; + var srcy = j0 < 0 ? 0u : j0 * info.Height; + srcx = (int)Math.Ceiling(srcx); + srcy = (int)Math.Ceiling(srcy); + + // Find the size of the clipped source rectangle + var srcw = i1 > 1 ? info.Width - srcx : (i1 * info.Width) - srcx; + var srch = j1 > 1 ? info.Height - srcy : (j1 * info.Height) - srcy; + srcw = (int)srcw; + srch = (int)srch; + + if ((int)srcw <= 0 || (int)srch <= 0) + { + return; + } + + // The clipped destination rectangle + var destx = i0 < 0 ? x : x + (srcx / info.Width * w); + var desty = j0 < 0 ? y : y + (srcy / info.Height * h); + var destw = w * srcw / info.Width; + var desth = h * srch / info.Height; + + rc.DrawImage(source, (uint)srcx, (uint)srcy, (uint)srcw, (uint)srch, destx, desty, destw, desth, opacity, interpolate); + } + + /// + /// Draws the polygon within the specified clipping rectangle. + /// + /// + /// The render context. + /// + /// + /// The points. + /// + /// + /// The clipping rectangle. + /// + /// + /// The squared minimum distance between points. + /// + /// + /// The fill. + /// + /// + /// The stroke. + /// + /// + /// The stroke thickness. + /// + /// + /// The line style. + /// + /// + /// The line join. + /// + /// + /// The aliased. + /// + public static void DrawClippedPolygon( + this IRenderContext rc, + IList points, + OxyRect clippingRectangle, + double minDistSquared, + OxyColor fill, + OxyColor stroke, + double strokeThickness = 1.0, + LineStyle lineStyle = LineStyle.Solid, + OxyPenLineJoin lineJoin = OxyPenLineJoin.Miter, + bool aliased = false) + { + if (rc.SetClip(clippingRectangle)) + { + rc.DrawPolygon(points, fill, stroke, strokeThickness, lineStyle.GetDashArray(), lineJoin, aliased); + rc.ResetClip(); + return; + } + + var clippedPoints = SutherlandHodgmanClipping.ClipPolygon(clippingRectangle, points); + + rc.DrawPolygon( + clippedPoints, fill, stroke, strokeThickness, lineStyle.GetDashArray(), lineJoin, aliased); + } + + /// + /// Draws the clipped rectangle. + /// + /// + /// The render context. + /// + /// + /// The rectangle to draw. + /// + /// + /// The clipping rectangle. + /// + /// + /// The fill color. + /// + /// + /// The stroke color. + /// + /// + /// The stroke thickness. + /// + public static void DrawClippedRectangle( + this IRenderContext rc, + OxyRect rect, + OxyRect clippingRectangle, + OxyColor fill, + OxyColor stroke, + double thickness) + { + if (rc.SetClip(clippingRectangle)) + { + rc.DrawRectangle(rect, fill, stroke, thickness); + rc.ResetClip(); + return; + } + + var clippedRect = ClipRect(rect, clippingRectangle); + if (clippedRect == null) + { + return; + } + + rc.DrawRectangle(clippedRect.Value, fill, stroke, thickness); + } + + /// + /// Draws the clipped rectangle as a polygon. + /// + /// + /// The render context. + /// + /// + /// The rectangle to draw. + /// + /// + /// The clipping rectangle. + /// + /// + /// The fill color. + /// + /// + /// The stroke color. + /// + /// + /// The stroke thickness. + /// + public static void DrawClippedRectangleAsPolygon( + this IRenderContext rc, + OxyRect rect, + OxyRect clippingRectangle, + OxyColor fill, + OxyColor stroke, + double thickness) + { + if (rc.SetClip(clippingRectangle)) + { + rc.DrawRectangleAsPolygon(rect, fill, stroke, thickness); + rc.ResetClip(); + return; + } + + var clippedRect = ClipRect(rect, clippingRectangle); + if (clippedRect == null) + { + return; + } + + rc.DrawRectangleAsPolygon(clippedRect.Value, fill, stroke, thickness); + } + + /// + /// Draws a clipped ellipse. + /// + /// The render context. + /// The clipping rectangle. + /// The rectangle. + /// The fill color. + /// The stroke color. + /// The stroke thickness. + /// The number of points around the ellipse. + public static void DrawClippedEllipse( + this IRenderContext rc, + OxyRect clippingRectangle, + OxyRect rect, + OxyColor fill, + OxyColor stroke, + double thickness, + int n = 100) + { + if (rc.SetClip(clippingRectangle)) + { + rc.DrawEllipse(rect, fill, stroke, thickness); + rc.ResetClip(); + return; + } + + var points = new ScreenPoint[n]; + double cx = (rect.Left + rect.Right) / 2; + double cy = (rect.Top + rect.Bottom) / 2; + double rx = (rect.Right - rect.Left) / 2; + double ry = (rect.Bottom - rect.Top) / 2; + for (int i = 0; i < n; i++) + { + double a = Math.PI * 2 * i / (n - 1); + points[i] = new ScreenPoint(cx + (rx * Math.Cos(a)), cy + (ry * Math.Sin(a))); + } + + rc.DrawClippedPolygon(points, clippingRectangle, 4, fill, stroke, thickness); + } + + /// + /// Draws the clipped text. + /// + /// The rendering context. + /// The clipping rectangle. + /// The position. + /// The text. + /// The fill color. + /// The font family. + /// Size of the font. + /// The font weight. + /// The rotation angle. + /// The horizontal align. + /// The vertical align. + /// Size of the max. + public static void DrawClippedText( + this IRenderContext rc, + OxyRect clippingRectangle, + ScreenPoint p, + string text, + OxyColor fill, + string fontFamily = null, + double fontSize = 10, + double fontWeight = 500, + double rotate = 0, + HorizontalAlignment horizontalAlignment = HorizontalAlignment.Left, + VerticalAlignment verticalAlignment = VerticalAlignment.Top, + OxySize? maxSize = null) + { + if (rc.SetClip(clippingRectangle)) + { + rc.DrawText(p, text, fill, fontFamily, fontSize, fontWeight, rotate, horizontalAlignment, verticalAlignment, maxSize); + rc.ResetClip(); + return; + } + + // fall back simply check position + if (clippingRectangle.Contains(p.X, p.Y)) + { + rc.DrawText(p, text, fill, fontFamily, fontSize, fontWeight, rotate, horizontalAlignment, verticalAlignment, maxSize); + } + } + + /// + /// Draws a line specified by coordinates. + /// + /// + /// The render context. + /// + /// + /// The x0. + /// + /// + /// The y0. + /// + /// + /// The x1. + /// + /// + /// The y1. + /// + /// + /// The pen. + /// + /// + /// Aliased line if set to true. + /// + public static void DrawLine( + this IRenderContext rc, double x0, double y0, double x1, double y1, OxyPen pen, bool aliased = true) + { + if (pen == null) + { + return; + } + + rc.DrawLine( + new[] { new ScreenPoint(x0, y0), new ScreenPoint(x1, y1) }, + pen.Color, + pen.Thickness, + pen.DashArray, + pen.LineJoin, + aliased); + } + + /// + /// Draws the line segments. + /// + /// + /// The render context. + /// + /// + /// The points. + /// + /// + /// The pen. + /// + /// + /// if set to true [aliased]. + /// + public static void DrawLineSegments( + this IRenderContext rc, IList points, OxyPen pen, bool aliased = true) + { + if (pen == null) + { + return; + } + + rc.DrawLineSegments(points, pen.Color, pen.Thickness, pen.DashArray, pen.LineJoin, aliased); + } + + /// + /// Renders the marker. + /// + /// The render context. + /// The center point of the marker. + /// The clipping rectangle. + /// The marker type. + /// The outline. + /// The size of the marker. + /// The fill color. + /// The stroke color. + /// The stroke thickness. + public static void DrawMarker( + this IRenderContext rc, + ScreenPoint p, + OxyRect clippingRect, + MarkerType type, + IList outline, + double size, + OxyColor fill, + OxyColor stroke, + double strokeThickness) + { + rc.DrawMarkers(new[] { p }, clippingRect, type, outline, new[] { size }, fill, stroke, strokeThickness); + } + + /// + /// Draws a list of markers. + /// + /// + /// The render context. + /// + /// + /// The marker points. + /// + /// + /// The clipping rectangle. + /// + /// + /// Type of the marker. + /// + /// + /// The marker outline. + /// + /// + /// Size of the marker. + /// + /// + /// The marker fill. + /// + /// + /// The marker stroke. + /// + /// + /// The marker stroke thickness. + /// + /// + /// The resolution. + /// + /// + /// The bin Offset. + /// + public static void DrawMarkers( + this IRenderContext rc, + IList markerPoints, + OxyRect clippingRect, + MarkerType markerType, + IList markerOutline, + double markerSize, + OxyColor markerFill, + OxyColor markerStroke, + double markerStrokeThickness, + int resolution = 0, + ScreenPoint binOffset = new ScreenPoint()) + { + DrawMarkers( + rc, + markerPoints, + clippingRect, + markerType, + markerOutline, + new[] { markerSize }, + markerFill, + markerStroke, + markerStrokeThickness, + resolution, + binOffset); + } + + /// + /// Draws a list of markers. + /// + /// + /// The render context. + /// + /// + /// The marker points. + /// + /// + /// The clipping rectangle. + /// + /// + /// Type of the marker. + /// + /// + /// The marker outline. + /// + /// + /// Size of the markers. + /// + /// + /// The marker fill. + /// + /// + /// The marker stroke. + /// + /// + /// The marker stroke thickness. + /// + /// + /// The resolution. + /// + /// + /// The bin Offset. + /// + public static void DrawMarkers( + this IRenderContext rc, + IList markerPoints, + OxyRect clippingRect, + MarkerType markerType, + IList markerOutline, + IList markerSize, + OxyColor markerFill, + OxyColor markerStroke, + double markerStrokeThickness, + int resolution = 0, + ScreenPoint binOffset = new ScreenPoint()) + { + if (markerType == MarkerType.None) + { + return; + } + + int n = markerPoints.Count; + var ellipses = new List(n); + var rects = new List(n); + var polygons = new List>(n); + var lines = new List(n); + + var hashset = new Dictionary(); + + int i = 0; + + double minx = clippingRect.Left; + double maxx = clippingRect.Right; + double miny = clippingRect.Top; + double maxy = clippingRect.Bottom; + + foreach (var p in markerPoints) + { + if (resolution > 1) + { + var x = (int)((p.X - binOffset.X) / resolution); + var y = (int)((p.Y - binOffset.Y) / resolution); + uint hash = (uint)(x << 16) + (uint)y; + if (hashset.ContainsKey(hash)) + { + i++; + continue; + } + + hashset.Add(hash, true); + } + + bool outside = p.x < minx || p.x > maxx || p.y < miny || p.y > maxy; + if (!outside) + { + int j = i < markerSize.Count ? i : 0; + AddMarkerGeometry(p, markerType, markerOutline, markerSize[j], ellipses, rects, polygons, lines); + } + + i++; + } + + if (ellipses.Count > 0) + { + rc.DrawEllipses(ellipses, markerFill, markerStroke, markerStrokeThickness); + } + + if (rects.Count > 0) + { + rc.DrawRectangles(rects, markerFill, markerStroke, markerStrokeThickness); + } + + if (polygons.Count > 0) + { + rc.DrawPolygons(polygons, markerFill, markerStroke, markerStrokeThickness); + } + + if (lines.Count > 0) + { + rc.DrawLineSegments(lines, markerStroke, markerStrokeThickness); + } + } + + /// + /// Draws the rectangle as an aliased polygon. + /// (makes sure pixel alignment is the same as for lines) + /// + /// + /// The render context. + /// + /// + /// The rectangle. + /// + /// + /// The fill. + /// + /// + /// The stroke. + /// + /// + /// The thickness. + /// + public static void DrawRectangleAsPolygon( + this IRenderContext rc, OxyRect rect, OxyColor fill, OxyColor stroke, double thickness) + { + var sp0 = new ScreenPoint(rect.Left, rect.Top); + var sp1 = new ScreenPoint(rect.Right, rect.Top); + var sp2 = new ScreenPoint(rect.Right, rect.Bottom); + var sp3 = new ScreenPoint(rect.Left, rect.Bottom); + rc.DrawPolygon(new[] { sp0, sp1, sp2, sp3 }, fill, stroke, thickness, null, OxyPenLineJoin.Miter, true); + } + + /// + /// Draws the rectangle as an aliased polygon. + /// (makes sure pixel alignment is the same as for lines) + /// + /// + /// The render context. + /// + /// + /// The rectangle. + /// + /// + /// The fill. + /// + /// + /// The stroke. + /// + /// + /// The thickness. + /// + public static void DrawRectangleAsPolygon( + this IRenderContext rc, OxyRect rect, OxyColor fill, OxyColor stroke, OxyThickness thickness) + { + if (thickness.Left.Equals(thickness.Right) && thickness.Left.Equals(thickness.Top) + && thickness.Left.Equals(thickness.Bottom)) + { + DrawRectangleAsPolygon(rc, rect, fill, stroke, thickness.Left); + return; + } + + var sp0 = new ScreenPoint(rect.Left, rect.Top); + var sp1 = new ScreenPoint(rect.Right, rect.Top); + var sp2 = new ScreenPoint(rect.Right, rect.Bottom); + var sp3 = new ScreenPoint(rect.Left, rect.Bottom); + rc.DrawPolygon(new[] { sp0, sp1, sp2, sp3 }, fill, null, 0, null, OxyPenLineJoin.Miter, true); + rc.DrawPolygon(new[] { sp0, sp1 }, null, stroke, thickness.Top, null, OxyPenLineJoin.Miter, true); + rc.DrawPolygon(new[] { sp1, sp2 }, null, stroke, thickness.Right, null, OxyPenLineJoin.Miter, true); + rc.DrawPolygon(new[] { sp2, sp3 }, null, stroke, thickness.Bottom, null, OxyPenLineJoin.Miter, true); + rc.DrawPolygon(new[] { sp3, sp0 }, null, stroke, thickness.Left, null, OxyPenLineJoin.Miter, true); + } + + /// + /// Adds a marker geometry. + /// + /// + /// The position of the marker. + /// + /// + /// The type. + /// + /// + /// The outline. + /// + /// + /// The size. + /// + /// + /// The ellipse collection. + /// + /// + /// The rectangle collection. + /// + /// + /// The polygon collection. + /// + /// + /// The line collection. + /// + private static void AddMarkerGeometry( + ScreenPoint p, + MarkerType type, + IEnumerable outline, + double size, + IList ellipses, + IList rects, + IList> polygons, + IList lines) + { + if (type == MarkerType.Custom) + { + if (outline == null) + { + throw new ArgumentNullException("outline", "The outline should be set when MarkerType is 'Custom'."); + } + + var poly = outline.Select(o => new ScreenPoint(p.X + (o.x * size), p.Y + (o.y * size))).ToList(); + polygons.Add(poly); + return; + } + + switch (type) + { + case MarkerType.Circle: + { + ellipses.Add(new OxyRect(p.x - size, p.y - size, size * 2, size * 2)); + break; + } + + case MarkerType.Square: + { + rects.Add(new OxyRect(p.x - size, p.y - size, size * 2, size * 2)); + break; + } + + case MarkerType.Diamond: + { + polygons.Add( + new[] + { + new ScreenPoint(p.x, p.y - (M2 * size)), new ScreenPoint(p.x + (M2 * size), p.y), + new ScreenPoint(p.x, p.y + (M2 * size)), new ScreenPoint(p.x - (M2 * size), p.y) + }); + break; + } + + case MarkerType.Triangle: + { + polygons.Add( + new[] + { + new ScreenPoint(p.x - size, p.y + (M1 * size)), + new ScreenPoint(p.x + size, p.y + (M1 * size)), new ScreenPoint(p.x, p.y - (M2 * size)) + }); + break; + } + + case MarkerType.Plus: + case MarkerType.Star: + { + lines.Add(new ScreenPoint(p.x - size, p.y)); + lines.Add(new ScreenPoint(p.x + size, p.y)); + lines.Add(new ScreenPoint(p.x, p.y - size)); + lines.Add(new ScreenPoint(p.x, p.y + size)); + break; + } + } + + switch (type) + { + case MarkerType.Cross: + case MarkerType.Star: + { + lines.Add(new ScreenPoint(p.x - (size * M3), p.y - (size * M3))); + lines.Add(new ScreenPoint(p.x + (size * M3), p.y + (size * M3))); + lines.Add(new ScreenPoint(p.x - (size * M3), p.y + (size * M3))); + lines.Add(new ScreenPoint(p.x + (size * M3), p.y - (size * M3))); + break; + } + } + } + + /// + /// Calculates the clipped version of a rectangle. + /// + /// + /// The rectangle to clip. + /// + /// + /// The clipping rectangle. + /// + /// + /// The clipped rectangle, or null if the rectangle is outside the clipping area. + /// + private static OxyRect? ClipRect(OxyRect rect, OxyRect clippingRectangle) + { + if (rect.Right < clippingRectangle.Left) + { + return null; + } + + if (rect.Left > clippingRectangle.Right) + { + return null; + } + + if (rect.Top > clippingRectangle.Bottom) + { + return null; + } + + if (rect.Bottom < clippingRectangle.Top) + { + return null; + } + + if (rect.Right > clippingRectangle.Right) + { + rect.Right = clippingRectangle.Right; + } + + if (rect.Left < clippingRectangle.Left) + { + rect.Width = rect.Right - clippingRectangle.Left; + rect.Left = clippingRectangle.Left; + } + + if (rect.Top < clippingRectangle.Top) + { + rect.Height = rect.Bottom - clippingRectangle.Top; + rect.Top = clippingRectangle.Top; + } + + if (rect.Bottom > clippingRectangle.Bottom) + { + rect.Bottom = clippingRectangle.Bottom; + } + + if (rect.Width <= 0 || rect.Height <= 0) + { + return null; + } + + return rect; + } + + /// + /// Makes sure that a non empty line is visible. + /// + /// The points (screen coordinates). + /// + /// If the line contains one point, another point is added. + /// If the line contains two points at the same position, the points are moved 2 pixels apart. + /// + private static void EnsureNonEmptyLineIsVisible(IList pts) + { + // Check if the line contains two points and they are at the same point + if (pts.Count == 2) + { + if (pts[0].DistanceTo(pts[1]) < 1) + { + // Modify to a small horizontal line to make sure it is being rendered + pts[1] = new ScreenPoint(pts[0].X + 1, pts[0].Y); + pts[0] = new ScreenPoint(pts[0].X - 1, pts[0].Y); + } + } + + // Check if the line contains a single point + if (pts.Count == 1) + { + // Add a second point to make sure the line is being rendered as a small dot + pts.Add(new ScreenPoint(pts[0].X + 1, pts[0].Y)); + pts[0] = new ScreenPoint(pts[0].X - 1, pts[0].Y); + } + } + } +} \ No newline at end of file diff -r 88d699a65cc2 -r 5be8f2773237 External/OxyPlot/OxyPlot/Render/VerticalAxisRenderer.cs --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/External/OxyPlot/OxyPlot/Render/VerticalAxisRenderer.cs Sat Jun 08 16:53:22 2013 +0000 @@ -0,0 +1,318 @@ +// -------------------------------------------------------------------------------------------------------------------- +// +// The MIT License (MIT) +// +// Copyright (c) 2012 Oystein Bjorke +// +// Permission is hereby granted, free of charge, to any person obtaining a +// copy of this software and associated documentation files (the +// "Software"), to deal in the Software without restriction, including +// without limitation the rights to use, copy, modify, merge, publish, +// distribute, sublicense, and/or sell copies of the Software, and to +// permit persons to whom the Software is furnished to do so, subject to +// the following conditions: +// +// The above copyright notice and this permission notice shall be included +// in all copies or substantial portions of the Software. +// +// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS +// OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF +// MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. +// IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY +// CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, +// TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE +// SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. +// +// +// Gets the rotated alignments given the specified angle. +// +// -------------------------------------------------------------------------------------------------------------------- +using System; +using System.Diagnostics; + +namespace OxyPlot +{ + public class VerticalAxisRendererBase : AxisRendererBase + { + public VerticalAxisRendererBase(IRenderContext rc, PlotModel plot) + : base(rc, plot) + { + } + + public override void Render(Axis axis) + { + base.Render(axis); + + var perpendicularAxis = Plot.DefaultXAxis; + bool isHorizontal = true; + + // Axis position (x or y screen coordinate) + double apos = 0; + + switch (axis.Position) + { + case AxisPosition.Left: + apos = Plot.PlotArea.Left; + isHorizontal = false; + break; + case AxisPosition.Right: + apos = Plot.PlotArea.Right; + isHorizontal = false; + break; + case AxisPosition.Top: + apos = Plot.PlotArea.Top; + perpendicularAxis = Plot.DefaultYAxis; + break; + case AxisPosition.Bottom: + apos = Plot.PlotArea.Bottom; + perpendicularAxis = Plot.DefaultYAxis; + break; + } + + if (axis.PositionAtZeroCrossing) + { + apos = perpendicularAxis.Transform(0); + } + + double a0, a1; + + if (axis.ShowMinorTicks) + { + GetTickPositions(axis, axis.TickStyle, axis.MinorTickSize, axis.Position, out a0, out a1); + + foreach (double value in MinorTickValues) + { + if (value < axis.ActualMinimum || value > axis.ActualMaximum) + { + continue; + } + + if (MajorTickValues.Contains(value)) + { + continue; + } + + double transformedValue = axis.Transform(value); + + if (MinorPen != null) + { + if (isHorizontal) + { + rc.DrawLine(transformedValue, Plot.PlotArea.Top, transformedValue, Plot.PlotArea.Bottom, MinorPen); + + } + else + { + rc.DrawLine(Plot.PlotArea.Left, transformedValue, Plot.PlotArea.Right, transformedValue, MinorPen); + } + } + if (isHorizontal) + { + rc.DrawLine(transformedValue, apos + a0, transformedValue, apos + a1, MinorTickPen); + + } + else + { + rc.DrawLine(apos + a0, transformedValue, apos + a1, transformedValue, MinorTickPen); + } + } + } + + GetTickPositions(axis, axis.TickStyle, axis.MajorTickSize, axis.Position, out a0, out a1); + + double maxWidth = 0; + double maxHeight = 0; + + foreach (double value in MajorTickValues) + { + if (value < axis.ActualMinimum || value > axis.ActualMaximum) + continue; + + double transformedValue = axis.Transform(value); + + if (MajorPen != null) + { + if (isHorizontal) + { + rc.DrawLine(transformedValue, Plot.PlotArea.Top, transformedValue, Plot.PlotArea.Bottom, MajorPen); + + } + else + { + rc.DrawLine(Plot.PlotArea.Left, transformedValue, Plot.PlotArea.Right, transformedValue, MajorPen); + } + } + + if (isHorizontal) + { + rc.DrawLine(transformedValue, apos + a0, transformedValue, apos + a1, MajorTickPen); + + } + else + { + rc.DrawLine(apos + a0, transformedValue, apos + a1, transformedValue, MajorTickPen); + } + + if (value == 0 && axis.PositionAtZeroCrossing) + continue; + + var pt = new ScreenPoint(); + var ha = HorizontalTextAlign.Right; + var va = VerticalTextAlign.Middle; + switch (axis.Position) + { + case AxisPosition.Left: + pt = new ScreenPoint(apos + a1 - TICK_DIST, transformedValue); + GetRotatedAlignments(axis.Angle, HorizontalTextAlign.Right, VerticalTextAlign.Middle, out ha, out va); + break; + case AxisPosition.Right: + pt = new ScreenPoint(apos + a1 + TICK_DIST, transformedValue); + GetRotatedAlignments(axis.Angle, HorizontalTextAlign.Left, VerticalTextAlign.Middle, out ha, out va); + break; + case AxisPosition.Top: + pt = new ScreenPoint(transformedValue, apos + a1 - TICK_DIST); + GetRotatedAlignments(axis.Angle, HorizontalTextAlign.Center, VerticalTextAlign.Bottom, out ha, out va); + break; + case AxisPosition.Bottom: + pt = new ScreenPoint(transformedValue, apos + a1 + TICK_DIST); + GetRotatedAlignments(axis.Angle, HorizontalTextAlign.Center, VerticalTextAlign.Top, out ha, out va); + break; + + } + + string text = axis.FormatValue(value); + var size = rc.DrawMathText(pt, text, Plot.TextColor, + axis.FontFamily, axis.FontSize, axis.FontWeight, + axis.Angle, ha, va); + + maxWidth = Math.Max(maxWidth, size.Width); + maxHeight = Math.Max(maxHeight, size.Height); + } + + if (axis.PositionAtZeroCrossing) + { + double t0 = axis.Transform(0); + if (isHorizontal) + { + rc.DrawLine(t0, Plot.PlotArea.Top, t0, Plot.PlotArea.Bottom, ZeroPen); + + } + else + { + rc.DrawLine(Plot.PlotArea.Left, t0, Plot.PlotArea.Right, t0, ZeroPen); + } + } + + if (axis.ExtraGridlines != null) + { + foreach (double value in axis.ExtraGridlines) + { + if (!IsWithin(value, axis.ActualMinimum, axis.ActualMaximum)) + continue; + + double transformedValue = axis.Transform(value); + if (isHorizontal) + { + rc.DrawLine(transformedValue, Plot.PlotArea.Top, transformedValue, Plot.PlotArea.Bottom, ExtraPen); + + } + else + { + rc.DrawLine(Plot.PlotArea.Left, transformedValue, Plot.PlotArea.Right, transformedValue, ExtraPen); + } + } + } + if (isHorizontal) + { + rc.DrawLine(Plot.PlotArea.Left, apos, Plot.PlotArea.Right, apos, MajorPen); + + } + else + { + rc.DrawLine(apos, Plot.PlotArea.Top, apos, Plot.PlotArea.Bottom, MajorPen); + } + + if (!String.IsNullOrWhiteSpace(axis.Title)) + { + // Axis legend + double ymid = axis.Transform((axis.ActualMinimum + axis.ActualMaximum) / 2); + double angle = -90; + var lpt = new ScreenPoint(); + + var halign = HorizontalTextAlign.Center; + var valign = VerticalTextAlign.Top; + + if (axis.PositionAtZeroCrossing) + { + ymid = perpendicularAxis.Transform(perpendicularAxis.ActualMaximum); + // valign = axis.IsReversed ? VerticalTextAlign.Top : VerticalTextAlign.Bottom; + } + + switch (axis.Position) + { + case AxisPosition.Left: + lpt = new ScreenPoint(AXIS_LEGEND_DIST, ymid); + break; + case AxisPosition.Right: + lpt = new ScreenPoint(rc.Width - AXIS_LEGEND_DIST, ymid); + valign = VerticalTextAlign.Bottom; + break; + case AxisPosition.Top: + lpt = new ScreenPoint(ymid, AXIS_LEGEND_DIST); + halign = HorizontalTextAlign.Center; + valign = VerticalTextAlign.Top; + angle = 0; + break; + case AxisPosition.Bottom: + lpt = new ScreenPoint(ymid, rc.Height - AXIS_LEGEND_DIST); + halign = HorizontalTextAlign.Center; + valign = VerticalTextAlign.Bottom; + angle = 0; + break; + } + + rc.DrawText(lpt, axis.Title, Plot.TextColor, + axis.FontFamily, axis.FontSize, axis.FontWeight, + angle, halign, valign); + } + } + + /// + /// Gets the rotated alignments given the specified angle. + /// + /// The angle. + /// The default horizontal alignment. + /// The default vertical alignment. + /// The rotated horizontal alignment. + /// The rotated vertical alignment. + private static void GetRotatedAlignments(double angle, HorizontalTextAlign defaultHorizontalAlignment, VerticalTextAlign defaultVerticalAlignment, + out HorizontalTextAlign ha, out VerticalTextAlign va) + { + ha = defaultHorizontalAlignment; + va = defaultVerticalAlignment; + + Debug.Assert(angle <= 180 && angle >= -180, "Axis angle should be in the interval [-180,180] degrees."); + + if (angle > -45 && angle < 45) + return; + if (angle > 135 || angle < -135) + { + ha = (HorizontalTextAlign)(-(int)defaultHorizontalAlignment); + va = (VerticalTextAlign)(-(int)defaultVerticalAlignment); + return; + } + if (angle > 45) + { + ha = (HorizontalTextAlign)((int)defaultVerticalAlignment); + va = (VerticalTextAlign)(-(int)defaultHorizontalAlignment); + return; + } + if (angle < -45) + { + ha = (HorizontalTextAlign)(-(int)defaultVerticalAlignment); + va = (VerticalTextAlign)((int)defaultHorizontalAlignment); + return; + } + } + } +} \ No newline at end of file diff -r 88d699a65cc2 -r 5be8f2773237 External/OxyPlot/OxyPlot/Reporting/NamespaceDoc.cs --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/External/OxyPlot/OxyPlot/Reporting/NamespaceDoc.cs Sat Jun 08 16:53:22 2013 +0000 @@ -0,0 +1,39 @@ +// -------------------------------------------------------------------------------------------------------------------- +// +// The MIT License (MIT) +// +// Copyright (c) 2012 Oystein Bjorke +// +// Permission is hereby granted, free of charge, to any person obtaining a +// copy of this software and associated documentation files (the +// "Software"), to deal in the Software without restriction, including +// without limitation the rights to use, copy, modify, merge, publish, +// distribute, sublicense, and/or sell copies of the Software, and to +// permit persons to whom the Software is furnished to do so, subject to +// the following conditions: +// +// The above copyright notice and this permission notice shall be included +// in all copies or substantial portions of the Software. +// +// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS +// OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF +// MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. +// IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY +// CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, +// TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE +// SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. +// +// -------------------------------------------------------------------------------------------------------------------- + +namespace OxyPlot.Reporting +{ + using System.Runtime.CompilerServices; + + /// + /// The OxyPlot.Reporting namespace contains a simple report model. + /// + [CompilerGenerated] + internal class NamespaceDoc + { + } +} \ No newline at end of file diff -r 88d699a65cc2 -r 5be8f2773237 External/OxyPlot/OxyPlot/Reporting/Report/Content.cs --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/External/OxyPlot/OxyPlot/Reporting/Report/Content.cs Sat Jun 08 16:53:22 2013 +0000 @@ -0,0 +1,75 @@ +// -------------------------------------------------------------------------------------------------------------------- +// +// The MIT License (MIT) +// +// Copyright (c) 2012 Oystein Bjorke +// +// Permission is hereby granted, free of charge, to any person obtaining a +// copy of this software and associated documentation files (the +// "Software"), to deal in the Software without restriction, including +// without limitation the rights to use, copy, modify, merge, publish, +// distribute, sublicense, and/or sell copies of the Software, and to +// permit persons to whom the Software is furnished to do so, subject to +// the following conditions: +// +// The above copyright notice and this permission notice shall be included +// in all copies or substantial portions of the Software. +// +// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS +// OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF +// MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. +// IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY +// CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, +// TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE +// SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. +// +// -------------------------------------------------------------------------------------------------------------------- +using System.Collections.Generic; + +namespace OxyPlot.Reporting +{ + public class Content : Table + { + public List Contents { get; set; } + public ReportItem Base { get; set; } + + public Content(ReportItem b) + { + this.Base = b; + Class = "content"; + Contents = new List(); + Columns.Add(new TableColumn(null, "Chapter")); + Columns.Add(new TableColumn(null, "Title")); + Items = Contents; + } + + public class ContentItem + { + public string Chapter { get; set; } + public string Title { get; set; } + } + + public override void Update() + { + Contents.Clear(); + var hh = new HeaderHelper(); + Search(Base, hh); + base.Update(); + } + + private void Search(ReportItem item, HeaderHelper hh) + { + var h = item as Header; + if (h != null) + { + h.Chapter = hh.GetHeader(h.Level); + Contents.Add(new ContentItem() { Chapter = h.Chapter, Title = h.Text }); + } + foreach (var c in item.Children) + Search(c,hh); + } + public override void WriteContent(IReportWriter w) + { + } + } +} \ No newline at end of file diff -r 88d699a65cc2 -r 5be8f2773237 External/OxyPlot/OxyPlot/Reporting/Report/Drawing.cs --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/External/OxyPlot/OxyPlot/Reporting/Report/Drawing.cs Sat Jun 08 16:53:22 2013 +0000 @@ -0,0 +1,46 @@ +// -------------------------------------------------------------------------------------------------------------------- +// +// The MIT License (MIT) +// +// Copyright (c) 2012 Oystein Bjorke +// +// Permission is hereby granted, free of charge, to any person obtaining a +// copy of this software and associated documentation files (the +// "Software"), to deal in the Software without restriction, including +// without limitation the rights to use, copy, modify, merge, publish, +// distribute, sublicense, and/or sell copies of the Software, and to +// permit persons to whom the Software is furnished to do so, subject to +// the following conditions: +// +// The above copyright notice and this permission notice shall be included +// in all copies or substantial portions of the Software. +// +// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS +// OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF +// MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. +// IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY +// CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, +// TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE +// SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. +// +// +// Drawing currently only supports SVG format. +// +// -------------------------------------------------------------------------------------------------------------------- +namespace OxyPlot.Reporting +{ + /// + /// Drawing currently only supports SVG format. + /// + public class Drawing : Figure + { + public enum DrawingFormat { Svg } + public DrawingFormat Format { get; set; } + public string Content { get; set; } + + public override void WriteContent(IReportWriter w) + { + w.WriteDrawing(this); + } + } +} \ No newline at end of file diff -r 88d699a65cc2 -r 5be8f2773237 External/OxyPlot/OxyPlot/Reporting/Report/DrawingFigure.cs --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/External/OxyPlot/OxyPlot/Reporting/Report/DrawingFigure.cs Sat Jun 08 16:53:22 2013 +0000 @@ -0,0 +1,73 @@ +// -------------------------------------------------------------------------------------------------------------------- +// +// The MIT License (MIT) +// +// Copyright (c) 2012 Oystein Bjorke +// +// Permission is hereby granted, free of charge, to any person obtaining a +// copy of this software and associated documentation files (the +// "Software"), to deal in the Software without restriction, including +// without limitation the rights to use, copy, modify, merge, publish, +// distribute, sublicense, and/or sell copies of the Software, and to +// permit persons to whom the Software is furnished to do so, subject to +// the following conditions: +// +// The above copyright notice and this permission notice shall be included +// in all copies or substantial portions of the Software. +// +// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS +// OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF +// MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. +// IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY +// CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, +// TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE +// SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. +// +// +// Represents a drawing report item. +// +// -------------------------------------------------------------------------------------------------------------------- +namespace OxyPlot.Reporting +{ + /// + /// Represents a drawing report item. + /// + /// + /// Drawing currently only supports SVG format. + /// + public class DrawingFigure : Figure + { + /// + /// The drawing format. + /// + public enum DrawingFormat + { + /// + /// The svg. + /// + Svg + } + + /// + /// Gets or sets Content. + /// + public string Content { get; set; } + + /// + /// Gets or sets Format. + /// + public DrawingFormat Format { get; set; } + + /// + /// The write content. + /// + /// + /// The w. + /// + public override void WriteContent(IReportWriter w) + { + w.WriteDrawing(this); + } + + } +} \ No newline at end of file diff -r 88d699a65cc2 -r 5be8f2773237 External/OxyPlot/OxyPlot/Reporting/Report/Equation.cs --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/External/OxyPlot/OxyPlot/Reporting/Report/Equation.cs Sat Jun 08 16:53:22 2013 +0000 @@ -0,0 +1,59 @@ +// -------------------------------------------------------------------------------------------------------------------- +// +// The MIT License (MIT) +// +// Copyright (c) 2012 Oystein Bjorke +// +// Permission is hereby granted, free of charge, to any person obtaining a +// copy of this software and associated documentation files (the +// "Software"), to deal in the Software without restriction, including +// without limitation the rights to use, copy, modify, merge, publish, +// distribute, sublicense, and/or sell copies of the Software, and to +// permit persons to whom the Software is furnished to do so, subject to +// the following conditions: +// +// The above copyright notice and this permission notice shall be included +// in all copies or substantial portions of the Software. +// +// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS +// OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF +// MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. +// IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY +// CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, +// TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE +// SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. +// +// +// Represents an equation. +// +// -------------------------------------------------------------------------------------------------------------------- +namespace OxyPlot.Reporting +{ + /// + /// Represents an equation. + /// + public class Equation : ReportItem + { + /// + /// Gets or sets Caption. + /// + public string Caption { get; set; } + + /// + /// Gets or sets Content. + /// + public string Content { get; set; } + + /// + /// The write content. + /// + /// + /// The w. + /// + public override void WriteContent(IReportWriter w) + { + w.WriteEquation(this); + } + + } +} \ No newline at end of file diff -r 88d699a65cc2 -r 5be8f2773237 External/OxyPlot/OxyPlot/Reporting/Report/Figure.cs --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/External/OxyPlot/OxyPlot/Reporting/Report/Figure.cs Sat Jun 08 16:53:22 2013 +0000 @@ -0,0 +1,62 @@ +// -------------------------------------------------------------------------------------------------------------------- +// +// The MIT License (MIT) +// +// Copyright (c) 2012 Oystein Bjorke +// +// Permission is hereby granted, free of charge, to any person obtaining a +// copy of this software and associated documentation files (the +// "Software"), to deal in the Software without restriction, including +// without limitation the rights to use, copy, modify, merge, publish, +// distribute, sublicense, and/or sell copies of the Software, and to +// permit persons to whom the Software is furnished to do so, subject to +// the following conditions: +// +// The above copyright notice and this permission notice shall be included +// in all copies or substantial portions of the Software. +// +// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS +// OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF +// MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. +// IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY +// CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, +// TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE +// SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. +// +// +// Represents a figure (abstract base class for DrawingFigure, Image and PlotFigure). +// +// -------------------------------------------------------------------------------------------------------------------- +namespace OxyPlot.Reporting +{ + /// + /// Represents a figure (abstract base class for DrawingFigure, Image and PlotFigure). + /// + public abstract class Figure : ReportItem + { + /// + /// Gets or sets FigureNumber. + /// + public int FigureNumber { get; set; } + + /// + /// Gets or sets FigureText. + /// + public string FigureText { get; set; } + + /// + /// The get full caption. + /// + /// + /// The style. + /// + /// + /// The get full caption. + /// + public string GetFullCaption(ReportStyle style) + { + return string.Format(style.FigureTextFormatString, this.FigureNumber, this.FigureText); + } + + } +} \ No newline at end of file diff -r 88d699a65cc2 -r 5be8f2773237 External/OxyPlot/OxyPlot/Reporting/Report/Header.cs --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/External/OxyPlot/OxyPlot/Reporting/Report/Header.cs Sat Jun 08 16:53:22 2013 +0000 @@ -0,0 +1,82 @@ +// -------------------------------------------------------------------------------------------------------------------- +// +// The MIT License (MIT) +// +// Copyright (c) 2012 Oystein Bjorke +// +// Permission is hereby granted, free of charge, to any person obtaining a +// copy of this software and associated documentation files (the +// "Software"), to deal in the Software without restriction, including +// without limitation the rights to use, copy, modify, merge, publish, +// distribute, sublicense, and/or sell copies of the Software, and to +// permit persons to whom the Software is furnished to do so, subject to +// the following conditions: +// +// The above copyright notice and this permission notice shall be included +// in all copies or substantial portions of the Software. +// +// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS +// OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF +// MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. +// IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY +// CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, +// TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE +// SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. +// +// +// Represents a header. +// +// -------------------------------------------------------------------------------------------------------------------- +namespace OxyPlot.Reporting +{ + /// + /// Represents a header. + /// + public class Header : ReportItem + { + /// + /// Gets or sets the chapter number(s). + /// + public string Chapter { get; set; } + + /// + /// Gets or sets the level of the header (1-5). + /// + public int Level { get; set; } + + /// + /// Gets or sets the header text. + /// + public string Text { get; set; } + + /// + /// The to string. + /// + /// + /// The to string. + /// + public override string ToString() + { + string h = string.Empty; + if (this.Chapter != null) + { + h += this.Chapter + " "; + } + + h += this.Text; + return h; + } + + /// + /// The write content. + /// + /// + /// The w. + /// + public override void WriteContent(IReportWriter w) + { + w.WriteHeader(this); + } + + } +} \ No newline at end of file diff -r 88d699a65cc2 -r 5be8f2773237 External/OxyPlot/OxyPlot/Reporting/Report/HeaderHelper.cs --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/External/OxyPlot/OxyPlot/Reporting/Report/HeaderHelper.cs Sat Jun 08 16:53:22 2013 +0000 @@ -0,0 +1,82 @@ +// -------------------------------------------------------------------------------------------------------------------- +// +// The MIT License (MIT) +// +// Copyright (c) 2012 Oystein Bjorke +// +// Permission is hereby granted, free of charge, to any person obtaining a +// copy of this software and associated documentation files (the +// "Software"), to deal in the Software without restriction, including +// without limitation the rights to use, copy, modify, merge, publish, +// distribute, sublicense, and/or sell copies of the Software, and to +// permit persons to whom the Software is furnished to do so, subject to +// the following conditions: +// +// The above copyright notice and this permission notice shall be included +// in all copies or substantial portions of the Software. +// +// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS +// OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF +// MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. +// IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY +// CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, +// TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE +// SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. +// +// +// The header helper. +// +// -------------------------------------------------------------------------------------------------------------------- +namespace OxyPlot.Reporting +{ + /// + /// The header helper. + /// + public class HeaderHelper + { + /// + /// The header level. + /// + private readonly int[] headerLevel = new int[10]; + + /// + /// The get header. + /// + /// + /// The level. + /// + /// + /// The get header. + /// + public string GetHeader(int level) + { + for (int i = level - 1; i > 0; i--) + { + if (this.headerLevel[i] == 0) + { + this.headerLevel[i] = 1; + } + } + + this.headerLevel[level]++; + for (int i = level + 1; i < 10; i++) + { + this.headerLevel[i] = 0; + } + + string levelString = string.Empty; + for (int i = 1; i <= level; i++) + { + if (i > 1) + { + levelString += "."; + } + + levelString += this.headerLevel[i]; + } + + return levelString; + } + + } +} \ No newline at end of file diff -r 88d699a65cc2 -r 5be8f2773237 External/OxyPlot/OxyPlot/Reporting/Report/Image.cs --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/External/OxyPlot/OxyPlot/Reporting/Report/Image.cs Sat Jun 08 16:53:22 2013 +0000 @@ -0,0 +1,54 @@ +// -------------------------------------------------------------------------------------------------------------------- +// +// The MIT License (MIT) +// +// Copyright (c) 2012 Oystein Bjorke +// +// Permission is hereby granted, free of charge, to any person obtaining a +// copy of this software and associated documentation files (the +// "Software"), to deal in the Software without restriction, including +// without limitation the rights to use, copy, modify, merge, publish, +// distribute, sublicense, and/or sell copies of the Software, and to +// permit persons to whom the Software is furnished to do so, subject to +// the following conditions: +// +// The above copyright notice and this permission notice shall be included +// in all copies or substantial portions of the Software. +// +// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS +// OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF +// MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. +// IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY +// CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, +// TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE +// SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. +// +// +// Represents an image report item. +// +// -------------------------------------------------------------------------------------------------------------------- +namespace OxyPlot.Reporting +{ + /// + /// Represents an image report item. + /// + public class Image : Figure + { + /// + /// Gets or sets Source. + /// + public string Source { get; set; } + + /// + /// The write content. + /// + /// + /// The w. + /// + public override void WriteContent(IReportWriter w) + { + w.WriteImage(this); + } + + } +} \ No newline at end of file diff -r 88d699a65cc2 -r 5be8f2773237 External/OxyPlot/OxyPlot/Reporting/Report/ItemsTable.cs --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/External/OxyPlot/OxyPlot/Reporting/Report/ItemsTable.cs Sat Jun 08 16:53:22 2013 +0000 @@ -0,0 +1,243 @@ +// -------------------------------------------------------------------------------------------------------------------- +// +// The MIT License (MIT) +// +// Copyright (c) 2012 Oystein Bjorke +// +// Permission is hereby granted, free of charge, to any person obtaining a +// copy of this software and associated documentation files (the +// "Software"), to deal in the Software without restriction, including +// without limitation the rights to use, copy, modify, merge, publish, +// distribute, sublicense, and/or sell copies of the Software, and to +// permit persons to whom the Software is furnished to do so, subject to +// the following conditions: +// +// The above copyright notice and this permission notice shall be included +// in all copies or substantial portions of the Software. +// +// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS +// OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF +// MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. +// IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY +// CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, +// TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE +// SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. +// +// +// Represents a table of items. +// +// -------------------------------------------------------------------------------------------------------------------- +namespace OxyPlot.Reporting +{ + using System.Collections; + using System.Collections.Generic; + using System.Diagnostics; + using System.Linq; + + /// + /// Represents a table of items. + /// + public class ItemsTable : Table + { + /// + /// Initializes a new instance of the class. + /// + /// + /// The items in rows. + /// + public ItemsTable(bool itemsInRows = true) + { + this.Fields = new List(); + this.ItemsInRows = itemsInRows; + this.Alignment = Alignment.Center; + } + + /// + /// Gets or sets Alignment. + /// + public Alignment Alignment { get; set; } + + /// + /// Gets or sets Fields. + /// + public IList Fields { get; set; } + + /// + /// Gets or sets the items. + /// The table will be filled when this property is set. + /// + /// The items. + public IEnumerable Items { get; set; } + + /// + /// Gets a value indicating whether ItemsInRows. + /// + public bool ItemsInRows { get; private set; } + + /// + /// The has header. + /// + /// + /// The has header. + /// + public bool HasHeader() + { + foreach (var c in this.Fields) + { + if (c.Header != null) + { + return true; + } + } + + return false; + } + + /// + /// The to array. + /// + /// + /// + public string[,] ToArray() + { + List items = this.Items.Cast().ToList(); + int nrows = items.Count; + + bool hasHeader = this.HasHeader(); + if (hasHeader) + { + nrows++; + } + + var result = new string[nrows, this.Fields.Count]; + + int row = 0; + if (hasHeader) + { + for (int i = 0; i < this.Fields.Count; i++) + { + ItemsTableField c = this.Fields[i]; + result[row, i] = c.Header; + } + + row++; + } + + foreach (var item in items) + { + for (int i = 0; i < this.Fields.Count; i++) + { + ItemsTableField c = this.Fields[i]; + string text = c.GetText(item, this.Report.ActualCulture); + result[row, i] = text; + } + + row++; + } + + if (!this.ItemsInRows) + { + result = Transpose(result); + } + + return result; + } + + /// + /// The update. + /// + public override void Update() + { + base.Update(); + this.UpdateItems(); + } + + /// + /// The update items. + /// + public void UpdateItems() + { + this.Rows.Clear(); + this.Columns.Clear(); + if (this.Fields == null || this.Fields.Count == 0) + { + return; + } + + string[,] cells = this.ToArray(); + + int rows = cells.GetUpperBound(0) + 1; + int columns = cells.GetUpperBound(1) + 1; + for (int i = 0; i < rows; i++) + { + var tr = new TableRow(); + if (this.ItemsInRows) + { + tr.IsHeader = i == 0; + } + + this.Rows.Add(tr); + for (int j = 0; j < columns; j++) + { + var tc = new TableCell(); + tc.Content = cells[i, j]; + tr.Cells.Add(tc); + } + } + + for (int j = 0; j < columns; j++) + { + var tc = new TableColumn(); + if (this.ItemsInRows) + { + ItemsTableField f = this.Fields[j]; + tc.Alignment = f.Alignment; + tc.Width = f.Width; + } + else + { + tc.IsHeader = j == 0; + tc.Alignment = this.Alignment; + } + + this.Columns.Add(tc); + } + } + + /// + /// Writes the content of the item. + /// + /// + /// The writer. + /// + public override void WriteContent(IReportWriter w) + { + w.WriteTable(this); + } + + /// + /// The transpose. + /// + /// + /// The input. + /// + /// + /// + private static string[,] Transpose(string[,] input) + { + int rows = input.GetUpperBound(0) + 1; + int cols = input.GetUpperBound(1) + 1; + var result = new string[cols, rows]; + for (int i = 0; i < rows; i++) + { + for (int j = 0; j < cols; j++) + { + result[j, i] = input[i, j]; + } + } + + return result; + } + + } +} \ No newline at end of file diff -r 88d699a65cc2 -r 5be8f2773237 External/OxyPlot/OxyPlot/Reporting/Report/ItemsTableField.cs --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/External/OxyPlot/OxyPlot/Reporting/Report/ItemsTableField.cs Sat Jun 08 16:53:22 2013 +0000 @@ -0,0 +1,136 @@ +// -------------------------------------------------------------------------------------------------------------------- +// +// The MIT License (MIT) +// +// Copyright (c) 2012 Oystein Bjorke +// +// Permission is hereby granted, free of charge, to any person obtaining a +// copy of this software and associated documentation files (the +// "Software"), to deal in the Software without restriction, including +// without limitation the rights to use, copy, modify, merge, publish, +// distribute, sublicense, and/or sell copies of the Software, and to +// permit persons to whom the Software is furnished to do so, subject to +// the following conditions: +// +// The above copyright notice and this permission notice shall be included +// in all copies or substantial portions of the Software. +// +// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS +// OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF +// MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. +// IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY +// CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, +// TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE +// SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. +// +// +// The alignment. +// +// -------------------------------------------------------------------------------------------------------------------- +namespace OxyPlot.Reporting +{ + using System; + using System.Reflection; + + /// + /// The alignment. + /// + public enum Alignment + { + /// + /// The left. + /// + Left, + + /// + /// The right. + /// + Right, + + /// + /// The center. + /// + Center + } + + /// + /// Represents a field in an items table. + /// + public class ItemsTableField + { + /// + /// Initializes a new instance of the class. + /// + /// + /// The header. + /// + /// + /// The path. + /// + /// + /// The string format. + /// + /// + /// The alignment. + /// + public ItemsTableField( + string header, string path, string stringFormat = null, Alignment alignment = Alignment.Center) + { + this.Header = header; + this.Path = path; + this.StringFormat = stringFormat; + this.Alignment = alignment; + } + + /// + /// Gets or sets Alignment. + /// + public Alignment Alignment { get; set; } + + /// + /// Gets or sets Header. + /// + public string Header { get; set; } + + /// + /// Gets or sets Path. + /// + public string Path { get; set; } + + /// + /// Gets or sets StringFormat. + /// + public string StringFormat { get; set; } + + /// + /// Gets or sets Width. + /// + public double Width { get; set; } + + /// + /// Gets the text. + /// + /// + /// The item. + /// + /// + /// The format provider. + /// + /// + /// The text. + /// + public string GetText(object item, IFormatProvider formatProvider) + { + PropertyInfo pi = item.GetType().GetProperty(this.Path); + object o = pi.GetValue(item, null); + var of = o as IFormattable; + if (of != null) + { + return of.ToString(this.StringFormat, formatProvider); + } + + return o != null ? o.ToString() : null; + } + + } +} \ No newline at end of file diff -r 88d699a65cc2 -r 5be8f2773237 External/OxyPlot/OxyPlot/Reporting/Report/Paragraph.cs --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/External/OxyPlot/OxyPlot/Reporting/Report/Paragraph.cs Sat Jun 08 16:53:22 2013 +0000 @@ -0,0 +1,54 @@ +// -------------------------------------------------------------------------------------------------------------------- +// +// The MIT License (MIT) +// +// Copyright (c) 2012 Oystein Bjorke +// +// Permission is hereby granted, free of charge, to any person obtaining a +// copy of this software and associated documentation files (the +// "Software"), to deal in the Software without restriction, including +// without limitation the rights to use, copy, modify, merge, publish, +// distribute, sublicense, and/or sell copies of the Software, and to +// permit persons to whom the Software is furnished to do so, subject to +// the following conditions: +// +// The above copyright notice and this permission notice shall be included +// in all copies or substantial portions of the Software. +// +// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS +// OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF +// MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. +// IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY +// CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, +// TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE +// SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. +// +// +// Represents a paragraph. +// +// -------------------------------------------------------------------------------------------------------------------- +namespace OxyPlot.Reporting +{ + /// + /// Represents a paragraph. + /// + public class Paragraph : ReportItem + { + /// + /// Gets or sets Text. + /// + public string Text { get; set; } + + /// + /// The write content. + /// + /// + /// The w. + /// + public override void WriteContent(IReportWriter w) + { + w.WriteParagraph(this); + } + + } +} \ No newline at end of file diff -r 88d699a65cc2 -r 5be8f2773237 External/OxyPlot/OxyPlot/Reporting/Report/ParagraphStyle.cs --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/External/OxyPlot/OxyPlot/Reporting/Report/ParagraphStyle.cs Sat Jun 08 16:53:22 2013 +0000 @@ -0,0 +1,397 @@ +// -------------------------------------------------------------------------------------------------------------------- +// +// The MIT License (MIT) +// +// Copyright (c) 2012 Oystein Bjorke +// +// Permission is hereby granted, free of charge, to any person obtaining a +// copy of this software and associated documentation files (the +// "Software"), to deal in the Software without restriction, including +// without limitation the rights to use, copy, modify, merge, publish, +// distribute, sublicense, and/or sell copies of the Software, and to +// permit persons to whom the Software is furnished to do so, subject to +// the following conditions: +// +// The above copyright notice and this permission notice shall be included +// in all copies or substantial portions of the Software. +// +// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS +// OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF +// MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. +// IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY +// CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, +// TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE +// SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. +// +// +// The paragraph style. +// +// -------------------------------------------------------------------------------------------------------------------- +namespace OxyPlot.Reporting +{ + /// + /// The paragraph style. + /// + public class ParagraphStyle + { + /// + /// The default font. + /// + private const string DefaultFont = "Arial"; + + /// + /// The default font size. + /// + private const double DefaultFontSize = 11; + + /// + /// The bold. + /// + private bool? bold; + + /// + /// The font family. + /// + private string fontFamily; + + /// + /// The font size. + /// + private double? fontSize; + + /// + /// The italic. + /// + private bool? italic; + + /// + /// The left indentation. + /// + private double? leftIndentation; + + /// + /// The line spacing. + /// + private double? lineSpacing; + + /// + /// The page break before. + /// + private bool? pageBreakBefore; + + /// + /// The right indentation. + /// + private double? rightIndentation; + + /// + /// The spacing after. + /// + private double? spacingAfter; + + /// + /// The spacing before. + /// + private double? spacingBefore; + + /// + /// The text color. + /// + private OxyColor textColor; + + /// + /// Gets or sets BasedOn. + /// + public ParagraphStyle BasedOn { get; set; } + + /// + /// Gets or sets a value indicating whether Bold. + /// + public bool Bold + { + get + { + if (this.bold != null) + { + return this.bold.Value; + } + + if (this.BasedOn != null) + { + return this.BasedOn.Bold; + } + + return false; + } + + set + { + this.bold = value; + } + } + + /// + /// Gets or sets FontFamily. + /// + public string FontFamily + { + get + { + if (this.fontFamily != null) + { + return this.fontFamily; + } + + if (this.BasedOn != null) + { + return this.BasedOn.FontFamily; + } + + return DefaultFont; + } + + set + { + this.fontFamily = value; + } + } + + /// + /// Gets or sets FontSize. + /// + public double FontSize + { + get + { + if (this.fontSize != null) + { + return this.fontSize.Value; + } + + if (this.BasedOn != null) + { + return this.BasedOn.FontSize; + } + + return DefaultFontSize; + } + + set + { + this.fontSize = value; + } + } + + /// + /// Gets or sets a value indicating whether Italic. + /// + public bool Italic + { + get + { + if (this.italic != null) + { + return this.italic.Value; + } + + if (this.BasedOn != null) + { + return this.BasedOn.Italic; + } + + return false; + } + + set + { + this.italic = value; + } + } + + /// + /// Gets or sets LeftIndentation. + /// + public double LeftIndentation + { + get + { + if (this.leftIndentation != null) + { + return this.leftIndentation.Value; + } + + if (this.BasedOn != null) + { + return this.BasedOn.LeftIndentation; + } + + return 0; + } + + set + { + this.leftIndentation = value; + } + } + + /// + /// Gets or sets LineSpacing. + /// + public double LineSpacing + { + get + { + if (this.lineSpacing != null) + { + return this.lineSpacing.Value; + } + + if (this.BasedOn != null) + { + return this.BasedOn.LineSpacing; + } + + return 1; + } + + set + { + this.lineSpacing = value; + } + } + + /// + /// Gets or sets a value indicating whether PageBreakBefore. + /// + public bool PageBreakBefore + { + get + { + if (this.pageBreakBefore != null) + { + return this.pageBreakBefore.Value; + } + + if (this.BasedOn != null) + { + return this.BasedOn.PageBreakBefore; + } + + return false; + } + + set + { + this.pageBreakBefore = value; + } + } + + /// + /// Gets or sets RightIndentation. + /// + public double RightIndentation + { + get + { + if (this.rightIndentation != null) + { + return this.rightIndentation.Value; + } + + if (this.BasedOn != null) + { + return this.BasedOn.RightIndentation; + } + + return 0; + } + + set + { + this.rightIndentation = value; + } + } + + /// + /// Gets or sets SpacingAfter. + /// + public double SpacingAfter + { + get + { + if (this.spacingAfter != null) + { + return this.spacingAfter.Value; + } + + if (this.BasedOn != null) + { + return this.BasedOn.SpacingAfter; + } + + return 0; + } + + set + { + this.spacingAfter = value; + } + } + + /// + /// Gets or sets SpacingBefore. + /// + public double SpacingBefore + { + get + { + if (this.spacingBefore != null) + { + return this.spacingBefore.Value; + } + + if (this.BasedOn != null) + { + return this.BasedOn.SpacingBefore; + } + + return 0; + } + + set + { + this.spacingBefore = value; + } + } + + /// + /// Gets or sets TextColor. + /// + public OxyColor TextColor + { + get + { + if (this.textColor != null) + { + return this.textColor; + } + + if (this.BasedOn != null) + { + return this.BasedOn.TextColor; + } + + return OxyColors.Black; + } + + set + { + this.textColor = value; + } + } + + // margin + // padding + // borders + } +} \ No newline at end of file diff -r 88d699a65cc2 -r 5be8f2773237 External/OxyPlot/OxyPlot/Reporting/Report/Plot.cs --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/External/OxyPlot/OxyPlot/Reporting/Report/Plot.cs Sat Jun 08 16:53:22 2013 +0000 @@ -0,0 +1,40 @@ +// -------------------------------------------------------------------------------------------------------------------- +// +// The MIT License (MIT) +// +// Copyright (c) 2012 Oystein Bjorke +// +// Permission is hereby granted, free of charge, to any person obtaining a +// copy of this software and associated documentation files (the +// "Software"), to deal in the Software without restriction, including +// without limitation the rights to use, copy, modify, merge, publish, +// distribute, sublicense, and/or sell copies of the Software, and to +// permit persons to whom the Software is furnished to do so, subject to +// the following conditions: +// +// The above copyright notice and this permission notice shall be included +// in all copies or substantial portions of the Software. +// +// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS +// OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF +// MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. +// IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY +// CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, +// TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE +// SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. +// +// -------------------------------------------------------------------------------------------------------------------- +namespace OxyPlot.Reporting +{ + public class Plot : Figure + { + public PlotModel PlotModel { get; set; } + public double Width { get; set; } + public double Height { get; set; } + + public override void WriteContent(IReportWriter w) + { + w.WritePlot(this); + } + } +} \ No newline at end of file diff -r 88d699a65cc2 -r 5be8f2773237 External/OxyPlot/OxyPlot/Reporting/Report/PlotFigure.cs --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/External/OxyPlot/OxyPlot/Reporting/Report/PlotFigure.cs Sat Jun 08 16:53:22 2013 +0000 @@ -0,0 +1,64 @@ +// -------------------------------------------------------------------------------------------------------------------- +// +// The MIT License (MIT) +// +// Copyright (c) 2012 Oystein Bjorke +// +// Permission is hereby granted, free of charge, to any person obtaining a +// copy of this software and associated documentation files (the +// "Software"), to deal in the Software without restriction, including +// without limitation the rights to use, copy, modify, merge, publish, +// distribute, sublicense, and/or sell copies of the Software, and to +// permit persons to whom the Software is furnished to do so, subject to +// the following conditions: +// +// The above copyright notice and this permission notice shall be included +// in all copies or substantial portions of the Software. +// +// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS +// OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF +// MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. +// IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY +// CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, +// TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE +// SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. +// +// +// Represents a plot figure. +// +// -------------------------------------------------------------------------------------------------------------------- +namespace OxyPlot.Reporting +{ + /// + /// Represents a plot figure. + /// + public class PlotFigure : Figure + { + /// + /// Gets or sets Height. + /// + public double Height { get; set; } + + /// + /// Gets or sets PlotModel. + /// + public PlotModel PlotModel { get; set; } + + /// + /// Gets or sets Width. + /// + public double Width { get; set; } + + /// + /// The write content. + /// + /// + /// The w. + /// + public override void WriteContent(IReportWriter w) + { + w.WritePlot(this); + } + + } +} \ No newline at end of file diff -r 88d699a65cc2 -r 5be8f2773237 External/OxyPlot/OxyPlot/Reporting/Report/PropertyTable.cs --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/External/OxyPlot/OxyPlot/Reporting/Report/PropertyTable.cs Sat Jun 08 16:53:22 2013 +0000 @@ -0,0 +1,114 @@ +// -------------------------------------------------------------------------------------------------------------------- +// +// The MIT License (MIT) +// +// Copyright (c) 2012 Oystein Bjorke +// +// Permission is hereby granted, free of charge, to any person obtaining a +// copy of this software and associated documentation files (the +// "Software"), to deal in the Software without restriction, including +// without limitation the rights to use, copy, modify, merge, publish, +// distribute, sublicense, and/or sell copies of the Software, and to +// permit persons to whom the Software is furnished to do so, subject to +// the following conditions: +// +// The above copyright notice and this permission notice shall be included +// in all copies or substantial portions of the Software. +// +// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS +// OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF +// MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. +// IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY +// CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, +// TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE +// SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. +// +// +// Represents a table of autogenerated property values. +// +// -------------------------------------------------------------------------------------------------------------------- +namespace OxyPlot.Reporting +{ + using System; + using System.Collections; + using System.ComponentModel; + + /// + /// Represents a table of autogenerated property values. + /// + /// + /// The PropertyTable autogenerates columns or rows based on reflecting the Items type. + /// Only [Browsable] properties are included. + /// + public class PropertyTable : ItemsTable + { + /// + /// Initializes a new instance of the class. + /// + /// + /// The items. + /// + /// + /// The items in rows. + /// + public PropertyTable(IEnumerable items, bool itemsInRows) + : base(itemsInRows) + { + this.Alignment = Alignment.Left; + this.UpdateFields(items); + this.Items = items; + } + + /// + /// The get item type. + /// + /// + /// The items. + /// + /// + /// + private Type GetItemType(IEnumerable items) + { + Type result = null; + foreach (var item in items) + { + Type t = item.GetType(); + if (result == null) + { + result = t; + } + + if (t != result) + { + return null; + } + } + + return result; + } + + /// + /// Updates the fields. + /// + /// + /// The items. + /// + private void UpdateFields(IEnumerable items) + { + Type type = this.GetItemType(items); + if (type == null) + { + return; + } + + this.Columns.Clear(); + + foreach (var pi in type.GetProperties()) + { + // TODO: support Browsable and Displayname attributes + var header = pi.Name; + this.Fields.Add(new ItemsTableField(header, pi.Name, null, Alignment.Left)); + } + } + } +} \ No newline at end of file diff -r 88d699a65cc2 -r 5be8f2773237 External/OxyPlot/OxyPlot/Reporting/Report/Report.cs --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/External/OxyPlot/OxyPlot/Reporting/Report/Report.cs Sat Jun 08 16:53:22 2013 +0000 @@ -0,0 +1,87 @@ +// -------------------------------------------------------------------------------------------------------------------- +// +// The MIT License (MIT) +// +// Copyright (c) 2012 Oystein Bjorke +// +// Permission is hereby granted, free of charge, to any person obtaining a +// copy of this software and associated documentation files (the +// "Software"), to deal in the Software without restriction, including +// without limitation the rights to use, copy, modify, merge, publish, +// distribute, sublicense, and/or sell copies of the Software, and to +// permit persons to whom the Software is furnished to do so, subject to +// the following conditions: +// +// The above copyright notice and this permission notice shall be included +// in all copies or substantial portions of the Software. +// +// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS +// OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF +// MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. +// IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY +// CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, +// TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE +// SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. +// +// +// Represents a report. +// +// -------------------------------------------------------------------------------------------------------------------- +namespace OxyPlot.Reporting +{ + using System.Globalization; + + /// + /// Represents a report. + /// + public class Report : ReportItem + { + /// + /// Gets the actual culture. + /// + public CultureInfo ActualCulture + { + get + { + return this.Culture ?? CultureInfo.CurrentCulture; + } + } + + /// + /// Gets or sets Author. + /// + public string Author { get; set; } + + /// + /// Gets or sets the culture. + /// + /// + /// The culture. + /// + public CultureInfo Culture { get; set; } + + /// + /// Gets or sets SubTitle. + /// + public string SubTitle { get; set; } + + /// + /// Gets or sets Title. + /// + public string Title { get; set; } + + /// + /// The write. + /// + /// + /// The w. + /// + public override void Write(IReportWriter w) + { + this.UpdateParent(this); + this.UpdateFigureNumbers(); + base.Write(w); + } + + } +} \ No newline at end of file diff -r 88d699a65cc2 -r 5be8f2773237 External/OxyPlot/OxyPlot/Reporting/Report/ReportItem.cs --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/External/OxyPlot/OxyPlot/Reporting/Report/ReportItem.cs Sat Jun 08 16:53:22 2013 +0000 @@ -0,0 +1,311 @@ +// -------------------------------------------------------------------------------------------------------------------- +// +// The MIT License (MIT) +// +// Copyright (c) 2012 Oystein Bjorke +// +// Permission is hereby granted, free of charge, to any person obtaining a +// copy of this software and associated documentation files (the +// "Software"), to deal in the Software without restriction, including +// without limitation the rights to use, copy, modify, merge, publish, +// distribute, sublicense, and/or sell copies of the Software, and to +// permit persons to whom the Software is furnished to do so, subject to +// the following conditions: +// +// The above copyright notice and this permission notice shall be included +// in all copies or substantial portions of the Software. +// +// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS +// OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF +// MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. +// IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY +// CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, +// TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE +// SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. +// +// +// Represents a report item (abstract base class). +// +// -------------------------------------------------------------------------------------------------------------------- +namespace OxyPlot.Reporting +{ + using System.Collections; + using System.Collections.Generic; + using System.Collections.ObjectModel; + + /// + /// Represents a report item (abstract base class). + /// + public abstract class ReportItem + { + /// + /// Initializes a new instance of the class. + /// + protected ReportItem() + { + this.Children = new Collection(); + } + + /// + /// Gets the children. + /// + public Collection Children { get; private set; } + + /// + /// Gets the report. + /// + public Report Report { get; internal set; } + + /// + /// Adds a report item to the report. + /// + /// + /// The child. + /// + public void Add(ReportItem child) + { + this.Children.Add(child); + } + + /// + /// Adds a drawing to the report. + /// + /// + /// The content. + /// + /// + /// The text. + /// + public void AddDrawing(string content, string text) + { + this.Add(new DrawingFigure { Content = content, FigureText = text }); + } + + /// + /// Adds a plot to the report. + /// + /// The plot model. + /// The text. + /// The width. + /// The height. + public void AddPlot(PlotModel plot, string text, double width, double height) + { + this.Add(new PlotFigure { PlotModel = plot, Width = width, Height = height, FigureText = text }); + } + + /// + /// Adds an equation to the report. + /// + /// + /// The equation. + /// + /// + /// The caption. + /// + public void AddEquation(string equation, string caption = null) + { + this.Add(new Equation { Content = equation, Caption = caption }); + } + + /// + /// Adds a header to the report. + /// + /// + /// The level. + /// + /// + /// The header. + /// + public void AddHeader(int level, string header) + { + this.Add(new Header { Level = level, Text = header }); + } + + /// + /// Adds an image to the report. + /// + /// + /// The src. + /// + /// + /// The text. + /// + public void AddImage(string src, string text) + { + this.Add(new Image { Source = src, FigureText = text }); + } + + /// + /// Adds an items table to the report. + /// + /// + /// The title. + /// + /// + /// The items. + /// + /// + /// The fields. + /// + public void AddItemsTable(string title, IEnumerable items, IList fields) + { + this.Add(new ItemsTable { Caption = title, Items = items, Fields = fields }); + } + + /// + /// Adds a paragraph to the report. + /// + /// + /// The content. + /// + public void AddParagraph(string content) + { + this.Add(new Paragraph { Text = content }); + } + + /// + /// Adds a property table to the report. + /// + /// + /// The title. + /// + /// + /// The object. + /// + /// + /// A PropertyTable. + /// + public PropertyTable AddPropertyTable(string title, object obj) + { + var items = obj as IEnumerable; + if (items == null) + { + items = new[] { obj }; + } + + var pt = new PropertyTable(items, false) { Caption = title }; + this.Add(pt); + return pt; + } + + /// + /// The add table of contents. + /// + /// + /// The b. + /// + public void AddTableOfContents(ReportItem b) + { + this.Add(new TableOfContents(b)); + } + + /// + /// The update. + /// + public virtual void Update() + { + } + + /// + /// The write. + /// + /// + /// The w. + /// + public virtual void Write(IReportWriter w) + { + this.Update(); + this.WriteContent(w); + foreach (var child in this.Children) + { + child.Write(w); + } + } + + /// + /// Writes the content of the item. + /// + /// + /// The writer. + /// + public virtual void WriteContent(IReportWriter w) + { + } + + /// + /// The update figure numbers. + /// + protected void UpdateFigureNumbers() + { + var fc = new FigureCounter(); + this.UpdateFigureNumbers(fc); + } + + /// + /// Updates the Report property. + /// + /// + /// The report. + /// + protected void UpdateParent(Report report) + { + this.Report = report; + foreach (var child in this.Children) + { + child.UpdateParent(report); + } + } + + /// + /// The update figure numbers. + /// + /// + /// The fc. + /// + private void UpdateFigureNumbers(FigureCounter fc) + { + var table = this as Table; + if (table != null) + { + table.TableNumber = fc.TableNumber++; + } + + var figure = this as Figure; + if (figure != null) + { + figure.FigureNumber = fc.FigureNumber++; + } + + foreach (var child in this.Children) + { + child.UpdateFigureNumbers(fc); + } + } + + /// + /// The figure counter. + /// + private class FigureCounter + { + /// + /// Initializes a new instance of the class. + /// + public FigureCounter() + { + this.FigureNumber = 1; + this.TableNumber = 1; + } + + /// + /// Gets or sets FigureNumber. + /// + public int FigureNumber { get; set; } + + /// + /// Gets or sets TableNumber. + /// + public int TableNumber { get; set; } + + } + } +} \ No newline at end of file diff -r 88d699a65cc2 -r 5be8f2773237 External/OxyPlot/OxyPlot/Reporting/Report/ReportSection.cs --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/External/OxyPlot/OxyPlot/Reporting/Report/ReportSection.cs Sat Jun 08 16:53:22 2013 +0000 @@ -0,0 +1,38 @@ +// -------------------------------------------------------------------------------------------------------------------- +// +// The MIT License (MIT) +// +// Copyright (c) 2012 Oystein Bjorke +// +// Permission is hereby granted, free of charge, to any person obtaining a +// copy of this software and associated documentation files (the +// "Software"), to deal in the Software without restriction, including +// without limitation the rights to use, copy, modify, merge, publish, +// distribute, sublicense, and/or sell copies of the Software, and to +// permit persons to whom the Software is furnished to do so, subject to +// the following conditions: +// +// The above copyright notice and this permission notice shall be included +// in all copies or substantial portions of the Software. +// +// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS +// OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF +// MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. +// IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY +// CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, +// TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE +// SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. +// +// +// Represents a report section. +// +// -------------------------------------------------------------------------------------------------------------------- +namespace OxyPlot.Reporting +{ + /// + /// Represents a report section. + /// + public class ReportSection : ReportItem + { + } +} \ No newline at end of file diff -r 88d699a65cc2 -r 5be8f2773237 External/OxyPlot/OxyPlot/Reporting/Report/ReportStyle.cs --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/External/OxyPlot/OxyPlot/Reporting/Report/ReportStyle.cs Sat Jun 08 16:53:22 2013 +0000 @@ -0,0 +1,156 @@ +// -------------------------------------------------------------------------------------------------------------------- +// +// The MIT License (MIT) +// +// Copyright (c) 2012 Oystein Bjorke +// +// Permission is hereby granted, free of charge, to any person obtaining a +// copy of this software and associated documentation files (the +// "Software"), to deal in the Software without restriction, including +// without limitation the rights to use, copy, modify, merge, publish, +// distribute, sublicense, and/or sell copies of the Software, and to +// permit persons to whom the Software is furnished to do so, subject to +// the following conditions: +// +// The above copyright notice and this permission notice shall be included +// in all copies or substantial portions of the Software. +// +// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS +// OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF +// MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. +// IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY +// CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, +// TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE +// SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. +// +// +// The report style. +// +// -------------------------------------------------------------------------------------------------------------------- +namespace OxyPlot.Reporting +{ + /// + /// The report style. + /// + public class ReportStyle + { + /// + /// Initializes a new instance of the class. + /// + /// + /// The title font family. + /// + /// + /// The body text font family. + /// + /// + /// The table text font family. + /// + public ReportStyle( + string titleFontFamily = "Arial", + string bodyTextFontFamily = "Verdana", + string tableTextFontFamily = "Courier New") + { + this.DefaultStyle = new ParagraphStyle { FontFamily = bodyTextFontFamily, FontSize = 11, SpacingAfter = 10 }; + + this.HeaderStyles = new ParagraphStyle[5]; + this.HeaderStyles[0] = new ParagraphStyle + { + BasedOn = this.DefaultStyle, FontFamily = titleFontFamily, SpacingBefore = 12, SpacingAfter = 3 + }; + for (int i = 1; i < this.HeaderStyles.Length; i++) + { + this.HeaderStyles[i] = new ParagraphStyle { BasedOn = this.HeaderStyles[i - 1] }; + } + + for (int i = 0; i < this.HeaderStyles.Length; i++) + { + this.HeaderStyles[i].Bold = true; + } + + this.HeaderStyles[0].FontSize = 16; + this.HeaderStyles[1].FontSize = 14; + this.HeaderStyles[2].FontSize = 13; + this.HeaderStyles[3].FontSize = 12; + this.HeaderStyles[4].FontSize = 11; + + this.HeaderStyles[0].PageBreakBefore = true; + this.HeaderStyles[1].PageBreakBefore = false; + + this.BodyTextStyle = new ParagraphStyle { BasedOn = this.DefaultStyle }; + this.FigureTextStyle = new ParagraphStyle { BasedOn = this.DefaultStyle, Italic = true }; + + this.TableTextStyle = new ParagraphStyle + { + BasedOn = this.DefaultStyle, + FontFamily = tableTextFontFamily, + SpacingAfter = 0, + LeftIndentation = 3, + RightIndentation = 3 + }; + this.TableHeaderStyle = new ParagraphStyle { BasedOn = this.TableTextStyle, Bold = true }; + this.TableCaptionStyle = new ParagraphStyle + { + BasedOn = this.DefaultStyle, Italic = true, SpacingBefore = 10, SpacingAfter = 3 + }; + + this.Margins = new OxyThickness(25); + + this.FigureTextFormatString = "Figure {0}. {1}"; + this.TableCaptionFormatString = "Table {0}. {1}"; + } + + /// + /// Gets or sets BodyTextStyle. + /// + public ParagraphStyle BodyTextStyle { get; set; } + + /// + /// Gets or sets DefaultStyle. + /// + public ParagraphStyle DefaultStyle { get; set; } + + /// + /// Gets or sets FigureTextFormatString. + /// + public string FigureTextFormatString { get; set; } + + /// + /// Gets or sets FigureTextStyle. + /// + public ParagraphStyle FigureTextStyle { get; set; } + + /// + /// Gets or sets HeaderStyles. + /// + public ParagraphStyle[] HeaderStyles { get; set; } + + /// + /// Gets or sets the page margins (mm). + /// + public OxyThickness Margins { get; set; } + + // todo: should the FormatStrings be in the Report class? + + /// + /// Gets or sets TableCaptionFormatString. + /// + public string TableCaptionFormatString { get; set; } + + /// + /// Gets or sets TableCaptionStyle. + /// + public ParagraphStyle TableCaptionStyle { get; set; } + + /// + /// Gets or sets TableHeaderStyle. + /// + public ParagraphStyle TableHeaderStyle { get; set; } + + /// + /// Gets or sets TableTextStyle. + /// + public ParagraphStyle TableTextStyle { get; set; } + + } +} \ No newline at end of file diff -r 88d699a65cc2 -r 5be8f2773237 External/OxyPlot/OxyPlot/Reporting/Report/Table.cs --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/External/OxyPlot/OxyPlot/Reporting/Report/Table.cs Sat Jun 08 16:53:22 2013 +0000 @@ -0,0 +1,252 @@ +// -------------------------------------------------------------------------------------------------------------------- +// +// The MIT License (MIT) +// +// Copyright (c) 2012 Oystein Bjorke +// +// Permission is hereby granted, free of charge, to any person obtaining a +// copy of this software and associated documentation files (the +// "Software"), to deal in the Software without restriction, including +// without limitation the rights to use, copy, modify, merge, publish, +// distribute, sublicense, and/or sell copies of the Software, and to +// permit persons to whom the Software is furnished to do so, subject to +// the following conditions: +// +// The above copyright notice and this permission notice shall be included +// in all copies or substantial portions of the Software. +// +// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS +// OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF +// MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. +// IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY +// CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, +// TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE +// SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. +// +// +// Represents a table column definition. +// +// -------------------------------------------------------------------------------------------------------------------- +namespace OxyPlot.Reporting +{ + using System; + using System.Collections.Generic; + + /// + /// Represents a table column definition. + /// + public class TableColumn + { + /// + /// Initializes a new instance of the class. + /// + public TableColumn() + { + this.Width = double.NaN; + this.Alignment = Alignment.Center; + } + + /// + /// Gets or sets the actual width (mm). + /// + /// The actual width. + public double ActualWidth { get; internal set; } + + /// + /// Gets or sets Alignment. + /// + public Alignment Alignment { get; set; } + + /// + /// Gets or sets a value indicating whether IsHeader. + /// + public bool IsHeader { get; set; } + + /// + /// Gets or sets the width. + /// NaN: auto width. + /// Negative numbers: weights + /// + /// The width. + public double Width { get; set; } + + } + + /// + /// Represents a table row definition. + /// + public class TableRow + { + /// + /// Initializes a new instance of the class. + /// + public TableRow() + { + this.Cells = new List(); + } + + /// + /// Gets Cells. + /// + public IList Cells { get; private set; } + + /// + /// Gets or sets a value indicating whether IsHeader. + /// + public bool IsHeader { get; set; } + + } + + /// + /// Represents a table cell. + /// + public class TableCell + { + // public Alignment Alignment { get; set; } + // public int RowSpan { get; set; } + // public int ColumnSpan { get; set; } + /// + /// Gets or sets Content. + /// + public string Content { get; set; } + + } + + /// + /// Represents a table. + /// + public class Table : ReportItem + { + /// + /// Initializes a new instance of the class. + /// + public Table() + { + this.Rows = new List(); + this.Columns = new List(); + this.Width = double.NaN; + } + + /// + /// Gets or sets the actual width of the table (mm). + /// + /// The actual width. + public double ActualWidth { get; private set; } + + /// + /// Gets or sets Caption. + /// + public string Caption { get; set; } + + /// + /// Gets Columns. + /// + public IList Columns { get; private set; } + + /// + /// Gets Rows. + /// + public IList Rows { get; private set; } + + /// + /// Gets or sets TableNumber. + /// + public int TableNumber { get; set; } + + /// + /// Gets or sets the width of the table (mm). + /// NaN: auto width. + /// 0..-1: fraction of page width. + /// + public double Width { get; set; } + + /// + /// The get full caption. + /// + /// + /// The style. + /// + /// + /// The get full caption. + /// + public string GetFullCaption(ReportStyle style) + { + return string.Format(style.TableCaptionFormatString, this.TableNumber, this.Caption); + } + + /// + /// The update. + /// + public override void Update() + { + base.Update(); + this.UpdateWidths(); + } + + /// + /// The write content. + /// + /// + /// The w. + /// + public override void WriteContent(IReportWriter w) + { + // todo + } + + /// + /// The update widths. + /// + private void UpdateWidths() + { + if (this.Width < 0) + { + this.ActualWidth = 150 * (-this.Width); + } + else + { + this.ActualWidth = this.Width; + } + + // update actual widths of all columns + double totalWeight = 0; + double totalWidth = 0; + foreach (var c in this.Columns) + { + if (double.IsNaN(c.Width)) + { + // todo: find auto width + c.ActualWidth = 40; + totalWidth += c.ActualWidth; + } + + if (c.Width < 0) + { + totalWeight += -c.Width; + } + + if (c.Width >= 0) + { + totalWidth += c.Width; + c.ActualWidth = c.Width; + } + } + + if (double.IsNaN(this.ActualWidth)) + { + this.ActualWidth = Math.Max(150, totalWidth + 100); + } + + double w = this.ActualWidth - totalWidth; + foreach (var c in this.Columns) + { + if (c.Width < 0 && totalWeight != 0) + { + double weight = -c.Width; + c.ActualWidth = w * (weight / totalWeight); + } + } + } + + } +} \ No newline at end of file diff -r 88d699a65cc2 -r 5be8f2773237 External/OxyPlot/OxyPlot/Reporting/Report/TableColumn.cs --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/External/OxyPlot/OxyPlot/Reporting/Report/TableColumn.cs Sat Jun 08 16:53:22 2013 +0000 @@ -0,0 +1,63 @@ +// -------------------------------------------------------------------------------------------------------------------- +// +// The MIT License (MIT) +// +// Copyright (c) 2012 Oystein Bjorke +// +// Permission is hereby granted, free of charge, to any person obtaining a +// copy of this software and associated documentation files (the +// "Software"), to deal in the Software without restriction, including +// without limitation the rights to use, copy, modify, merge, publish, +// distribute, sublicense, and/or sell copies of the Software, and to +// permit persons to whom the Software is furnished to do so, subject to +// the following conditions: +// +// The above copyright notice and this permission notice shall be included +// in all copies or substantial portions of the Software. +// +// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS +// OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF +// MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. +// IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY +// CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, +// TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE +// SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. +// +// -------------------------------------------------------------------------------------------------------------------- +using System; +using System.Collections.ObjectModel; +using System.Globalization; + +namespace OxyPlot.Reporting +{ + public enum Alignment { Left, Right, Center }; + + public class TableColumn + { + public Alignment Alignment { get; set; } + public string Header { get; set; } + public string StringFormat { get; set; } + public string Path { get; set; } + public double Width { get; set; } + // public Collection SubColumns { get; set; } + + public TableColumn(string header, string path, string stringFormat=null, Alignment alignment=Alignment.Center) + { + Header = header; + Path = path; + StringFormat = stringFormat; + Alignment = alignment; + // SubColumns = new Collection(); + } + + public string GetText(object item) + { + var pi = item.GetType().GetProperty(Path); + object o = pi.GetValue(item, null); + var of = o as IFormattable; + if (of != null) + return of.ToString(StringFormat, CultureInfo.InvariantCulture); + return o!=null ? o.ToString():null; + } + } +} \ No newline at end of file diff -r 88d699a65cc2 -r 5be8f2773237 External/OxyPlot/OxyPlot/Reporting/Report/TableOfContents.cs --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/External/OxyPlot/OxyPlot/Reporting/Report/TableOfContents.cs Sat Jun 08 16:53:22 2013 +0000 @@ -0,0 +1,115 @@ +// -------------------------------------------------------------------------------------------------------------------- +// +// The MIT License (MIT) +// +// Copyright (c) 2012 Oystein Bjorke +// +// Permission is hereby granted, free of charge, to any person obtaining a +// copy of this software and associated documentation files (the +// "Software"), to deal in the Software without restriction, including +// without limitation the rights to use, copy, modify, merge, publish, +// distribute, sublicense, and/or sell copies of the Software, and to +// permit persons to whom the Software is furnished to do so, subject to +// the following conditions: +// +// The above copyright notice and this permission notice shall be included +// in all copies or substantial portions of the Software. +// +// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS +// OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF +// MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. +// IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY +// CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, +// TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE +// SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. +// +// +// Represents a table of contents. +// +// -------------------------------------------------------------------------------------------------------------------- +namespace OxyPlot.Reporting +{ + using System.Collections.Generic; + + /// + /// Represents a table of contents. + /// + public class TableOfContents : ItemsTable + { + /// + /// Initializes a new instance of the class. + /// + /// + /// The b. + /// + public TableOfContents(ReportItem b) + { + this.Base = b; + this.Contents = new List(); + this.Fields.Add(new ItemsTableField(null, "Chapter")); + this.Fields.Add(new ItemsTableField(null, "Title")); + this.Items = this.Contents; + } + + /// + /// Gets or sets Base. + /// + public ReportItem Base { get; set; } + + /// + /// Gets or sets Contents. + /// + public List Contents { get; set; } + + /// + /// The update. + /// + public override void Update() + { + this.Contents.Clear(); + var hh = new HeaderHelper(); + this.Search(this.Base, hh); + base.Update(); + } + + /// + /// The search. + /// + /// + /// The item. + /// + /// + /// The hh. + /// + private void Search(ReportItem item, HeaderHelper hh) + { + var h = item as Header; + if (h != null) + { + h.Chapter = hh.GetHeader(h.Level); + this.Contents.Add(new ContentItem { Chapter = h.Chapter, Title = h.Text }); + } + + foreach (var c in item.Children) + { + this.Search(c, hh); + } + } + + /// + /// The content item. + /// + public class ContentItem + { + /// + /// Gets or sets Chapter. + /// + public string Chapter { get; set; } + + /// + /// Gets or sets Title. + /// + public string Title { get; set; } + } + } +} \ No newline at end of file diff -r 88d699a65cc2 -r 5be8f2773237 External/OxyPlot/OxyPlot/Reporting/ReportWriters/HtmlReportWriter.cs --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/External/OxyPlot/OxyPlot/Reporting/ReportWriters/HtmlReportWriter.cs Sat Jun 08 16:53:22 2013 +0000 @@ -0,0 +1,501 @@ +// -------------------------------------------------------------------------------------------------------------------- +// +// The MIT License (MIT) +// +// Copyright (c) 2012 Oystein Bjorke +// +// Permission is hereby granted, free of charge, to any person obtaining a +// copy of this software and associated documentation files (the +// "Software"), to deal in the Software without restriction, including +// without limitation the rights to use, copy, modify, merge, publish, +// distribute, sublicense, and/or sell copies of the Software, and to +// permit persons to whom the Software is furnished to do so, subject to +// the following conditions: +// +// The above copyright notice and this permission notice shall be included +// in all copies or substantial portions of the Software. +// +// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS +// OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF +// MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. +// IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY +// CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, +// TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE +// SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. +// +// +// Specifies the html element type to use when writing plots. +// +// -------------------------------------------------------------------------------------------------------------------- +namespace OxyPlot.Reporting +{ + using System.Collections.Generic; + using System.IO; + using System.Text; + + /// + /// Specifies the html element type to use when writing plots. + /// + public enum HtmlPlotElementType + { + /// + /// Use the embed tag and reference an external svg file. + /// + Embed, + + /// + /// Use the object tag and reference an external svg file. + /// + Object, + + /// + /// Use the svg tag and include the plot inline. + /// + Svg + } + + /// + /// HTML5 report writer. + /// + public class HtmlReportWriter : XmlWriterBase, IReportWriter + { + /// + /// The text measurer. + /// + private readonly IRenderContext textMeasurer; + + /// + /// The figure counter. + /// + private int figureCounter; + + /// + /// The style. + /// + private ReportStyle style; + + /// + /// Initializes a new instance of the class. + /// + /// + /// The stream. + /// + /// + /// The text measurer. + /// + public HtmlReportWriter(Stream stream, IRenderContext textMeasurer = null) + : base(stream) + { + this.textMeasurer = textMeasurer; + this.WriteHtmlElement(); + this.PlotElementType = HtmlPlotElementType.Svg; + } + + /// + /// Gets or sets the type of the plot element. + /// + /// + /// The type of the plot element. + /// + public HtmlPlotElementType PlotElementType { get; set; } + + /// + /// Closes this instance. + /// + public override void Close() + { + this.WriteEndElement(); + this.WriteEndElement(); + base.Close(); + } + + /// + /// Writes the class ID. + /// + /// + /// The class. + /// + /// + /// The id. + /// + public void WriteClassId(string className, string id = null) + { + if (className != null) + { + this.WriteAttributeString("class", className); + } + + if (id != null) + { + this.WriteAttributeString("id", id); + } + } + + /// + /// Writes the drawing. + /// + /// + /// The drawing. + /// + public void WriteDrawing(DrawingFigure d) + { + this.WriteStartFigure(); + this.WriteRaw(d.Content); + this.WriteEndFigure(d.FigureText); + } + + /// + /// Writes the equation. + /// + /// + /// The equation. + /// + public void WriteEquation(Equation equation) + { + // todo: MathML? + } + + /// + /// Writes the header. + /// + /// + /// The header. + /// + public void WriteHeader(Header h) + { + if (h.Text == null) + { + return; + } + + this.WriteStartElement("h" + h.Level); + this.WriteString(h.ToString()); + this.WriteEndElement(); + } + + /// + /// Writes the image. + /// + /// + /// The image. + /// + public void WriteImage(Image i) + { + // this requires the image to be located in the same folder as the html + string localFileName = i.Source; + this.WriteStartFigure(); + this.WriteStartElement("img"); + this.WriteAttributeString("src", localFileName); + this.WriteAttributeString("alt", i.FigureText); + this.WriteEndElement(); + this.WriteEndFigure(i.FigureText); + } + + /// + /// Writes the paragraph. + /// + /// + /// The paragraph. + /// + public void WriteParagraph(Paragraph p) + { + this.WriteElementString("p", p.Text); + } + + /// + /// Writes the plot. + /// + /// + /// The plot. + /// + public void WritePlot(PlotFigure plot) + { + this.WriteStartFigure(); + switch (this.PlotElementType) + { + case HtmlPlotElementType.Embed: + case HtmlPlotElementType.Object: + // TODO: need a Func to provide streams for the plot files? + + //string source = string.Format( + // "{0}_Plot{1}.svg", Path.GetFileNameWithoutExtension(this.outputFile), plot.FigureNumber); + //plot.PlotModel.SaveSvg(this.GetFullFileName(source), plot.Width, plot.Height, this.textMeasurer); + //this.WriteStartElement(this.PlotElementType == HtmlPlotElementType.Embed ? "embed" : "object"); + //this.WriteAttributeString("src", source); + //this.WriteAttributeString("type", "image/svg+xml"); + //this.WriteEndElement(); + break; + case HtmlPlotElementType.Svg: + this.WriteRaw(plot.PlotModel.ToSvg(plot.Width, plot.Height, false, this.textMeasurer)); + break; + } + + this.WriteEndFigure(plot.FigureText); + } + + /// + /// The write report. + /// + /// + /// The report. + /// + /// + /// The style. + /// + public void WriteReport(Report report, ReportStyle reportStyle) + { + this.style = reportStyle; + this.WriteHtmlHeader(report.Title, null, CreateCss(reportStyle)); + report.Write(this); + } + + /// + /// Writes the items. + /// + /// + /// The table. + /// + public void WriteRows(Table t) + { + IList columns = t.Columns; + + foreach (var c in columns) + { + this.WriteStartElement("col"); + this.WriteAttributeString("align", GetAlignmentString(c.Alignment)); + if (double.IsNaN(c.Width)) + { + this.WriteAttributeString("width", c.Width + "pt"); + } + + this.WriteEndElement(); + } + + foreach (var row in t.Rows) + { + if (row.IsHeader) + { + this.WriteStartElement("thead"); + } + + this.WriteStartElement("tr"); + int j = 0; + foreach (var c in row.Cells) + { + bool isHeader = row.IsHeader || t.Columns[j++].IsHeader; + + this.WriteStartElement("td"); + if (isHeader) + { + this.WriteAttributeString("class", "header"); + } + + this.WriteString(c.Content); + this.WriteEndElement(); + } + + this.WriteEndElement(); // tr + if (row.IsHeader) + { + this.WriteEndElement(); // thead + } + } + } + + /// + /// Writes the table. + /// + /// + /// The t. + /// + public void WriteTable(Table t) + { + if (t.Rows == null || t.Columns == null) + { + return; + } + + this.WriteStartElement("table"); + + // WriteAttributeString("border", "1"); + // WriteAttributeString("width", "60%"); + if (t.Caption != null) + { + this.WriteStartElement("caption"); + this.WriteString(t.GetFullCaption(this.style)); + this.WriteEndElement(); + } + + this.WriteRows(t); + + this.WriteEndElement(); // table + } + + /// + /// Creates the css section. + /// + /// + /// The style. + /// + /// + /// The css. + /// + private static string CreateCss(ReportStyle style) + { + var css = new StringBuilder(); + css.AppendLine("body { " + ParagraphStyleToCss(style.BodyTextStyle) + " }"); + for (int i = 0; i < style.HeaderStyles.Length; i++) + { + css.AppendLine("h" + (i + 1) + " {" + ParagraphStyleToCss(style.HeaderStyles[i]) + " }"); + } + + css.AppendLine("table caption { " + ParagraphStyleToCss(style.TableCaptionStyle) + " }"); + css.AppendLine("thead { " + ParagraphStyleToCss(style.TableHeaderStyle) + " }"); + css.AppendLine("td { " + ParagraphStyleToCss(style.TableTextStyle) + " }"); + css.AppendLine("td.header { " + ParagraphStyleToCss(style.TableHeaderStyle) + " }"); + css.AppendLine("figuretext { " + ParagraphStyleToCss(style.FigureTextStyle) + " }"); + + css.Append( + @"body { margin:20pt; } + table { border: solid 1px black; margin: 8pt; border-collapse:collapse; } + td { padding: 0 2pt 0 2pt; border-left: solid 1px black; border-right: solid 1px black;} + thead { border:solid 1px black; } + .content, .content td { border: none; } + .figure { margin: 8pt;} + .table { margin: 8pt;} + .table caption { margin: 4pt;} + .table thead td { padding: 2pt;}"); + return css.ToString(); + } + + /// + /// Gets the alignment string. + /// + /// + /// The alignment type. + /// + /// + /// An alignment string. + /// + private static string GetAlignmentString(Alignment a) + { + return a.ToString().ToLower(); + } + + /// + /// Converts a paragraphes style to css. + /// + /// + /// The style. + /// + /// + /// A css string. + /// + private static string ParagraphStyleToCss(ParagraphStyle s) + { + var css = new StringBuilder(); + if (s.FontFamily != null) + { + css.Append(string.Format("font-family:{0};", s.FontFamily)); + } + + css.Append(string.Format("font-size:{0}pt;", s.FontSize)); + if (s.Bold) + { + css.Append(string.Format("font-weight:bold;")); + } + + return css.ToString(); + } + + /// + /// Initializes this instance. + /// + private void WriteHtmlElement() + { + this.WriteStartElement("html", "http://www.w3.org/1999/xhtml"); + } + + /// + /// Writes the div. + /// + /// + /// The style of the div. + /// + /// + /// The content. + /// + private void WriteDiv(string divstyle, string content) + { + this.WriteStartElement("div"); + this.WriteAttributeString("class", divstyle); + this.WriteString(content); + this.WriteEndElement(); + } + + /// + /// Writes the end figure. + /// + /// + /// The figure text. + /// + private void WriteEndFigure(string text) + { + this.WriteDiv("figuretext", string.Format("Fig {0}. {1}", this.figureCounter, text)); + this.WriteEndElement(); + } + + /// + /// Writes the HTML header. + /// + /// + /// The title. + /// + /// + /// The CSS path. + /// + /// + /// The style. + /// + private void WriteHtmlHeader(string title, string cssPath, string cssStyle) + { + this.WriteStartElement("head"); + + if (title != null) + { + this.WriteElementString("title", title); + } + + if (cssPath != null) + { + this.WriteStartElement("link"); + this.WriteAttributeString("href", cssPath); + this.WriteAttributeString("rel", "stylesheet"); + this.WriteAttributeString("type", "text/css"); + this.WriteEndElement(); // link + } + + if (cssStyle != null) + { + this.WriteStartElement("style"); + this.WriteAttributeString("type", "text/css"); + this.WriteRaw(cssStyle); + this.WriteEndElement(); + } + + this.WriteEndElement(); // head + this.WriteStartElement("body"); + } + + /// + /// Writes the start figure element. + /// + private void WriteStartFigure() + { + this.figureCounter++; + this.WriteStartElement("p"); + this.WriteClassId("figure"); + } + + } +} \ No newline at end of file diff -r 88d699a65cc2 -r 5be8f2773237 External/OxyPlot/OxyPlot/Reporting/ReportWriters/IReportWriter.cs --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/External/OxyPlot/OxyPlot/Reporting/ReportWriters/IReportWriter.cs Sat Jun 08 16:53:22 2013 +0000 @@ -0,0 +1,87 @@ +// -------------------------------------------------------------------------------------------------------------------- +// +// The MIT License (MIT) +// +// Copyright (c) 2012 Oystein Bjorke +// +// Permission is hereby granted, free of charge, to any person obtaining a +// copy of this software and associated documentation files (the +// "Software"), to deal in the Software without restriction, including +// without limitation the rights to use, copy, modify, merge, publish, +// distribute, sublicense, and/or sell copies of the Software, and to +// permit persons to whom the Software is furnished to do so, subject to +// the following conditions: +// +// The above copyright notice and this permission notice shall be included +// in all copies or substantial portions of the Software. +// +// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS +// OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF +// MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. +// IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY +// CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, +// TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE +// SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. +// +// +// Interface for Report writers. +// +// -------------------------------------------------------------------------------------------------------------------- +namespace OxyPlot.Reporting +{ + /// + /// Interface for Report writers. + /// + public interface IReportWriter + { + /// + /// Writes the drawing. + /// + /// The drawing. + void WriteDrawing(DrawingFigure drawing); + + /// + /// Writes the equation. + /// + /// The equation. + void WriteEquation(Equation equation); + + /// + /// Writes the header. + /// + /// The header. + void WriteHeader(Header header); + + /// + /// Writes the image. + /// + /// The image. + void WriteImage(Image image); + + /// + /// Writes the paragraph. + /// + /// The paragraph. + void WriteParagraph(Paragraph paragraph); + + /// + /// Writes the plot. + /// + /// The plot. + void WritePlot(PlotFigure plot); + + /// + /// Writes the report. + /// + /// The report. + /// The style. + void WriteReport(Report report, ReportStyle reportStyle); + + /// + /// Writes the table. + /// + /// The table. + void WriteTable(Table table); + + } +} \ No newline at end of file diff -r 88d699a65cc2 -r 5be8f2773237 External/OxyPlot/OxyPlot/Reporting/ReportWriters/StringExtensions.cs --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/External/OxyPlot/OxyPlot/Reporting/ReportWriters/StringExtensions.cs Sat Jun 08 16:53:22 2013 +0000 @@ -0,0 +1,130 @@ +// -------------------------------------------------------------------------------------------------------------------- +// +// The MIT License (MIT) +// +// Copyright (c) 2012 Oystein Bjorke +// +// Permission is hereby granted, free of charge, to any person obtaining a +// copy of this software and associated documentation files (the +// "Software"), to deal in the Software without restriction, including +// without limitation the rights to use, copy, modify, merge, publish, +// distribute, sublicense, and/or sell copies of the Software, and to +// permit persons to whom the Software is furnished to do so, subject to +// the following conditions: +// +// The above copyright notice and this permission notice shall be included +// in all copies or substantial portions of the Software. +// +// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS +// OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF +// MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. +// IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY +// CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, +// TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE +// SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. +// +// +// The string extensions. +// +// -------------------------------------------------------------------------------------------------------------------- +namespace OxyPlot.Reporting +{ + using System.Collections.Generic; + using System.Text; + + /// + /// The string extensions. + /// + public static class StringExtensions + { + /// + /// The repeat. + /// + /// + /// The source. + /// + /// + /// The n. + /// + /// + /// The repeat. + /// + public static string Repeat(this string source, int n) + { + var sb = new StringBuilder(n * source.Length); + for (int i = 0; i < n; i++) + { + sb.Append(source); + } + + return sb.ToString(); + } + + /// + /// The split lines. + /// + /// + /// The s. + /// + /// + /// The line length. + /// + /// + /// + public static string[] SplitLines(this string s, int lineLength = 80) + { + var lines = new List(); + + int i = 0; + while (i < s.Length) + { + int len = FindLineLength(s, i, lineLength); + lines.Add(len == 0 ? s.Substring(i).Trim() : s.Substring(i, len).Trim()); + i += len; + if (len == 0) + { + break; + } + } + + return lines.ToArray(); + } + + /// + /// The find line length. + /// + /// + /// The text. + /// + /// + /// The i. + /// + /// + /// The max line length. + /// + /// + /// The find line length. + /// + private static int FindLineLength(string text, int i, int maxLineLength) + { + int i2 = i + 1; + int len = 0; + while (i2 < i + maxLineLength && i2 < text.Length) + { + i2 = text.IndexOfAny(" \n\r".ToCharArray(), i2 + 1); + if (i2 == -1) + { + i2 = text.Length; + } + + if (i2 - i < maxLineLength) + { + len = i2 - i; + } + } + + return len; + } + + } +} \ No newline at end of file diff -r 88d699a65cc2 -r 5be8f2773237 External/OxyPlot/OxyPlot/Reporting/ReportWriters/TextReportWriter.cs --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/External/OxyPlot/OxyPlot/Reporting/ReportWriters/TextReportWriter.cs Sat Jun 08 16:53:22 2013 +0000 @@ -0,0 +1,289 @@ +// -------------------------------------------------------------------------------------------------------------------- +// +// The MIT License (MIT) +// +// Copyright (c) 2012 Oystein Bjorke +// +// Permission is hereby granted, free of charge, to any person obtaining a +// copy of this software and associated documentation files (the +// "Software"), to deal in the Software without restriction, including +// without limitation the rights to use, copy, modify, merge, publish, +// distribute, sublicense, and/or sell copies of the Software, and to +// permit persons to whom the Software is furnished to do so, subject to +// the following conditions: +// +// The above copyright notice and this permission notice shall be included +// in all copies or substantial portions of the Software. +// +// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS +// OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF +// MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. +// IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY +// CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, +// TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE +// SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. +// +// +// ANSI text report writer. +// +// -------------------------------------------------------------------------------------------------------------------- +namespace OxyPlot.Reporting +{ + using System; + using System.IO; + + /// + /// ANSI text report writer. + /// + /// + /// This will not write figures/images. + /// + public class TextReportWriter : StreamWriter, IReportWriter + { + /// + /// The table cell separator. + /// + private const string TableCellSeparator = " | "; + + /// + /// The table row end. + /// + private const string TableRowEnd = " |"; + + /// + /// The table row start. + /// + private const string TableRowStart = "| "; + + /// + /// The table counter. + /// + private int tableCounter; + + /// + /// Initializes a new instance of the class. + /// + /// + /// The stream. + /// + public TextReportWriter(Stream stream) + : base(stream) + { + this.MaxLineLength = 60; + } + + /// + /// Gets or sets MaxLineLength. + /// + public int MaxLineLength { get; set; } + + /// + /// The write drawing. + /// + /// + /// The d. + /// + public void WriteDrawing(DrawingFigure d) + { + } + + /// + /// The write equation. + /// + /// + /// The equation. + /// + public void WriteEquation(Equation equation) + { + } + + /// + /// The write header. + /// + /// + /// The h. + /// + public void WriteHeader(Header h) + { + if (h.Text == null) + { + return; + } + + WriteLine(h); + if (h.Level == 1) + { + this.WriteLine("=".Repeat(h.Text.Length)); + } + + this.WriteLine(); + } + + /// + /// The write image. + /// + /// + /// The i. + /// + public void WriteImage(Image i) + { + } + + /// + /// The write paragraph. + /// + /// + /// The p. + /// + public void WriteParagraph(Paragraph p) + { + foreach (string line in p.Text.SplitLines(this.MaxLineLength)) + { + WriteLine(line); + } + + this.WriteLine(); + } + + /// + /// The write plot. + /// + /// + /// The plot. + /// + public void WritePlot(PlotFigure plot) + { + } + + /// + /// The write report. + /// + /// + /// The report. + /// + /// + /// The style. + /// + public void WriteReport(Report report, ReportStyle reportStyle) + { + report.Write(this); + } + + /// + /// The write table. + /// + /// + /// The t. + /// + public void WriteTable(Table t) + { + this.tableCounter++; + this.WriteLine(string.Format("Table {0}. {1}", this.tableCounter, t.Caption)); + this.WriteLine(); + int rows = t.Rows.Count; + int cols = t.Columns.Count; + + var columnWidth = new int[cols]; + int totalLength = 0; + for (int j = 0; j < cols; j++) + { + columnWidth[j] = 0; + foreach (var tr in t.Rows) + { + TableCell cell = tr.Cells[j]; + string text = cell.Content; + columnWidth[j] = Math.Max(columnWidth[j], text != null ? text.Length : 0); + } + + totalLength += columnWidth[j]; + } + + // WriteLine("-".Repeat(totalLength)); + foreach (var tr in t.Rows) + { + for (int j = 0; j < cols; j++) + { + TableCell cell = tr.Cells[j]; + string text = cell.Content; + this.Write(GetCellText(j, cols, PadString(text, t.Columns[j].Alignment, columnWidth[j]))); + } + + this.WriteLine(); + } + + this.WriteLine(); + } + + /// + /// The get cell text. + /// + /// + /// The i. + /// + /// + /// The count. + /// + /// + /// The p. + /// + /// + /// The get cell text. + /// + private static string GetCellText(int i, int count, string p) + { + if (i == 0) + { + p = TableRowStart + p; + } + + if (i + 1 < count) + { + p += TableCellSeparator; + } + + if (i == count - 1) + { + p += TableRowEnd; + } + + return p; + } + + /// + /// The pad string. + /// + /// + /// The text. + /// + /// + /// The alignment. + /// + /// + /// The width. + /// + /// + /// The pad string. + /// + private static string PadString(string text, Alignment alignment, int width) + { + if (text == null) + { + return string.Empty.PadLeft(width); + } + + switch (alignment) + { + case Alignment.Left: + return text.PadRight(width); + case Alignment.Right: + return text.PadLeft(width); + case Alignment.Center: + text = text.PadRight((text.Length + width) / 2); + return text.PadLeft(width); + } + + return null; + } + + } +} \ No newline at end of file diff -r 88d699a65cc2 -r 5be8f2773237 External/OxyPlot/OxyPlot/Reporting/ReportWriters/WikiReportWriter.cs --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/External/OxyPlot/OxyPlot/Reporting/ReportWriters/WikiReportWriter.cs Sat Jun 08 16:53:22 2013 +0000 @@ -0,0 +1,308 @@ +// -------------------------------------------------------------------------------------------------------------------- +// +// The MIT License (MIT) +// +// Copyright (c) 2012 Oystein Bjorke +// +// Permission is hereby granted, free of charge, to any person obtaining a +// copy of this software and associated documentation files (the +// "Software"), to deal in the Software without restriction, including +// without limitation the rights to use, copy, modify, merge, publish, +// distribute, sublicense, and/or sell copies of the Software, and to +// permit persons to whom the Software is furnished to do so, subject to +// the following conditions: +// +// The above copyright notice and this permission notice shall be included +// in all copies or substantial portions of the Software. +// +// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS +// OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF +// MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. +// IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY +// CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, +// TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE +// SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. +// +// +// Wiki formatting report writer. +// +// -------------------------------------------------------------------------------------------------------------------- +namespace OxyPlot.Reporting +{ + using System; + using System.IO; + + /// + /// Wiki formatting report writer. + /// + /// + /// This will not write figures/images. + /// + public class WikiReportWriter : StreamWriter, IReportWriter + { + /// + /// The table cell separator. + /// + private const string TableCellSeparator = " | "; + + /// + /// The table header cell separator. + /// + private const string TableHeaderCellSeparator = " || "; + + /// + /// The table header row end. + /// + private const string TableHeaderRowEnd = " ||"; + + /// + /// The table header row start. + /// + private const string TableHeaderRowStart = "|| "; + + /// + /// The table row end. + /// + private const string TableRowEnd = " |"; + + /// + /// The table row start. + /// + private const string TableRowStart = "| "; + + /// + /// The table counter. + /// + private int tableCounter; + + /// + /// Initializes a new instance of the class. + /// + /// + /// The s. + /// + public WikiReportWriter(Stream s) + : base(s) + { + this.MaxLineLength = 60; + } + + /// + /// Gets or sets MaxLineLength. + /// + public int MaxLineLength { get; set; } + + /// + /// The write drawing. + /// + /// + /// The d. + /// + public void WriteDrawing(DrawingFigure d) + { + } + + /// + /// The write equation. + /// + /// + /// The equation. + /// + public void WriteEquation(Equation equation) + { + } + + /// + /// The write header. + /// + /// + /// The h. + /// + public void WriteHeader(Header h) + { + if (h.Text == null) + { + return; + } + + string prefix = string.Empty; + for (int i = 0; i < h.Level; i++) + { + prefix += "!"; + } + + this.WriteLine(prefix + " " + h.Text); + } + + /// + /// The write image. + /// + /// + /// The i. + /// + public void WriteImage(Image i) + { + } + + /// + /// The write paragraph. + /// + /// + /// The p. + /// + public void WriteParagraph(Paragraph p) + { + foreach (string line in p.Text.SplitLines(this.MaxLineLength)) + { + WriteLine(line); + } + + this.WriteLine(); + } + + /// + /// The write plot. + /// + /// + /// The plot. + /// + public void WritePlot(PlotFigure plot) + { + } + + /// + /// The write report. + /// + /// + /// The report. + /// + /// + /// The style. + /// + public void WriteReport(Report report, ReportStyle reportStyle) + { + report.Write(this); + } + + /// + /// The write table. + /// + /// + /// The t. + /// + public void WriteTable(Table t) + { + this.tableCounter++; + this.WriteLine(string.Format("Table {0}. {1}", this.tableCounter, t.Caption)); + this.WriteLine(); + int rows = t.Rows.Count; + int cols = t.Columns.Count; + + var columnWidth = new int[cols]; + int totalLength = 0; + for (int j = 0; j < cols; j++) + { + columnWidth[j] = 0; + foreach (var tr in t.Rows) + { + TableCell cell = tr.Cells[j]; + string text = cell.Content; + columnWidth[j] = Math.Max(columnWidth[j], text != null ? text.Length : 0); + } + + totalLength += columnWidth[j]; + } + + // WriteLine("-".Repeat(totalLength)); + foreach (var tr in t.Rows) + { + for (int j = 0; j < cols; j++) + { + TableCell cell = tr.Cells[j]; + string text = cell.Content; + bool isHeader = tr.IsHeader || t.Columns[j].IsHeader; + this.Write(GetCellText(j, cols, PadString(text, t.Columns[j].Alignment, columnWidth[j]), isHeader)); + } + + this.WriteLine(); + } + + this.WriteLine(); + } + + /// + /// The get cell text. + /// + /// + /// The i. + /// + /// + /// The count. + /// + /// + /// The p. + /// + /// + /// The is header. + /// + /// + /// The get cell text. + /// + private static string GetCellText(int i, int count, string p, bool isHeader) + { + if (i == 0) + { + p = isHeader ? TableHeaderRowStart : TableRowStart + p; + } + + if (i + 1 < count) + { + p += isHeader ? TableHeaderCellSeparator : TableCellSeparator; + } + + if (i == count - 1) + { + p += isHeader ? TableHeaderRowEnd : TableRowEnd; + } + + return p; + } + + /// + /// The pad string. + /// + /// + /// The text. + /// + /// + /// The alignment. + /// + /// + /// The width. + /// + /// + /// The pad string. + /// + private static string PadString(string text, Alignment alignment, int width) + { + if (text == null) + { + return string.Empty.PadLeft(width); + } + + switch (alignment) + { + case Alignment.Left: + return text.PadRight(width); + case Alignment.Right: + return text.PadLeft(width); + case Alignment.Center: + text = text.PadRight((text.Length + width) / 2); + return text.PadLeft(width); + } + + return null; + } + + } +} \ No newline at end of file diff -r 88d699a65cc2 -r 5be8f2773237 External/OxyPlot/OxyPlot/Series/AreaSeries.cs --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/External/OxyPlot/OxyPlot/Series/AreaSeries.cs Sat Jun 08 16:53:22 2013 +0000 @@ -0,0 +1,295 @@ +// -------------------------------------------------------------------------------------------------------------------- +// +// The MIT License (MIT) +// +// Copyright (c) 2012 Oystein Bjorke +// +// Permission is hereby granted, free of charge, to any person obtaining a +// copy of this software and associated documentation files (the +// "Software"), to deal in the Software without restriction, including +// without limitation the rights to use, copy, modify, merge, publish, +// distribute, sublicense, and/or sell copies of the Software, and to +// permit persons to whom the Software is furnished to do so, subject to +// the following conditions: +// +// The above copyright notice and this permission notice shall be included +// in all copies or substantial portions of the Software. +// +// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS +// OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF +// MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. +// IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY +// CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, +// TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE +// SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. +// +// +// Represents an area series that fills the polygon defined by one or two sets of points. +// +// -------------------------------------------------------------------------------------------------------------------- +namespace OxyPlot.Series +{ + using System; + using System.Collections.Generic; + + /// + /// Represents an area series that fills the polygon defined by two sets of points or one set of points and a constant. + /// + public class AreaSeries : LineSeries + { + /// + /// The second list of points. + /// + private readonly List points2 = new List(); + + /// + /// Initializes a new instance of the class. + /// + public AreaSeries() + { + this.Reverse2 = true; + } + + /// + /// Gets or sets a constant value for the area definition. + /// This is used if DataFieldBase and BaselineValues are null. + /// + /// The baseline. + public double ConstantY2 { get; set; } + + /// + /// Gets or sets the second X data field. + /// + public string DataFieldX2 { get; set; } + + /// + /// Gets or sets the second Y data field. + /// + public string DataFieldY2 { get; set; } + + /// + /// Gets or sets the area fill color. + /// + /// The fill. + public OxyColor Fill { get; set; } + + /// + /// Gets the second list of points. + /// + /// The second list of points. + public List Points2 + { + get + { + return this.points2; + } + } + + /// + /// Gets or sets a value indicating whether the second + /// data collection should be reversed. + /// The first dataset is not reversed, and normally + /// the second dataset should be reversed to get a + /// closed polygon. + /// + public bool Reverse2 { get; set; } + + /// + /// Gets the nearest point. + /// + /// The point. + /// interpolate if set to true . + /// A TrackerHitResult for the current hit. + public override TrackerHitResult GetNearestPoint(ScreenPoint point, bool interpolate) + { + if (interpolate) + { + var r1 = this.GetNearestInterpolatedPointInternal(this.Points, point); + if (r1 != null) + { + return r1; + } + + var r2 = this.GetNearestInterpolatedPointInternal(this.points2, point); + if (r2 != null) + { + return r2; + } + } + else + { + var result1 = this.GetNearestPointInternal(this.Points, point); + var result2 = this.GetNearestPointInternal(this.points2, point); + + if (result1 != null && result2 != null) + { + double dist1 = result1.Position.DistanceTo(point); + double dist2 = result2.Position.DistanceTo(point); + return dist1 < dist2 ? result1 : result2; + } + + if (result1 != null) + { + return result1; + } + + if (result2 != null) + { + return result2; + } + } + + return null; + } + + /// + /// Renders the series on the specified rendering context. + /// + /// The rendering context. + /// The owner plot model. + public override void Render(IRenderContext rc, PlotModel model) + { + if (this.Points.Count == 0) + { + return; + } + + base.VerifyAxes(); + + double minDistSquared = this.MinimumSegmentLength * this.MinimumSegmentLength; + + var clippingRect = this.GetClippingRect(); + + // Transform all points to screen coordinates + var points = this.Points; + int n0 = points.Count; + IList pts0 = new ScreenPoint[n0]; + for (int i = 0; i < n0; i++) + { + pts0[i] = this.XAxis.Transform(points[i].X, points[i].Y, this.YAxis); + } + + int n1 = this.points2.Count; + IList pts1 = new ScreenPoint[n1]; + for (int i = 0; i < n1; i++) + { + int j = this.Reverse2 ? n1 - 1 - i : i; + pts1[j] = this.XAxis.Transform(this.points2[i].X, this.points2[i].Y, this.YAxis); + } + + if (this.Smooth) + { + var rpts0 = ScreenPointHelper.ResamplePoints(pts0, this.MinimumSegmentLength); + var rpts1 = ScreenPointHelper.ResamplePoints(pts1, this.MinimumSegmentLength); + + pts0 = CanonicalSplineHelper.CreateSpline(rpts0, 0.5, null, false, 0.25); + pts1 = CanonicalSplineHelper.CreateSpline(rpts1, 0.5, null, false, 0.25); + } + + // draw the clipped lines + rc.DrawClippedLine( + pts0, + clippingRect, + minDistSquared, + this.GetSelectableColor(this.ActualColor), + this.StrokeThickness, + this.ActualLineStyle, + this.LineJoin, + false); + rc.DrawClippedLine( + pts1, + clippingRect, + minDistSquared, + this.GetSelectableColor(this.ActualColor), + this.StrokeThickness, + this.ActualLineStyle, + this.LineJoin, + false); + + // combine the two lines and draw the clipped area + var pts = new List(); + pts.AddRange(pts1); + pts.AddRange(pts0); + + // pts = SutherlandHodgmanClipping.ClipPolygon(clippingRect, pts); + rc.DrawClippedPolygon(pts, clippingRect, minDistSquared, this.GetSelectableFillColor(this.Fill), null); + + // draw the markers on top + rc.DrawMarkers( + pts0, + clippingRect, + this.MarkerType, + null, + new[] { this.MarkerSize }, + this.MarkerFill, + this.MarkerStroke, + this.MarkerStrokeThickness, + 1); + rc.DrawMarkers( + pts1, + clippingRect, + this.MarkerType, + null, + new[] { this.MarkerSize }, + this.MarkerFill, + this.MarkerStroke, + this.MarkerStrokeThickness, + 1); + } + + /// + /// Renders the legend symbol for the line series on the + /// specified rendering context. + /// + /// + /// The rendering context. + /// + /// + /// The bounding rectangle of the legend box. + /// + public override void RenderLegend(IRenderContext rc, OxyRect legendBox) + { + double y0 = (legendBox.Top * 0.2) + (legendBox.Bottom * 0.8); + double y1 = (legendBox.Top * 0.4) + (legendBox.Bottom * 0.6); + double y2 = (legendBox.Top * 0.8) + (legendBox.Bottom * 0.2); + + var pts0 = new[] { new ScreenPoint(legendBox.Left, y0), new ScreenPoint(legendBox.Right, y0) }; + var pts1 = new[] { new ScreenPoint(legendBox.Right, y2), new ScreenPoint(legendBox.Left, y1) }; + var pts = new List(); + pts.AddRange(pts0); + pts.AddRange(pts1); + var color = this.GetSelectableColor(this.ActualColor); + rc.DrawLine(pts0, color, this.StrokeThickness, LineStyleHelper.GetDashArray(this.ActualLineStyle)); + rc.DrawLine(pts1, color, this.StrokeThickness, LineStyleHelper.GetDashArray(this.ActualLineStyle)); + rc.DrawPolygon(pts, this.GetSelectableFillColor(this.Fill), null); + } + + /// + /// The update data. + /// + protected internal override void UpdateData() + { + base.UpdateData(); + + if (this.ItemsSource == null) + { + return; + } + + this.points2.Clear(); + + // Using reflection on DataFieldX2 and DataFieldY2 + this.AddDataPoints(this.points2, this.ItemsSource, this.DataFieldX2, this.DataFieldY2); + } + + /// + /// The update max min. + /// + protected internal override void UpdateMaxMin() + { + base.UpdateMaxMin(); + this.InternalUpdateMaxMin(this.points2); + } + + } +} \ No newline at end of file diff -r 88d699a65cc2 -r 5be8f2773237 External/OxyPlot/OxyPlot/Series/BarSeries/BarItem.cs --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/External/OxyPlot/OxyPlot/Series/BarSeries/BarItem.cs Sat Jun 08 16:53:22 2013 +0000 @@ -0,0 +1,64 @@ +// -------------------------------------------------------------------------------------------------------------------- +// +// The MIT License (MIT) +// +// Copyright (c) 2012 Oystein Bjorke +// +// Permission is hereby granted, free of charge, to any person obtaining a +// copy of this software and associated documentation files (the +// "Software"), to deal in the Software without restriction, including +// without limitation the rights to use, copy, modify, merge, publish, +// distribute, sublicense, and/or sell copies of the Software, and to +// permit persons to whom the Software is furnished to do so, subject to +// the following conditions: +// +// The above copyright notice and this permission notice shall be included +// in all copies or substantial portions of the Software. +// +// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS +// OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF +// MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. +// IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY +// CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, +// TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE +// SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. +// +// +// Represents an item used in the BarSeries. +// +// -------------------------------------------------------------------------------------------------------------------- +namespace OxyPlot.Series +{ + /// + /// Represents an item used in the BarSeries. + /// + public class BarItem : BarItemBase + { + /// + /// Initializes a new instance of the class. + /// + public BarItem() + { + } + + /// + /// Initializes a new instance of the class. + /// + /// + /// The value. + /// + /// + /// Index of the category. + /// + /// + /// The color. + /// + public BarItem(double value, int categoryIndex = -1, OxyColor color = null) + { + this.Value = value; + this.CategoryIndex = categoryIndex; + this.Color = color; + } + + } +} \ No newline at end of file diff -r 88d699a65cc2 -r 5be8f2773237 External/OxyPlot/OxyPlot/Series/BarSeries/BarItemBase.cs --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/External/OxyPlot/OxyPlot/Series/BarSeries/BarItemBase.cs Sat Jun 08 16:53:22 2013 +0000 @@ -0,0 +1,83 @@ +// -------------------------------------------------------------------------------------------------------------------- +// +// The MIT License (MIT) +// +// Copyright (c) 2012 Oystein Bjorke +// +// Permission is hereby granted, free of charge, to any person obtaining a +// copy of this software and associated documentation files (the +// "Software"), to deal in the Software without restriction, including +// without limitation the rights to use, copy, modify, merge, publish, +// distribute, sublicense, and/or sell copies of the Software, and to +// permit persons to whom the Software is furnished to do so, subject to +// the following conditions: +// +// The above copyright notice and this permission notice shall be included +// in all copies or substantial portions of the Software. +// +// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS +// OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF +// MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. +// IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY +// CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, +// TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE +// SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. +// +// +// Represents an item used in the BarSeriesBase. +// +// -------------------------------------------------------------------------------------------------------------------- +namespace OxyPlot.Series +{ + /// + /// Represents an item used in the BarSeriesBase. + /// + public abstract class BarItemBase : CategorizedItem, ICodeGenerating + { + /// + /// Initializes a new instance of the class. Initializes a new instance of the class. + /// + protected BarItemBase() + { + // Label = null; + this.Value = double.NaN; + this.Color = null; + } + + /// + /// Gets or sets the color of the item. + /// + /// + /// If the color is not specified (default), the color of the series will be used. + /// + public OxyColor Color { get; set; } + + /// + /// Gets or sets the value of the item. + /// + public double Value { get; set; } + + /// + /// Returns c# code that generates this instance. + /// + /// + /// C# code. + /// + public virtual string ToCode() + { + if (this.Color != null) + { + return CodeGenerator.FormatConstructor( + this.GetType(), "{0},{1},{2}", this.Value, this.CategoryIndex, this.Color.ToCode()); + } + + if (this.CategoryIndex != -1) + { + return CodeGenerator.FormatConstructor(this.GetType(), "{0},{1}", this.Value, this.CategoryIndex); + } + + return CodeGenerator.FormatConstructor(this.GetType(), "{0}", this.Value); + } + + } +} \ No newline at end of file diff -r 88d699a65cc2 -r 5be8f2773237 External/OxyPlot/OxyPlot/Series/BarSeries/BarSeries.cs --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/External/OxyPlot/OxyPlot/Series/BarSeries/BarSeries.cs Sat Jun 08 16:53:22 2013 +0000 @@ -0,0 +1,198 @@ +// -------------------------------------------------------------------------------------------------------------------- +// +// The MIT License (MIT) +// +// Copyright (c) 2012 Oystein Bjorke +// +// Permission is hereby granted, free of charge, to any person obtaining a +// copy of this software and associated documentation files (the +// "Software"), to deal in the Software without restriction, including +// without limitation the rights to use, copy, modify, merge, publish, +// distribute, sublicense, and/or sell copies of the Software, and to +// permit persons to whom the Software is furnished to do so, subject to +// the following conditions: +// +// The above copyright notice and this permission notice shall be included +// in all copies or substantial portions of the Software. +// +// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS +// OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF +// MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. +// IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY +// CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, +// TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE +// SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. +// +// +// Represents a series for clustered or stacked bar charts. +// +// -------------------------------------------------------------------------------------------------------------------- +namespace OxyPlot.Series +{ + using System; + + using OxyPlot.Axes; + + /// + /// Represents a series for clustered or stacked bar charts. + /// + public class BarSeries : BarSeriesBase + { + /// + /// Initializes a new instance of the class. + /// + public BarSeries() + { + this.BarWidth = 1; + } + + /// + /// Gets or sets the width (height) of the bars. + /// + /// + /// The width of the bars. + /// + public double BarWidth { get; set; } + + /// + /// Gets or sets the width of the columns/bars (as a fraction of the available space). + /// + /// + /// The fractional width. + /// + /// + /// The width of the bars. + /// + /// + /// The available space will be determined by the GapWidth of the CategoryAxis used by this series. + /// + internal override double GetBarWidth() + { + return this.BarWidth; + } + + /// + /// Gets the actual width/height of the items of this series. + /// + /// + /// The width or height. + /// + /// + /// The actual width is also influenced by the GapWidth of the CategoryAxis used by this series. + /// + protected override double GetActualBarWidth() + { + var categoryAxis = this.GetCategoryAxis(); + return this.BarWidth / (1 + categoryAxis.GapWidth) / categoryAxis.MaxWidth; + } + + /// + /// Gets the category axis. + /// + /// + /// The category axis. + /// + protected override CategoryAxis GetCategoryAxis() + { + if (!(this.YAxis is CategoryAxis)) + { + throw new Exception( + "A BarSeries requires a CategoryAxis on the y-axis. Use a ColumnSeries if you want vertical bars."); + } + + return this.YAxis as CategoryAxis; + } + + /// + /// Gets the rectangle for the specified values. + /// + /// + /// The base value of the bar + /// + /// + /// The top value of the bar + /// + /// + /// The begin value of the bar + /// + /// + /// The end value of the bar + /// + /// + /// The rectangle. + /// + protected override OxyRect GetRectangle(double baseValue, double topValue, double beginValue, double endValue) + { + return OxyRect.Create(this.Transform(baseValue, beginValue), this.Transform(topValue, endValue)); + } + + /// + /// Gets the value axis. + /// + /// + /// The value axis. + /// + protected override Axis GetValueAxis() + { + return this.XAxis; + } + + /// + /// Draws the label. + /// + /// + /// The render context. + /// + /// + /// The clipping rect. + /// + /// + /// The rect. + /// + /// + /// The value. + /// + /// + /// The i. + /// + protected override void RenderLabel(IRenderContext rc, OxyRect clippingRect, OxyRect rect, double value, int i) + { + var s = StringHelper.Format( + this.ActualCulture, this.LabelFormatString, this.GetItem(this.ValidItemsIndexInversion[i]), value); + HorizontalAlignment ha; + ScreenPoint pt; + switch (this.LabelPlacement) + { + case LabelPlacement.Inside: + pt = new ScreenPoint(rect.Right - this.LabelMargin, (rect.Top + rect.Bottom) / 2); + ha = HorizontalAlignment.Right; + break; + case LabelPlacement.Middle: + pt = new ScreenPoint((rect.Left + rect.Right) / 2, (rect.Top + rect.Bottom) / 2); + ha = HorizontalAlignment.Center; + break; + case LabelPlacement.Base: + pt = new ScreenPoint(rect.Left + this.LabelMargin, (rect.Top + rect.Bottom) / 2); + ha = HorizontalAlignment.Left; + break; + default: // Outside + pt = new ScreenPoint(rect.Right + this.LabelMargin, (rect.Top + rect.Bottom) / 2); + ha = HorizontalAlignment.Left; + break; + } + + rc.DrawClippedText( + clippingRect, + pt, + s, + this.ActualTextColor, + this.ActualFont, + this.ActualFontSize, + this.ActualFontWeight, + 0, + ha, + VerticalAlignment.Middle); + } + + } +} \ No newline at end of file diff -r 88d699a65cc2 -r 5be8f2773237 External/OxyPlot/OxyPlot/Series/BarSeries/BarSeriesBase.cs --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/External/OxyPlot/OxyPlot/Series/BarSeries/BarSeriesBase.cs Sat Jun 08 16:53:22 2013 +0000 @@ -0,0 +1,603 @@ +// -------------------------------------------------------------------------------------------------------------------- +// +// The MIT License (MIT) +// +// Copyright (c) 2012 Oystein Bjorke +// +// Permission is hereby granted, free of charge, to any person obtaining a +// copy of this software and associated documentation files (the +// "Software"), to deal in the Software without restriction, including +// without limitation the rights to use, copy, modify, merge, publish, +// distribute, sublicense, and/or sell copies of the Software, and to +// permit persons to whom the Software is furnished to do so, subject to +// the following conditions: +// +// The above copyright notice and this permission notice shall be included +// in all copies or substantial portions of the Software. +// +// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS +// OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF +// MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. +// IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY +// CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, +// TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE +// SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. +// +// +// Base class for BarSeries and ColumnSeries. +// +// -------------------------------------------------------------------------------------------------------------------- +namespace OxyPlot.Series +{ + using System; + using System.Collections.Generic; + using System.Linq; + + using OxyPlot.Axes; + + /// + /// Base class for BarSeries and ColumnSeries. + /// + public abstract class BarSeriesBase : CategorizedSeries, IStackableSeries + { + /// + /// The default fill color. + /// + private OxyColor defaultFillColor; + + /// + /// Initializes a new instance of the class. + /// + protected BarSeriesBase() + { + this.StrokeColor = OxyColors.Black; + this.StrokeThickness = 0; + this.TrackerFormatString = "{0}, {1}: {2}"; + this.LabelMargin = 2; + this.StackGroup = string.Empty; + } + + /// + /// Gets or sets the base value. + /// + /// + /// The base value. + /// + public double BaseValue { get; set; } + + /// + /// Gets or sets the color field. + /// + public string ColorField { get; set; } + + /// + /// Gets or sets the color of the interior of the bars. + /// + /// + /// The color. + /// + public OxyColor FillColor { get; set; } + + /// + /// Gets the actual fill color. + /// + /// The actual color. + public OxyColor ActualFillColor + { + get { return this.FillColor ?? this.defaultFillColor; } + } + + /// + /// Gets or sets a value indicating whether this bar series is stacked. + /// + public bool IsStacked { get; set; } + + /// + /// Gets or sets the label format string. + /// + /// + /// The label format string. + /// + public string LabelFormatString { get; set; } + + /// + /// Gets or sets the label margins. + /// + public double LabelMargin { get; set; } + + /// + /// Gets or sets label placements. + /// + public LabelPlacement LabelPlacement { get; set; } + + /// + /// Gets or sets the color of the interior of the bars when the value is negative. + /// + /// + /// The color. + /// + public OxyColor NegativeFillColor { get; set; } + + /// + /// Gets or sets the stack index indication to which stack the series belongs. Default is 0. Hence, all stacked series belong to the same stack. + /// + public string StackGroup { get; set; } + + /// + /// Gets or sets the color of the border around the bars. + /// + /// + /// The color of the stroke. + /// + public OxyColor StrokeColor { get; set; } + + /// + /// Gets or sets the thickness of the bar border strokes. + /// + /// + /// The stroke thickness. + /// + public double StrokeThickness { get; set; } + + /// + /// Gets or sets the value field. + /// + public string ValueField { get; set; } + + /// + /// Gets or sets the valid items + /// + protected internal IList ValidItems { get; set; } + + /// + /// Gets or sets the dictionary which stores the index-inversion for the valid items + /// + protected internal Dictionary ValidItemsIndexInversion { get; set; } + + /// + /// Gets or sets the actual rectangles for the bars. + /// + protected IList ActualBarRectangles { get; set; } + + /// + /// Gets the nearest point. + /// + /// + /// The point. + /// + /// + /// interpolate if set to true . + /// + /// + /// A TrackerHitResult for the current hit. + /// + public override TrackerHitResult GetNearestPoint(ScreenPoint point, bool interpolate) + { + if (this.ActualBarRectangles == null || this.ValidItems == null) + { + return null; + } + + var i = 0; + foreach (var rectangle in this.ActualBarRectangles) + { + if (rectangle.Contains(point)) + { + var categoryIndex = this.ValidItems[i].GetCategoryIndex(i); + + var dp = new DataPoint(categoryIndex, this.ValidItems[i].Value); + var item = this.GetItem(this.ValidItemsIndexInversion[i]); + var text = this.GetTrackerText(item, categoryIndex); + return new TrackerHitResult(this, dp, point, item, i, text); + } + + i++; + } + + return null; + } + + /// + /// Renders the series on the specified rendering context. + /// + /// + /// The rendering context. + /// + /// + /// The model. + /// + public override void Render(IRenderContext rc, PlotModel model) + { + this.ActualBarRectangles = new List(); + + if (this.ValidItems == null || this.ValidItems.Count == 0) + { + return; + } + + var clippingRect = this.GetClippingRect(); + var categoryAxis = this.GetCategoryAxis(); + + var actualBarWidth = this.GetActualBarWidth(); + var stackIndex = this.IsStacked ? categoryAxis.StackIndexMapping[this.StackGroup] : 0; + for (var i = 0; i < this.ValidItems.Count; i++) + { + var item = this.ValidItems[i]; + var categoryIndex = this.ValidItems[i].GetCategoryIndex(i); + + var value = item.Value; + + // Get base- and topValue + var baseValue = double.NaN; + if (this.IsStacked) + { + baseValue = value < 0 + ? categoryAxis.NegativeBaseValues[stackIndex, categoryIndex] + : categoryAxis.PositiveBaseValues[stackIndex, categoryIndex]; + } + + if (double.IsNaN(baseValue)) + { + baseValue = this.BaseValue; + } + + var topValue = this.IsStacked ? baseValue + value : value; + + // Calculate offset + double categoryValue; + if (this.IsStacked) + { + categoryValue = categoryAxis.GetCategoryValue(categoryIndex, stackIndex, actualBarWidth); + } + else + { + categoryValue = categoryIndex - 0.5 + categoryAxis.BarOffset[categoryIndex]; + } + + if (this.IsStacked) + { + if (value < 0) + { + categoryAxis.NegativeBaseValues[stackIndex, categoryIndex] = topValue; + } + else + { + categoryAxis.PositiveBaseValues[stackIndex, categoryIndex] = topValue; + } + } + + var rect = this.GetRectangle(baseValue, topValue, categoryValue, categoryValue + actualBarWidth); + this.ActualBarRectangles.Add(rect); + + this.RenderItem(rc, clippingRect, topValue, categoryValue, actualBarWidth, item, rect); + + if (this.LabelFormatString != null) + { + this.RenderLabel(rc, clippingRect, rect, value, i); + } + + if (!this.IsStacked) + { + categoryAxis.BarOffset[categoryIndex] += actualBarWidth; + } + } + } + + /// + /// Renders the legend symbol on the specified rendering context. + /// + /// + /// The rendering context. + /// + /// + /// The legend rectangle. + /// + public override void RenderLegend(IRenderContext rc, OxyRect legendBox) + { + var xmid = (legendBox.Left + legendBox.Right) / 2; + var ymid = (legendBox.Top + legendBox.Bottom) / 2; + var height = (legendBox.Bottom - legendBox.Top) * 0.8; + var width = height; + rc.DrawRectangleAsPolygon( + new OxyRect(xmid - (0.5 * width), ymid - (0.5 * height), width, height), + this.GetSelectableColor(this.ActualFillColor), + this.StrokeColor, + this.StrokeThickness); + } + + /// + /// Check if the data series is using the specified axis. + /// + /// + /// An axis which should be checked if used + /// + /// + /// True if the axis is in use. + /// + protected internal override bool IsUsing(Axis axis) + { + return this.XAxis == axis || this.YAxis == axis; + } + + /// + /// The set default values. + /// + /// + /// The model. + /// + protected internal override void SetDefaultValues(PlotModel model) + { + if (this.FillColor == null) + { + this.defaultFillColor = model.GetDefaultColor(); + } + } + + /// + /// The update axis max min. + /// + protected internal override void UpdateAxisMaxMin() + { + var valueAxis = this.GetValueAxis(); + if (valueAxis.IsVertical()) + { + valueAxis.Include(this.MinY); + valueAxis.Include(this.MaxY); + } + else + { + valueAxis.Include(this.MinX); + valueAxis.Include(this.MaxX); + } + } + + /// + /// Updates the maximum/minimum value on the value axis from the bar values. + /// + protected internal override void UpdateMaxMin() + { + base.UpdateMaxMin(); + + if (this.ValidItems == null || this.ValidItems.Count == 0) + { + return; + } + + var categoryAxis = this.GetCategoryAxis(); + + double minValue = double.MaxValue, maxValue = double.MinValue; + if (this.IsStacked) + { + var labels = this.GetCategoryAxis().Labels; + for (var i = 0; i < labels.Count; i++) + { + int j = 0; + var values = + this.ValidItems.Where(item => item.GetCategoryIndex(j++) == i).Select(item => item.Value).Concat(new[] { 0d }).ToList(); + var minTemp = values.Where(v => v <= 0).Sum(); + var maxTemp = values.Where(v => v >= 0).Sum(); + + int stackIndex = categoryAxis.StackIndexMapping[this.StackGroup]; + var stackedMinValue = categoryAxis.MinValue[stackIndex, i]; + if (!double.IsNaN(stackedMinValue)) + { + minTemp += stackedMinValue; + } + + categoryAxis.MinValue[stackIndex, i] = minTemp; + + var stackedMaxValue = categoryAxis.MaxValue[stackIndex, i]; + if (!double.IsNaN(stackedMaxValue)) + { + maxTemp += stackedMaxValue; + } + + categoryAxis.MaxValue[stackIndex, i] = maxTemp; + + minValue = Math.Min(minValue, minTemp + this.BaseValue); + maxValue = Math.Max(maxValue, maxTemp + this.BaseValue); + } + } + else + { + var values = this.ValidItems.Select(item => item.Value).Concat(new[] { 0d }).ToList(); + minValue = values.Min(); + maxValue = values.Max(); + if (this.BaseValue < minValue) + { + minValue = this.BaseValue; + } + + if (this.BaseValue > maxValue) + { + maxValue = this.BaseValue; + } + } + + var valueAxis = this.GetValueAxis(); + if (valueAxis.IsVertical()) + { + this.MinY = minValue; + this.MaxY = maxValue; + } + else + { + this.MinX = minValue; + this.MaxX = maxValue; + } + } + + /// + /// Updates the valid items + /// + protected internal override void UpdateValidData() + { + this.ValidItems = new List(); + this.ValidItemsIndexInversion = new Dictionary(); + var categories = this.GetCategoryAxis().Labels.Count; + var valueAxis = this.GetValueAxis(); + + int i = 0; + foreach (var item in this.GetItems()) + { + var barSeriesItem = item as BarItemBase; + + if (barSeriesItem != null && item.GetCategoryIndex(i) < categories + && valueAxis.IsValidValue(barSeriesItem.Value)) + { + this.ValidItemsIndexInversion.Add(this.ValidItems.Count, i); + this.ValidItems.Add(barSeriesItem); + } + + i++; + } + } + + /// + /// Gets the rectangle for the specified values. + /// + /// + /// The base value of the bar + /// + /// + /// The top value of the bar + /// + /// + /// The begin value of the bar + /// + /// + /// The end value of the bar + /// + /// + /// The rectangle. + /// + protected abstract OxyRect GetRectangle(double baseValue, double topValue, double beginValue, double endValue); + + /// + /// Gets the tracker text for the specified item. + /// + /// + /// The item. + /// + /// + /// Category index of the item. + /// + /// + /// The tracker text. + /// + protected virtual string GetTrackerText(object item, int categoryIndex) + { + var barItem = item as BarItemBase; + if (barItem == null) + { + return null; + } + + var categoryAxis = this.GetCategoryAxis(); + + var text = StringHelper.Format( + this.ActualCulture, + this.TrackerFormatString, + item, + this.Title, + categoryAxis.FormatValueForTracker(categoryIndex), + barItem.Value); + return text; + } + + /// + /// Gets the value axis. + /// + /// + /// The value axis. + /// + protected abstract Axis GetValueAxis(); + + /// + /// Checks if the specified value is valid. + /// + /// + /// The value. + /// + /// + /// The y axis. + /// + /// + /// True if the value is valid. + /// + protected virtual bool IsValidPoint(double v, Axis yaxis) + { + return !double.IsNaN(v) && !double.IsInfinity(v); + } + + /// + /// Renders the bar/column item. + /// + /// + /// The render context. + /// + /// + /// The clipping rectangle. + /// + /// + /// The end value of the bar. + /// + /// + /// The category value. + /// + /// + /// The actual width of the bar. + /// + /// + /// The item. + /// + /// + /// The rectangle of the bar. + /// + protected virtual void RenderItem( + IRenderContext rc, + OxyRect clippingRect, + double topValue, + double categoryValue, + double actualBarWidth, + BarItemBase item, + OxyRect rect) + { + // Get the color of the item + var actualFillColor = item.Color; + if (actualFillColor == null) + { + actualFillColor = this.ActualFillColor; + if (item.Value < 0 && this.NegativeFillColor != null) + { + actualFillColor = this.NegativeFillColor; + } + } + + rc.DrawClippedRectangleAsPolygon( + rect, clippingRect, this.GetSelectableFillColor(actualFillColor), this.StrokeColor, this.StrokeThickness); + } + + /// + /// Renders the item label. + /// + /// + /// The render context + /// + /// + /// The clipping rectangle + /// + /// + /// The rectangle of the item. + /// + /// + /// The value of the label. + /// + /// + /// The index of the bar item. + /// + protected abstract void RenderLabel( + IRenderContext rc, OxyRect clippingRect, OxyRect rect, double value, int index); + + } +} \ No newline at end of file diff -r 88d699a65cc2 -r 5be8f2773237 External/OxyPlot/OxyPlot/Series/BarSeries/BarSeriesBase{T}.cs --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/External/OxyPlot/OxyPlot/Series/BarSeries/BarSeriesBase{T}.cs Sat Jun 08 16:53:22 2013 +0000 @@ -0,0 +1,113 @@ +// -------------------------------------------------------------------------------------------------------------------- +// +// The MIT License (MIT) +// +// Copyright (c) 2012 Oystein Bjorke +// +// Permission is hereby granted, free of charge, to any person obtaining a +// copy of this software and associated documentation files (the +// "Software"), to deal in the Software without restriction, including +// without limitation the rights to use, copy, modify, merge, publish, +// distribute, sublicense, and/or sell copies of the Software, and to +// permit persons to whom the Software is furnished to do so, subject to +// the following conditions: +// +// The above copyright notice and this permission notice shall be included +// in all copies or substantial portions of the Software. +// +// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS +// OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF +// MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. +// IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY +// CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, +// TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE +// SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. +// +// +// Generic base class that provides common properties and methods for the BarSeries and ColumnSeries. +// +// -------------------------------------------------------------------------------------------------------------------- +namespace OxyPlot.Series +{ + using System; + using System.Collections; + using System.Collections.Generic; + using System.Linq; + + /// + /// Generic base class that provides common properties and methods for the BarSeries and ColumnSeries. + /// + /// + /// The type of the items. + /// + public abstract class BarSeriesBase : BarSeriesBase + where T : BarItemBase, new() + { + /// + /// Initializes a new instance of the class. Initializes a new instance of the class. + /// + protected BarSeriesBase() + { + this.Items = new List(); + } + + /// + /// Gets the items. + /// + /// + /// The items. + /// + public IList Items { get; private set; } + + /// + /// Gets the items of this series. + /// + /// + /// The items. + /// + protected internal override IList GetItems() + { + return this.Items.Cast().ToList(); + } + + /// + /// Updates the data. + /// + protected internal override void UpdateData() + { + if (this.ItemsSource == null) + { + return; + } + + var dest = new List(); + + // Using reflection to add points + var filler = new ListFiller(); + filler.Add(this.ValueField, (item, value) => item.Value = Convert.ToDouble(value)); + filler.Add(this.ColorField, (item, value) => item.Color = (OxyColor)value); + filler.Fill(dest, this.ItemsSource); + this.Items = dest; + } + + /// + /// Gets the item at the specified index. + /// + /// + /// The index of the item. + /// + /// + /// The item of the index. + /// + protected override object GetItem(int i) + { + if (this.ItemsSource != null || this.Items == null || this.Items.Count == 0) + { + return base.GetItem(i); + } + + return this.Items[i]; + } + + } +} \ No newline at end of file diff -r 88d699a65cc2 -r 5be8f2773237 External/OxyPlot/OxyPlot/Series/BarSeries/CategorizedItem.cs --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/External/OxyPlot/OxyPlot/Series/BarSeries/CategorizedItem.cs Sat Jun 08 16:53:22 2013 +0000 @@ -0,0 +1,73 @@ +// -------------------------------------------------------------------------------------------------------------------- +// +// The MIT License (MIT) +// +// Copyright (c) 2012 Oystein Bjorke +// +// Permission is hereby granted, free of charge, to any person obtaining a +// copy of this software and associated documentation files (the +// "Software"), to deal in the Software without restriction, including +// without limitation the rights to use, copy, modify, merge, publish, +// distribute, sublicense, and/or sell copies of the Software, and to +// permit persons to whom the Software is furnished to do so, subject to +// the following conditions: +// +// The above copyright notice and this permission notice shall be included +// in all copies or substantial portions of the Software. +// +// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS +// OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF +// MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. +// IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY +// CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, +// TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE +// SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. +// +// +// Represents an item in a CategorizedSeries. +// +// -------------------------------------------------------------------------------------------------------------------- +namespace OxyPlot.Series +{ + /// + /// Represents an item in a CategorizedSeries. + /// + public abstract class CategorizedItem + { + /// + /// Initializes a new instance of the class. Initializes a new instance of the class. + /// + protected CategorizedItem() + { + this.CategoryIndex = -1; + } + + /// + /// Gets or sets the index of the category. + /// + /// + /// The index of the category. + /// + public int CategoryIndex { get; set; } + + /// + /// Gets the index of the category. + /// + /// + /// The default index. + /// + /// + /// The index. + /// + internal int GetCategoryIndex(int defaultIndex) + { + if (this.CategoryIndex < 0) + { + return defaultIndex; + } + + return this.CategoryIndex; + } + + } +} \ No newline at end of file diff -r 88d699a65cc2 -r 5be8f2773237 External/OxyPlot/OxyPlot/Series/BarSeries/CategorizedSeries.cs --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/External/OxyPlot/OxyPlot/Series/BarSeries/CategorizedSeries.cs Sat Jun 08 16:53:22 2013 +0000 @@ -0,0 +1,83 @@ +// -------------------------------------------------------------------------------------------------------------------- +// +// The MIT License (MIT) +// +// Copyright (c) 2012 Oystein Bjorke +// +// Permission is hereby granted, free of charge, to any person obtaining a +// copy of this software and associated documentation files (the +// "Software"), to deal in the Software without restriction, including +// without limitation the rights to use, copy, modify, merge, publish, +// distribute, sublicense, and/or sell copies of the Software, and to +// permit persons to whom the Software is furnished to do so, subject to +// the following conditions: +// +// The above copyright notice and this permission notice shall be included +// in all copies or substantial portions of the Software. +// +// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS +// OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF +// MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. +// IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY +// CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, +// TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE +// SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. +// +// +// Base class for series where the items are categorized. +// +// -------------------------------------------------------------------------------------------------------------------- +namespace OxyPlot.Series +{ + using System.Collections.Generic; + + using OxyPlot.Axes; + + /// + /// Base class for series where the items are categorized. + /// + public abstract class CategorizedSeries : XYAxisSeries + { + /// + /// Gets or sets the width/height of the columns/bars (as a fraction of the available space). + /// + /// + /// The fractional width. + /// + /// + /// The width of the bars. + /// + /// + /// The available space will be determined by the GapWidth of the CategoryAxis used by this series. + /// + internal abstract double GetBarWidth(); + + /// + /// Gets the items of this series. + /// + /// + /// The items. + /// + protected internal abstract IList GetItems(); + + /// + /// Gets the actual bar width/height of the items in this series. + /// + /// + /// The width or height. + /// + /// + /// The actual width is also influenced by the GapWidth of the CategoryAxis used by this series. + /// + protected abstract double GetActualBarWidth(); + + /// + /// Gets the category axis. + /// + /// + /// The category axis. + /// + protected abstract CategoryAxis GetCategoryAxis(); + + } +} \ No newline at end of file diff -r 88d699a65cc2 -r 5be8f2773237 External/OxyPlot/OxyPlot/Series/BarSeries/ColumnItem.cs --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/External/OxyPlot/OxyPlot/Series/BarSeries/ColumnItem.cs Sat Jun 08 16:53:22 2013 +0000 @@ -0,0 +1,64 @@ +// -------------------------------------------------------------------------------------------------------------------- +// +// The MIT License (MIT) +// +// Copyright (c) 2012 Oystein Bjorke +// +// Permission is hereby granted, free of charge, to any person obtaining a +// copy of this software and associated documentation files (the +// "Software"), to deal in the Software without restriction, including +// without limitation the rights to use, copy, modify, merge, publish, +// distribute, sublicense, and/or sell copies of the Software, and to +// permit persons to whom the Software is furnished to do so, subject to +// the following conditions: +// +// The above copyright notice and this permission notice shall be included +// in all copies or substantial portions of the Software. +// +// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS +// OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF +// MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. +// IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY +// CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, +// TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE +// SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. +// +// +// Represents an item used in the ColumnSeries. +// +// -------------------------------------------------------------------------------------------------------------------- +namespace OxyPlot.Series +{ + /// + /// Represents an item used in the ColumnSeries. + /// + public class ColumnItem : BarItemBase + { + /// + /// Initializes a new instance of the class. + /// + public ColumnItem() + { + } + + /// + /// Initializes a new instance of the class. + /// + /// + /// The value. + /// + /// + /// Index of the category. + /// + /// + /// The color. + /// + public ColumnItem(double value, int categoryIndex = -1, OxyColor color = null) + { + this.Value = value; + this.CategoryIndex = categoryIndex; + this.Color = color; + } + + } +} \ No newline at end of file diff -r 88d699a65cc2 -r 5be8f2773237 External/OxyPlot/OxyPlot/Series/BarSeries/ColumnSeries.cs --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/External/OxyPlot/OxyPlot/Series/BarSeries/ColumnSeries.cs Sat Jun 08 16:53:22 2013 +0000 @@ -0,0 +1,198 @@ +// -------------------------------------------------------------------------------------------------------------------- +// +// The MIT License (MIT) +// +// Copyright (c) 2012 Oystein Bjorke +// +// Permission is hereby granted, free of charge, to any person obtaining a +// copy of this software and associated documentation files (the +// "Software"), to deal in the Software without restriction, including +// without limitation the rights to use, copy, modify, merge, publish, +// distribute, sublicense, and/or sell copies of the Software, and to +// permit persons to whom the Software is furnished to do so, subject to +// the following conditions: +// +// The above copyright notice and this permission notice shall be included +// in all copies or substantial portions of the Software. +// +// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS +// OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF +// MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. +// IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY +// CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, +// TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE +// SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. +// +// +// Represents a series for clustered or stacked column charts. +// +// -------------------------------------------------------------------------------------------------------------------- +namespace OxyPlot.Series +{ + using System; + + using OxyPlot.Axes; + + /// + /// Represents a series for clustered or stacked column charts. + /// + public class ColumnSeries : BarSeriesBase + { + /// + /// Initializes a new instance of the class. + /// + public ColumnSeries() + { + this.ColumnWidth = 1; + } + + /// + /// Gets or sets the width of the column. + /// + /// + /// The width of the column. + /// + public double ColumnWidth { get; set; } + + /// + /// Gets or sets the width/height of the columns/bars (as a fraction of the available space). + /// + /// + /// The fractional width. + /// + /// + /// The width of the bars. + /// + /// + /// The available space will be determined by the GapWidth of the CategoryAxis used by this series. + /// + internal override double GetBarWidth() + { + return this.ColumnWidth; + } + + /// + /// Gets the actual width/height of the items of this series. + /// + /// + /// The width or height. + /// + /// + /// The actual width is also influenced by the GapWidth of the CategoryAxis used by this series. + /// + protected override double GetActualBarWidth() + { + var categoryAxis = this.GetCategoryAxis(); + return this.ColumnWidth / (1 + categoryAxis.GapWidth) / categoryAxis.MaxWidth; + } + + /// + /// Gets the category axis. + /// + /// + /// The category axis. + /// + protected override CategoryAxis GetCategoryAxis() + { + if (!(this.XAxis is CategoryAxis)) + { + throw new Exception( + "A ColumnSeries requires a CategoryAxis on the x-axis. Use a BarSeries if you want horizontal bars."); + } + + return this.XAxis as CategoryAxis; + } + + /// + /// Gets the rectangle for the specified values. + /// + /// + /// The base value of the bar + /// + /// + /// The top value of the bar + /// + /// + /// The begin value of the bar + /// + /// + /// The end value of the bar + /// + /// + /// The rectangle. + /// + protected override OxyRect GetRectangle(double baseValue, double topValue, double beginValue, double endValue) + { + return OxyRect.Create(this.Transform(beginValue, baseValue), this.Transform(endValue, topValue)); + } + + /// + /// Gets the value axis. + /// + /// + /// The value axis. + /// + protected override Axis GetValueAxis() + { + return this.YAxis; + } + + /// + /// Draws the label. + /// + /// + /// The render context. + /// + /// + /// The clipping rect. + /// + /// + /// The rect. + /// + /// + /// The value. + /// + /// + /// The i. + /// + protected override void RenderLabel(IRenderContext rc, OxyRect clippingRect, OxyRect rect, double value, int i) + { + var s = StringHelper.Format( + this.ActualCulture, this.LabelFormatString, this.GetItem(this.ValidItemsIndexInversion[i]), value); + ScreenPoint pt; + VerticalAlignment va; + switch (this.LabelPlacement) + { + case LabelPlacement.Inside: + pt = new ScreenPoint((rect.Left + rect.Right) / 2, rect.Top + this.LabelMargin); + va = VerticalAlignment.Top; + break; + case LabelPlacement.Middle: + pt = new ScreenPoint((rect.Left + rect.Right) / 2, (rect.Bottom + rect.Top) / 2); + va = VerticalAlignment.Middle; + break; + case LabelPlacement.Base: + pt = new ScreenPoint((rect.Left + rect.Right) / 2, rect.Bottom - this.LabelMargin); + va = VerticalAlignment.Bottom; + break; + default: // outside + pt = new ScreenPoint((rect.Left + rect.Right) / 2, rect.Top - this.LabelMargin); + va = VerticalAlignment.Bottom; + break; + } + + rc.DrawClippedText( + clippingRect, + pt, + s, + this.ActualTextColor, + this.ActualFont, + this.ActualFontSize, + this.ActualFontWeight, + 0, + HorizontalAlignment.Center, + va); + } + + } +} \ No newline at end of file diff -r 88d699a65cc2 -r 5be8f2773237 External/OxyPlot/OxyPlot/Series/BarSeries/ErrorColumnItem.cs --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/External/OxyPlot/OxyPlot/Series/BarSeries/ErrorColumnItem.cs Sat Jun 08 16:53:22 2013 +0000 @@ -0,0 +1,96 @@ +// -------------------------------------------------------------------------------------------------------------------- +// +// The MIT License (MIT) +// +// Copyright (c) 2012 Oystein Bjorke +// +// Permission is hereby granted, free of charge, to any person obtaining a +// copy of this software and associated documentation files (the +// "Software"), to deal in the Software without restriction, including +// without limitation the rights to use, copy, modify, merge, publish, +// distribute, sublicense, and/or sell copies of the Software, and to +// permit persons to whom the Software is furnished to do so, subject to +// the following conditions: +// +// The above copyright notice and this permission notice shall be included +// in all copies or substantial portions of the Software. +// +// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS +// OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF +// MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. +// IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY +// CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, +// TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE +// SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. +// +// +// Represents an item used in the ErrorColumnSeries. +// +// -------------------------------------------------------------------------------------------------------------------- +namespace OxyPlot.Series +{ + /// + /// Represents an item used in the ErrorColumnSeries. + /// + public class ErrorColumnItem : ColumnItem + { + /// + /// Initializes a new instance of the class. + /// + public ErrorColumnItem() + { + } + + /// + /// Initializes a new instance of the class. + /// + /// + /// The value. + /// + /// + /// The error. + /// + /// + /// Index of the category. + /// + /// + /// The color. + /// + public ErrorColumnItem(double value, double error, int categoryIndex = -1, OxyColor color = null) + { + this.Value = value; + this.Error = error; + this.CategoryIndex = categoryIndex; + this.Color = color; + } + + /// + /// Gets or sets the error of the item. + /// + public double Error { get; set; } + + /// + /// Returns c# code that generates this instance. + /// + /// + /// C# code. + /// + public override string ToCode() + { + if (this.Color != null) + { + return CodeGenerator.FormatConstructor( + this.GetType(), "{0},{1},{2},{3}", this.Value, this.Error, this.CategoryIndex, this.Color.ToCode()); + } + + if (this.CategoryIndex != -1) + { + return CodeGenerator.FormatConstructor( + this.GetType(), "{0},{1},{2}", this.Value, this.Error, this.CategoryIndex); + } + + return CodeGenerator.FormatConstructor(this.GetType(), "{0},{1}", this.Value, this.Error); + } + + } +} \ No newline at end of file diff -r 88d699a65cc2 -r 5be8f2773237 External/OxyPlot/OxyPlot/Series/BarSeries/ErrorColumnSeries.cs --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/External/OxyPlot/OxyPlot/Series/BarSeries/ErrorColumnSeries.cs Sat Jun 08 16:53:22 2013 +0000 @@ -0,0 +1,240 @@ +// -------------------------------------------------------------------------------------------------------------------- +// +// The MIT License (MIT) +// +// Copyright (c) 2012 Oystein Bjorke +// +// Permission is hereby granted, free of charge, to any person obtaining a +// copy of this software and associated documentation files (the +// "Software"), to deal in the Software without restriction, including +// without limitation the rights to use, copy, modify, merge, publish, +// distribute, sublicense, and/or sell copies of the Software, and to +// permit persons to whom the Software is furnished to do so, subject to +// the following conditions: +// +// The above copyright notice and this permission notice shall be included +// in all copies or substantial portions of the Software. +// +// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS +// OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF +// MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. +// IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY +// CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, +// TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE +// SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. +// +// +// Represents a series for clustered or stacked column charts with an error value. +// +// -------------------------------------------------------------------------------------------------------------------- +namespace OxyPlot.Series +{ + using System; + using System.Collections.Generic; + using System.Linq; + + /// + /// Represents a series for clustered or stacked column charts with an error value. + /// + public class ErrorColumnSeries : ColumnSeries + { + /// + /// Initializes a new instance of the class. + /// + public ErrorColumnSeries() + { + this.ErrorWidth = 0.4; + this.ErrorStrokeThickness = 1; + this.TrackerFormatString = "{0}, {1}: {2}, Error: {Error}"; + } + + /// + /// Gets or sets the stroke thickness of the error line. + /// + /// + /// The stroke thickness of the error line. + /// + public double ErrorStrokeThickness { get; set; } + + /// + /// Gets or sets the width of the error end lines. + /// + /// + /// The width of the error end lines. + /// + public double ErrorWidth { get; set; } + + /// + /// Updates the maximum/minimum value on the value axis from the bar values. + /// + protected internal override void UpdateMaxMin() + { + base.UpdateMaxMin(); + + //// Todo: refactor (lots of duplicate code here) + if (this.ValidItems == null || this.ValidItems.Count == 0) + { + return; + } + + var categoryAxis = this.GetCategoryAxis(); + + double minValue = double.MaxValue, maxValue = double.MinValue; + if (this.IsStacked) + { + var labels = this.GetCategoryAxis().Labels; + for (var i = 0; i < labels.Count; i++) + { + int j = 0; + var items = this.ValidItems.Where(item => item.GetCategoryIndex(j++) == i).ToList(); + var values = items.Select(item => item.Value).Concat(new[] { 0d }).ToList(); + var minTemp = values.Where(v => v <= 0).Sum(); + var maxTemp = values.Where(v => v >= 0).Sum() + ((ErrorColumnItem)items.Last()).Error; + + int stackIndex = categoryAxis.StackIndexMapping[this.StackGroup]; + var stackedMinValue = categoryAxis.MinValue[stackIndex, i]; + if (!double.IsNaN(stackedMinValue)) + { + minTemp += stackedMinValue; + } + + categoryAxis.MinValue[stackIndex, i] = minTemp; + + var stackedMaxValue = categoryAxis.MaxValue[stackIndex, i]; + if (!double.IsNaN(stackedMaxValue)) + { + maxTemp += stackedMaxValue; + } + + categoryAxis.MaxValue[stackIndex, i] = maxTemp; + + minValue = Math.Min(minValue, minTemp + this.BaseValue); + maxValue = Math.Max(maxValue, maxTemp + this.BaseValue); + } + } + else + { + var valuesMin = + this.ValidItems.Select(item => item.Value - ((ErrorColumnItem)item).Error).Concat(new[] { 0d }). + ToList(); + var valuesMax = + this.ValidItems.Select(item => item.Value + ((ErrorColumnItem)item).Error).Concat(new[] { 0d }). + ToList(); + minValue = valuesMin.Min(); + maxValue = valuesMax.Max(); + if (this.BaseValue < minValue) + { + minValue = this.BaseValue; + } + + if (this.BaseValue > maxValue) + { + maxValue = this.BaseValue; + } + } + + var valueAxis = this.GetValueAxis(); + if (valueAxis.IsVertical()) + { + this.MinY = minValue; + this.MaxY = maxValue; + } + else + { + this.MinX = minValue; + this.MaxX = maxValue; + } + } + + /// + /// Renders the bar/column item. + /// + /// + /// The render context. + /// + /// + /// The clipping rectangle. + /// + /// + /// The end value of the bar. + /// + /// + /// The category value. + /// + /// + /// The actual width of the bar. + /// + /// + /// The item. + /// + /// + /// The rectangle of the bar. + /// + protected override void RenderItem( + IRenderContext rc, + OxyRect clippingRect, + double topValue, + double categoryValue, + double actualBarWidth, + BarItemBase item, + OxyRect rect) + { + base.RenderItem(rc, clippingRect, topValue, categoryValue, actualBarWidth, item, rect); + + var errorItem = item as ErrorColumnItem; + if (errorItem == null) + { + return; + } + + // Render the error + var lowerValue = topValue - errorItem.Error; + var upperValue = topValue + errorItem.Error; + var left = 0.5 - this.ErrorWidth / 2; + var right = 0.5 + this.ErrorWidth / 2; + var leftValue = categoryValue + (left * actualBarWidth); + var middleValue = categoryValue + (0.5 * actualBarWidth); + var rightValue = categoryValue + (right * actualBarWidth); + + var lowerErrorPoint = this.Transform(middleValue, lowerValue); + var upperErrorPoint = this.Transform(middleValue, upperValue); + rc.DrawClippedLine( + new List { lowerErrorPoint, upperErrorPoint }, + clippingRect, + 0, + this.StrokeColor, + this.ErrorStrokeThickness, + LineStyle.Solid, + OxyPenLineJoin.Miter, + true); + + if (this.ErrorWidth > 0) + { + var lowerLeftErrorPoint = this.Transform(leftValue, lowerValue); + var lowerRightErrorPoint = this.Transform(rightValue, lowerValue); + rc.DrawClippedLine( + new List { lowerLeftErrorPoint, lowerRightErrorPoint }, + clippingRect, + 0, + this.StrokeColor, + this.ErrorStrokeThickness, + LineStyle.Solid, + OxyPenLineJoin.Miter, + true); + + var upperLeftErrorPoint = this.Transform(leftValue, upperValue); + var upperRightErrorPoint = this.Transform(rightValue, upperValue); + rc.DrawClippedLine( + new List { upperLeftErrorPoint, upperRightErrorPoint }, + clippingRect, + 0, + this.StrokeColor, + this.ErrorStrokeThickness, + LineStyle.Solid, + OxyPenLineJoin.Miter, + true); + } + } + + } +} \ No newline at end of file diff -r 88d699a65cc2 -r 5be8f2773237 External/OxyPlot/OxyPlot/Series/BarSeries/IStackableSeries.cs --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/External/OxyPlot/OxyPlot/Series/BarSeries/IStackableSeries.cs Sat Jun 08 16:53:22 2013 +0000 @@ -0,0 +1,50 @@ +// -------------------------------------------------------------------------------------------------------------------- +// +// The MIT License (MIT) +// +// Copyright (c) 2012 Oystein Bjorke +// +// Permission is hereby granted, free of charge, to any person obtaining a +// copy of this software and associated documentation files (the +// "Software"), to deal in the Software without restriction, including +// without limitation the rights to use, copy, modify, merge, publish, +// distribute, sublicense, and/or sell copies of the Software, and to +// permit persons to whom the Software is furnished to do so, subject to +// the following conditions: +// +// The above copyright notice and this permission notice shall be included +// in all copies or substantial portions of the Software. +// +// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS +// OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF +// MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. +// IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY +// CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, +// TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE +// SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. +// +// +// Specifies a series that can be stacked. +// +// -------------------------------------------------------------------------------------------------------------------- +namespace OxyPlot.Series +{ + /// + /// Defines properties for stacked series. + /// + public interface IStackableSeries + { + /// + /// Gets a value indicating whether this series is stacked. + /// + bool IsStacked { get; } + + /// + /// Gets the stack group. + /// + /// + /// The stack group. + /// + string StackGroup { get; } + } +} \ No newline at end of file diff -r 88d699a65cc2 -r 5be8f2773237 External/OxyPlot/OxyPlot/Series/BarSeries/IntervalBarItem.cs --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/External/OxyPlot/OxyPlot/Series/BarSeries/IntervalBarItem.cs Sat Jun 08 16:53:22 2013 +0000 @@ -0,0 +1,110 @@ +// -------------------------------------------------------------------------------------------------------------------- +// +// The MIT License (MIT) +// +// Copyright (c) 2012 Oystein Bjorke +// +// Permission is hereby granted, free of charge, to any person obtaining a +// copy of this software and associated documentation files (the +// "Software"), to deal in the Software without restriction, including +// without limitation the rights to use, copy, modify, merge, publish, +// distribute, sublicense, and/or sell copies of the Software, and to +// permit persons to whom the Software is furnished to do so, subject to +// the following conditions: +// +// The above copyright notice and this permission notice shall be included +// in all copies or substantial portions of the Software. +// +// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS +// OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF +// MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. +// IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY +// CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, +// TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE +// SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. +// +// +// Represents an item in an IntervalBarSeries. +// +// -------------------------------------------------------------------------------------------------------------------- +namespace OxyPlot.Series +{ + /// + /// Represents an item in an IntervalBarSeries. + /// + public class IntervalBarItem : CategorizedItem, ICodeGenerating + { + /// + /// Initializes a new instance of the class. + /// + public IntervalBarItem() + { + } + + /// + /// Initializes a new instance of the class. + /// + /// + /// The start. + /// + /// + /// The end. + /// + /// + /// The title. + /// + /// + /// The color. + /// + public IntervalBarItem(double start, double end, string title = null, OxyColor color = null) + { + this.Start = start; + this.End = end; + this.Title = title; + this.Color = color; + } + + /// + /// Gets or sets the color. + /// + public OxyColor Color { get; set; } + + /// + /// Gets or sets the end value. + /// + public double End { get; set; } + + /// + /// Gets or sets the start value. + /// + public double Start { get; set; } + + /// + /// Gets or sets the title. + /// + public string Title { get; set; } + + /// + /// Returns c# code that generates this instance. + /// + /// + /// C# code. + /// + public string ToCode() + { + if (this.Color != null) + { + return CodeGenerator.FormatConstructor( + this.GetType(), "{0},{1},{2},{3}", this.Start, this.End, this.Title, this.Color.ToCode()); + } + + if (this.Title != null) + { + return CodeGenerator.FormatConstructor(this.GetType(), "{0},{1},{2}", this.Start, this.End, this.Title); + } + + return CodeGenerator.FormatConstructor(this.GetType(), "{0},{1}", this.Start, this.End); + } + + } +} \ No newline at end of file diff -r 88d699a65cc2 -r 5be8f2773237 External/OxyPlot/OxyPlot/Series/BarSeries/IntervalBarSeries.cs --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/External/OxyPlot/OxyPlot/Series/BarSeries/IntervalBarSeries.cs Sat Jun 08 16:53:22 2013 +0000 @@ -0,0 +1,515 @@ +// -------------------------------------------------------------------------------------------------------------------- +// +// The MIT License (MIT) +// +// Copyright (c) 2012 Oystein Bjorke +// +// Permission is hereby granted, free of charge, to any person obtaining a +// copy of this software and associated documentation files (the +// "Software"), to deal in the Software without restriction, including +// without limitation the rights to use, copy, modify, merge, publish, +// distribute, sublicense, and/or sell copies of the Software, and to +// permit persons to whom the Software is furnished to do so, subject to +// the following conditions: +// +// The above copyright notice and this permission notice shall be included +// in all copies or substantial portions of the Software. +// +// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS +// OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF +// MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. +// IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY +// CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, +// TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE +// SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. +// +// +// Represents a series for bar charts defined by to/from values. +// +// -------------------------------------------------------------------------------------------------------------------- +namespace OxyPlot.Series +{ + using System; + using System.Collections.Generic; + using System.Linq; + + using OxyPlot.Axes; + + /// + /// Represents a series for bar charts defined by to/from values. + /// + public class IntervalBarSeries : CategorizedSeries, IStackableSeries + { + /// + /// The default fill color. + /// + private OxyColor defaultFillColor; + + /// + /// Initializes a new instance of the class. + /// + public IntervalBarSeries() + { + this.Items = new List(); + + this.StrokeColor = OxyColors.Black; + this.StrokeThickness = 1; + this.BarWidth = 1; + + this.TrackerFormatString = "{0}"; + this.LabelMargin = 4; + + this.LabelFormatString = "{2}"; // title + + // this.LabelFormatString = "{0}-{1}"; // Minimum-Maximum + } + + /// + /// Gets or sets the width of the bars (as a fraction of the available width). The default value is 0.5 (50%) + /// + /// + /// The width of the bars. + /// + public double BarWidth { get; set; } + + /// + /// Gets or sets the default color of the interior of the Maximum bars. + /// + /// + /// The color. + /// + public OxyColor FillColor { get; set; } + + /// + /// Gets the actual fill color. + /// + /// The actual color. + public OxyColor ActualFillColor + { + get { return this.FillColor ?? this.defaultFillColor; } + } + + /// + /// Gets a value indicating whether IsStacked. + /// + public bool IsStacked + { + get + { + return true; + } + } + + /// + /// Gets the range bar items. + /// + public IList Items { get; private set; } + + /// + /// Gets or sets the label color. + /// + public OxyColor LabelColor { get; set; } + + /// + /// Gets or sets the label field. + /// + public string LabelField { get; set; } + + /// + /// Gets or sets the format string for the maximum labels. + /// + public string LabelFormatString { get; set; } + + /// + /// Gets or sets the label margins. + /// + public double LabelMargin { get; set; } + + /// + /// Gets or sets the maximum value field. + /// + public string MaximumField { get; set; } + + /// + /// Gets or sets the minimum value field. + /// + public string MinimumField { get; set; } + + /// + /// Gets StackGroup. + /// + public string StackGroup + { + get + { + return string.Empty; + } + } + + /// + /// Gets or sets the color of the border around the bars. + /// + /// + /// The color of the stroke. + /// + public OxyColor StrokeColor { get; set; } + + /// + /// Gets or sets the thickness of the bar border strokes. + /// + /// + /// The stroke thickness. + /// + public double StrokeThickness { get; set; } + + /// + /// Gets or sets the actual rectangles for the maximum bars. + /// + protected internal IList ActualBarRectangles { get; set; } + + /// + /// Gets or sets the valid items + /// + protected internal IList ValidItems { get; set; } + + /// + /// Gets or sets the dictionary which stores the index-inversion for the valid items + /// + protected internal Dictionary ValidItemsIndexInversion { get; set; } + + /// + /// Gets the point in the dataset that is nearest the specified point. + /// + /// + /// The point. + /// + /// + /// The interpolate. + /// + /// + /// A TrackerHitResult for the current hit. + /// + public override TrackerHitResult GetNearestPoint(ScreenPoint point, bool interpolate) + { + for (int i = 0; i < this.ActualBarRectangles.Count; i++) + { + var r = this.ActualBarRectangles[i]; + if (r.Contains(point)) + { + var item = (IntervalBarItem)this.GetItem(this.ValidItemsIndexInversion[i]); + var categoryIndex = item.GetCategoryIndex(i); + double value = (this.ValidItems[i].Start + this.ValidItems[i].End) / 2; + var dp = new DataPoint(categoryIndex, value); + var text = StringHelper.Format( + this.ActualCulture, + this.TrackerFormatString, + item, + this.Items[i].Start, + this.Items[i].End, + this.Items[i].Title); + return new TrackerHitResult(this, dp, point, item, i, text); + } + } + + return null; + } + + /// + /// Checks if the specified value is valid. + /// + /// + /// The value. + /// + /// + /// The y axis. + /// + /// + /// True if the value is valid. + /// + public virtual bool IsValidPoint(double v, Axis yaxis) + { + return !double.IsNaN(v) && !double.IsInfinity(v); + } + + /// + /// Renders the Series on the specified rendering context. + /// + /// + /// The rendering context. + /// + /// + /// The model. + /// + public override void Render(IRenderContext rc, PlotModel model) + { + this.ActualBarRectangles = new List(); + + if (this.ValidItems.Count == 0) + { + return; + } + + var clippingRect = this.GetClippingRect(); + var categoryAxis = this.GetCategoryAxis(); + + var actualBarWidth = this.GetActualBarWidth(); + var stackIndex = categoryAxis.StackIndexMapping[this.StackGroup]; + + for (var i = 0; i < this.ValidItems.Count; i++) + { + var item = this.ValidItems[i]; + + var categoryIndex = item.GetCategoryIndex(i); + double categoryValue = categoryAxis.GetCategoryValue(categoryIndex, stackIndex, actualBarWidth); + + var p0 = this.Transform(item.Start, categoryValue); + var p1 = this.Transform(item.End, categoryValue + actualBarWidth); + + var rectangle = OxyRect.Create(p0.X, p0.Y, p1.X, p1.Y); + + this.ActualBarRectangles.Add(rectangle); + + rc.DrawClippedRectangleAsPolygon( + rectangle, + clippingRect, + this.GetSelectableFillColor(item.Color ?? this.ActualFillColor), + this.StrokeColor, + this.StrokeThickness); + + if (this.LabelFormatString != null) + { + var s = StringHelper.Format( + this.ActualCulture, this.LabelFormatString, this.GetItem(i), item.Start, item.End, item.Title); + + var pt = new ScreenPoint( + (rectangle.Left + rectangle.Right) / 2, (rectangle.Top + rectangle.Bottom) / 2); + + rc.DrawClippedText( + clippingRect, + pt, + s, + this.ActualTextColor, + this.ActualFont, + this.ActualFontSize, + this.ActualFontWeight, + 0, + HorizontalAlignment.Center, + VerticalAlignment.Middle); + } + } + } + + /// + /// Renders the legend symbol on the specified rendering context. + /// + /// + /// The rendering context. + /// + /// + /// The legend rectangle. + /// + public override void RenderLegend(IRenderContext rc, OxyRect legendBox) + { + double xmid = (legendBox.Left + legendBox.Right) / 2; + double ymid = (legendBox.Top + legendBox.Bottom) / 2; + double height = (legendBox.Bottom - legendBox.Top) * 0.8; + double width = height; + rc.DrawRectangleAsPolygon( + new OxyRect(xmid - (0.5 * width), ymid - (0.5 * height), width, height), + this.GetSelectableFillColor(this.ActualFillColor), + this.StrokeColor, + this.StrokeThickness); + } + + /// + /// Gets or sets the width/height of the columns/bars (as a fraction of the available space). + /// + /// + /// The fractional width. + /// + /// + /// The width of the bars. + /// + /// + /// The available space will be determined by the GapWidth of the CategoryAxis used by this series. + /// + internal override double GetBarWidth() + { + return this.BarWidth; + } + + /// + /// Gets the items of this series. + /// + /// + /// The items. + /// + protected internal override IList GetItems() + { + return this.Items.Cast().ToList(); + } + + /// + /// Check if the data series is using the specified axis. + /// + /// + /// An axis which should be checked if used + /// + /// + /// True if the axis is in use. + /// + protected internal override bool IsUsing(Axis axis) + { + return this.XAxis == axis || this.YAxis == axis; + } + + /// + /// The set default values. + /// + /// + /// The model. + /// + protected internal override void SetDefaultValues(PlotModel model) + { + if (this.FillColor == null) + { + this.defaultFillColor = model.GetDefaultColor(); + } + } + + /// + /// Updates the axis maximum and minimum values. + /// + protected internal override void UpdateAxisMaxMin() + { + this.XAxis.Include(this.MinX); + this.XAxis.Include(this.MaxX); + } + + /// + /// Updates the data. + /// + protected internal override void UpdateData() + { + if (this.ItemsSource != null) + { + this.Items.Clear(); + + var filler = new ListFiller(); + filler.Add(this.MinimumField, (item, value) => item.Start = Convert.ToDouble(value)); + filler.Add(this.MaximumField, (item, value) => item.End = Convert.ToDouble(value)); + filler.FillT(this.Items, this.ItemsSource); + } + } + + /// + /// Updates the maximum/minimum value on the value axis from the bar values. + /// + protected internal override void UpdateMaxMin() + { + base.UpdateMaxMin(); + + if (this.ValidItems == null || this.ValidItems.Count == 0) + { + return; + } + + double minValue = double.MaxValue; + double maxValue = double.MinValue; + + foreach (var item in this.ValidItems) + { + minValue = Math.Min(minValue, item.Start); + minValue = Math.Min(minValue, item.End); + maxValue = Math.Max(maxValue, item.Start); + maxValue = Math.Max(maxValue, item.End); + } + + this.MinX = minValue; + this.MaxX = maxValue; + } + + /// + /// Updates the valid items + /// + protected internal override void UpdateValidData() + { + this.ValidItems = new List(); + this.ValidItemsIndexInversion = new Dictionary(); + var valueAxis = this.GetValueAxis(); + + for (var i = 0; i < this.Items.Count; i++) + { + var item = this.Items[i]; + if (valueAxis.IsValidValue(item.Start) && valueAxis.IsValidValue(item.End)) + { + this.ValidItemsIndexInversion.Add(this.ValidItems.Count, i); + this.ValidItems.Add(item); + } + } + } + + /// + /// Gets the actual width/height of the items of this series. + /// + /// + /// The width or height. + /// + /// + /// The actual width is also influenced by the GapWidth of the CategoryAxis used by this series. + /// + protected override double GetActualBarWidth() + { + var categoryAxis = this.GetCategoryAxis(); + return this.BarWidth / (1 + categoryAxis.GapWidth) / categoryAxis.MaxWidth; + } + + /// + /// Gets the category axis. + /// + /// + /// The category axis. + /// + protected override CategoryAxis GetCategoryAxis() + { + var categoryAxis = this.YAxis as CategoryAxis; + if (categoryAxis == null) + { + throw new InvalidOperationException("No category axis defined."); + } + + return categoryAxis; + } + + /// + /// Gets the item at the specified index. + /// + /// + /// The index of the item. + /// + /// + /// The item of the index. + /// + protected override object GetItem(int i) + { + if (this.ItemsSource != null || this.Items == null || this.Items.Count == 0) + { + return base.GetItem(i); + } + + return this.Items[i]; + } + + /// + /// Gets the value axis. + /// + /// + /// The value axis. + /// + private Axis GetValueAxis() + { + return this.XAxis; + } + + } +} \ No newline at end of file diff -r 88d699a65cc2 -r 5be8f2773237 External/OxyPlot/OxyPlot/Series/BarSeries/LabelPlacement.cs --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/External/OxyPlot/OxyPlot/Series/BarSeries/LabelPlacement.cs Sat Jun 08 16:53:22 2013 +0000 @@ -0,0 +1,57 @@ +// -------------------------------------------------------------------------------------------------------------------- +// +// The MIT License (MIT) +// +// Copyright (c) 2012 Oystein Bjorke +// +// Permission is hereby granted, free of charge, to any person obtaining a +// copy of this software and associated documentation files (the +// "Software"), to deal in the Software without restriction, including +// without limitation the rights to use, copy, modify, merge, publish, +// distribute, sublicense, and/or sell copies of the Software, and to +// permit persons to whom the Software is furnished to do so, subject to +// the following conditions: +// +// The above copyright notice and this permission notice shall be included +// in all copies or substantial portions of the Software. +// +// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS +// OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF +// MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. +// IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY +// CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, +// TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE +// SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. +// +// +// Placement of the labels. +// +// -------------------------------------------------------------------------------------------------------------------- +namespace OxyPlot.Series +{ + /// + /// Placement of the labels. + /// + public enum LabelPlacement + { + /// + /// Placed outside the bar. + /// + Outside, + + /// + /// Placed inside the bar. + /// + Inside, + + /// + /// Placed inside in the middle/center of the bar. + /// + Middle, + + /// + /// Placed inside at the base of the bar. + /// + Base + } +} \ No newline at end of file diff -r 88d699a65cc2 -r 5be8f2773237 External/OxyPlot/OxyPlot/Series/BarSeries/RectangleBarItem.cs --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/External/OxyPlot/OxyPlot/Series/BarSeries/RectangleBarItem.cs Sat Jun 08 16:53:22 2013 +0000 @@ -0,0 +1,137 @@ +// -------------------------------------------------------------------------------------------------------------------- +// +// The MIT License (MIT) +// +// Copyright (c) 2012 Oystein Bjorke +// +// Permission is hereby granted, free of charge, to any person obtaining a +// copy of this software and associated documentation files (the +// "Software"), to deal in the Software without restriction, including +// without limitation the rights to use, copy, modify, merge, publish, +// distribute, sublicense, and/or sell copies of the Software, and to +// permit persons to whom the Software is furnished to do so, subject to +// the following conditions: +// +// The above copyright notice and this permission notice shall be included +// in all copies or substantial portions of the Software. +// +// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS +// OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF +// MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. +// IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY +// CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, +// TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE +// SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. +// +// +// Represents a rectangle item in a RectangleBarSeries. +// +// -------------------------------------------------------------------------------------------------------------------- +namespace OxyPlot.Series +{ + /// + /// Represents a rectangle item in a RectangleBarSeries. + /// + public class RectangleBarItem : ICodeGenerating + { + /// + /// Initializes a new instance of the class. + /// + public RectangleBarItem() + { + } + + /// + /// Initializes a new instance of the class. + /// + /// + /// The x0. + /// + /// + /// The y0. + /// + /// + /// The x1. + /// + /// + /// The y1. + /// + /// + /// The title. + /// + /// + /// The color. + /// + public RectangleBarItem(double x0, double y0, double x1, double y1, string title = null, OxyColor color = null) + { + this.X0 = x0; + this.Y0 = y0; + this.X1 = x1; + this.Y1 = y1; + this.Title = title; + this.Color = color; + } + + /// + /// Gets or sets the color. + /// + public OxyColor Color { get; set; } + + /// + /// Gets or sets the title. + /// + public string Title { get; set; } + + /// + /// Gets or sets the x0 coordinate. + /// + public double X0 { get; set; } + + /// + /// Gets or sets the x1 coordinate. + /// + public double X1 { get; set; } + + /// + /// Gets or sets the y0 coordinate. + /// + public double Y0 { get; set; } + + /// + /// Gets or sets the y1 coordinate. + /// + public double Y1 { get; set; } + + /// + /// Returns c# code that generates this instance. + /// + /// + /// C# code. + /// + public string ToCode() + { + if (this.Color != null) + { + return CodeGenerator.FormatConstructor( + this.GetType(), + "{0},{1},{2},{3},{4},{5}", + this.X0, + this.Y0, + this.X1, + this.Y1, + this.Title, + this.Color.ToCode()); + } + + if (this.Title != null) + { + return CodeGenerator.FormatConstructor( + this.GetType(), "{0},{1},{2},{3},{4}", this.X0, this.Y0, this.X1, this.Y1, this.Title); + } + + return CodeGenerator.FormatConstructor( + this.GetType(), "{0},{1},{2},{3}", this.X0, this.Y0, this.X1, this.Y1); + } + + } +} \ No newline at end of file diff -r 88d699a65cc2 -r 5be8f2773237 External/OxyPlot/OxyPlot/Series/BarSeries/RectangleBarSeries.cs --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/External/OxyPlot/OxyPlot/Series/BarSeries/RectangleBarSeries.cs Sat Jun 08 16:53:22 2013 +0000 @@ -0,0 +1,337 @@ +// -------------------------------------------------------------------------------------------------------------------- +// +// The MIT License (MIT) +// +// Copyright (c) 2012 Oystein Bjorke +// +// Permission is hereby granted, free of charge, to any person obtaining a +// copy of this software and associated documentation files (the +// "Software"), to deal in the Software without restriction, including +// without limitation the rights to use, copy, modify, merge, publish, +// distribute, sublicense, and/or sell copies of the Software, and to +// permit persons to whom the Software is furnished to do so, subject to +// the following conditions: +// +// The above copyright notice and this permission notice shall be included +// in all copies or substantial portions of the Software. +// +// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS +// OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF +// MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. +// IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY +// CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, +// TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE +// SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. +// +// +// Represents a series for bar charts where the bars are defined by rectangles. +// +// -------------------------------------------------------------------------------------------------------------------- +namespace OxyPlot.Series +{ + using System; + using System.Collections.Generic; + + /// + /// Represents a series for bar charts where the bars are defined by rectangles. + /// + public class RectangleBarSeries : XYAxisSeries + { + /// + /// The default fill color. + /// + private OxyColor defaultFillColor; + + /// + /// Initializes a new instance of the class. + /// + public RectangleBarSeries() + { + this.Items = new List(); + + this.StrokeColor = OxyColors.Black; + this.StrokeThickness = 1; + + this.TrackerFormatString = "{0}"; + + this.LabelFormatString = "{4}"; // title + + // this.LabelFormatString = "{0}-{1},{2}-{3}"; // X0-X1,Y0-Y1 + } + + /// + /// Gets or sets the default color of the interior of the rectangles. + /// + /// + /// The color. + /// + public OxyColor FillColor { get; set; } + + /// + /// Gets the actual fill color. + /// + /// The actual color. + public OxyColor ActualFillColor + { + get { return this.FillColor ?? this.defaultFillColor; } + } + + /// + /// Gets the rectangle bar items. + /// + public IList Items { get; private set; } + + /// + /// Gets or sets the label color. + /// + public OxyColor LabelColor { get; set; } + + /// + /// Gets or sets the format string for the labels. + /// + public string LabelFormatString { get; set; } + + /// + /// Gets or sets the color of the border around the rectangles. + /// + /// + /// The color of the stroke. + /// + public OxyColor StrokeColor { get; set; } + + /// + /// Gets or sets the thickness of the border around the rectangles. + /// + /// + /// The stroke thickness. + /// + public double StrokeThickness { get; set; } + + /// + /// Gets or sets the actual rectangles for the rectangles. + /// + internal IList ActualBarRectangles { get; set; } + + /// + /// Gets the point in the dataset that is nearest the specified point. + /// + /// + /// The point. + /// + /// + /// Specifies whether to interpolate or not. + /// + /// + /// A for the current hit. + /// + public override TrackerHitResult GetNearestPoint(ScreenPoint point, bool interpolate) + { + if (this.ActualBarRectangles == null) + { + return null; + } + + for (int i = 0; i < this.ActualBarRectangles.Count; i++) + { + var r = this.ActualBarRectangles[i]; + if (r.Contains(point)) + { + double value = (this.Items[i].Y0 + this.Items[i].Y1) / 2; + var sp = point; + var dp = new DataPoint(i, value); + var item = this.GetItem(i); + var text = StringHelper.Format( + this.ActualCulture, + this.TrackerFormatString, + item, + this.Items[i].X0, + this.Items[i].X1, + this.Items[i].Y0, + this.Items[i].Y1, + this.Items[i].Title); + return new TrackerHitResult(this, dp, sp, item, i, text); + } + } + + return null; + } + + /// + /// Checks if the specified value is valid. + /// + /// + /// The value. + /// + /// + /// True if the value is valid. + /// + protected virtual bool IsValid(double v) + { + return !double.IsNaN(v) && !double.IsInfinity(v); + } + + /// + /// Renders the Series on the specified rendering context. + /// + /// + /// The rendering context. + /// + /// + /// The model. + /// + public override void Render(IRenderContext rc, PlotModel model) + { + if (this.Items.Count == 0) + { + return; + } + + var clippingRect = this.GetClippingRect(); + + int i = 0; + + this.ActualBarRectangles = new List(); + + foreach (var item in this.Items) + { + if (!this.IsValid(item.X0) || !this.IsValid(item.X1) + || !this.IsValid(item.Y0) || !this.IsValid(item.Y1)) + { + continue; + } + + var p0 = this.Transform(item.X0, item.Y0); + var p1 = this.Transform(item.X1, item.Y1); + + var rectangle = OxyRect.Create(p0.X, p0.Y, p1.X, p1.Y); + + this.ActualBarRectangles.Add(rectangle); + + rc.DrawClippedRectangleAsPolygon( + rectangle, + clippingRect, + this.GetSelectableFillColor(item.Color ?? this.ActualFillColor), + this.StrokeColor, + this.StrokeThickness); + + if (this.LabelFormatString != null) + { + var s = StringHelper.Format( + this.ActualCulture, + this.LabelFormatString, + this.GetItem(i), + item.X0, + item.X1, + item.Y0, + item.Y1, + item.Title); + + var pt = new ScreenPoint( + (rectangle.Left + rectangle.Right) / 2, (rectangle.Top + rectangle.Bottom) / 2); + + rc.DrawClippedText( + clippingRect, + pt, + s, + this.ActualTextColor, + this.ActualFont, + this.ActualFontSize, + this.ActualFontWeight, + 0, + HorizontalAlignment.Center, + VerticalAlignment.Middle); + } + + i++; + } + } + + /// + /// Renders the legend symbol on the specified rendering context. + /// + /// + /// The rendering context. + /// + /// + /// The legend rectangle. + /// + public override void RenderLegend(IRenderContext rc, OxyRect legendBox) + { + double xmid = (legendBox.Left + legendBox.Right) / 2; + double ymid = (legendBox.Top + legendBox.Bottom) / 2; + double height = (legendBox.Bottom - legendBox.Top) * 0.8; + double width = height; + rc.DrawRectangleAsPolygon( + new OxyRect(xmid - (0.5 * width), ymid - (0.5 * height), width, height), + this.GetSelectableFillColor(this.ActualFillColor), + this.StrokeColor, + this.StrokeThickness); + } + + /// + /// Sets the default values. + /// + /// + /// The model. + /// + protected internal override void SetDefaultValues(PlotModel model) + { + if (this.FillColor == null) + { + this.defaultFillColor = model.GetDefaultColor(); + } + } + + /// + /// Updates the data. + /// + protected internal override void UpdateData() + { + if (this.ItemsSource == null) + { + return; + } + + this.Items.Clear(); + + // ReflectionHelper.FillList( + // this.ItemsSource, + // this.Items, + // new[] { this.MinimumField, this.MaximumField }, + // (item, value) => item.Minimum = Convert.ToDouble(value), + // (item, value) => item.Maximum = Convert.ToDouble(value)); + throw new NotImplementedException(); + } + + /// + /// Updates the maximum/minimum value on the value axis from the bar values. + /// + protected internal override void UpdateMaxMin() + { + base.UpdateMaxMin(); + + if (this.Items == null || this.Items.Count == 0) + { + return; + } + + double minValueX = double.MaxValue; + double maxValueX = double.MinValue; + double minValueY = double.MaxValue; + double maxValueY = double.MinValue; + + foreach (var item in this.Items) + { + minValueX = Math.Min(minValueX, Math.Min(item.X0, item.X1)); + maxValueX = Math.Max(maxValueX, Math.Max(item.X1, item.X0)); + minValueY = Math.Min(minValueY, Math.Min(item.Y0, item.Y1)); + maxValueY = Math.Max(maxValueY, Math.Max(item.Y0, item.Y1)); + } + + this.MinX = minValueX; + this.MaxX = maxValueX; + this.MinY = minValueY; + this.MaxY = maxValueY; + } + } +} \ No newline at end of file diff -r 88d699a65cc2 -r 5be8f2773237 External/OxyPlot/OxyPlot/Series/BarSeries/TornadoBarItem.cs --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/External/OxyPlot/OxyPlot/Series/BarSeries/TornadoBarItem.cs Sat Jun 08 16:53:22 2013 +0000 @@ -0,0 +1,147 @@ +// -------------------------------------------------------------------------------------------------------------------- +// +// The MIT License (MIT) +// +// Copyright (c) 2012 Oystein Bjorke +// +// Permission is hereby granted, free of charge, to any person obtaining a +// copy of this software and associated documentation files (the +// "Software"), to deal in the Software without restriction, including +// without limitation the rights to use, copy, modify, merge, publish, +// distribute, sublicense, and/or sell copies of the Software, and to +// permit persons to whom the Software is furnished to do so, subject to +// the following conditions: +// +// The above copyright notice and this permission notice shall be included +// in all copies or substantial portions of the Software. +// +// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS +// OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF +// MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. +// IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY +// CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, +// TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE +// SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. +// +// +// Represents an item for the TornadoBarSeries. +// +// -------------------------------------------------------------------------------------------------------------------- +namespace OxyPlot.Series +{ + /// + /// Represents an item for the TornadoBarSeries. + /// + public class TornadoBarItem : CategorizedItem, ICodeGenerating + { + /// + /// Initializes a new instance of the class. + /// + public TornadoBarItem() + { + this.Minimum = double.NaN; + this.Maximum = double.NaN; + this.BaseValue = double.NaN; + this.MinimumColor = null; + this.MaximumColor = null; + } + + /// + /// Initializes a new instance of the class. + /// + /// + /// The minimum. + /// + /// + /// The maximum. + /// + /// + /// The base value. + /// + /// + /// The minimum color. + /// + /// + /// The maximum color. + /// + public TornadoBarItem( + double minimum, + double maximum, + double baseValue = double.NaN, + OxyColor minimumColor = null, + OxyColor maximumColor = null) + { + this.Minimum = minimum; + this.Maximum = maximum; + this.BaseValue = baseValue; + this.MinimumColor = minimumColor; + this.MaximumColor = maximumColor; + } + + /// + /// Gets or sets the base value. + /// + public double BaseValue { get; set; } + + /// + /// Gets or sets the maximum. + /// + public double Maximum { get; set; } + + /// + /// Gets or sets the color for the maximum bar. + /// + public OxyColor MaximumColor { get; set; } + + /// + /// Gets or sets the minimum value. + /// + public double Minimum { get; set; } + + /// + /// Gets or sets the color for the minimum bar. + /// + public OxyColor MinimumColor { get; set; } + + /// + /// Returns c# code that generates this instance. + /// + /// + /// C# code. + /// + public string ToCode() + { + if (this.MaximumColor != null) + { + return CodeGenerator.FormatConstructor( + this.GetType(), + "{0},{1},{2},{3},{4}", + this.Minimum, + this.Maximum, + this.BaseValue, + this.MinimumColor.ToCode(), + this.MaximumColor.ToCode()); + } + + if (this.MinimumColor != null) + { + return CodeGenerator.FormatConstructor( + this.GetType(), + "{0},{1},{2},{3}", + this.Minimum, + this.Maximum, + this.BaseValue, + this.MinimumColor.ToCode()); + } + + if (!double.IsNaN(this.BaseValue)) + { + return CodeGenerator.FormatConstructor( + this.GetType(), "{0},{1},{2}", this.Minimum, this.Maximum, this.BaseValue); + } + + return CodeGenerator.FormatConstructor(this.GetType(), "{0},{1}", this.Minimum, this.Maximum); + } + + } +} \ No newline at end of file diff -r 88d699a65cc2 -r 5be8f2773237 External/OxyPlot/OxyPlot/Series/BarSeries/TornadoBarSeries.cs --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/External/OxyPlot/OxyPlot/Series/BarSeries/TornadoBarSeries.cs Sat Jun 08 16:53:22 2013 +0000 @@ -0,0 +1,590 @@ +// -------------------------------------------------------------------------------------------------------------------- +// +// The MIT License (MIT) +// +// Copyright (c) 2012 Oystein Bjorke +// +// Permission is hereby granted, free of charge, to any person obtaining a +// copy of this software and associated documentation files (the +// "Software"), to deal in the Software without restriction, including +// without limitation the rights to use, copy, modify, merge, publish, +// distribute, sublicense, and/or sell copies of the Software, and to +// permit persons to whom the Software is furnished to do so, subject to +// the following conditions: +// +// The above copyright notice and this permission notice shall be included +// in all copies or substantial portions of the Software. +// +// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS +// OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF +// MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. +// IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY +// CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, +// TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE +// SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. +// +// +// Represents a series that can be used to create tornado plots. +// +// -------------------------------------------------------------------------------------------------------------------- +namespace OxyPlot.Series +{ + using System; + using System.Collections.Generic; + using System.Linq; + + using OxyPlot.Axes; + + /// + /// Represents a series that can be used to create tornado plots. + /// + /// + /// See http://en.wikipedia.org/wiki/Tornado_diagram. + /// + public class TornadoBarSeries : CategorizedSeries + { + /// + /// The default fill color. + /// + private OxyColor defaultMaximumFillColor; + + /// + /// The default minimum fill color. + /// + private OxyColor defaultMinimumFillColor; + + /// + /// Initializes a new instance of the class. + /// + public TornadoBarSeries() + { + this.Items = new List(); + + this.MaximumFillColor = OxyColor.FromRgb(216, 82, 85); + this.MinimumFillColor = OxyColor.FromRgb(84, 138, 209); + + this.StrokeColor = OxyColors.Black; + this.StrokeThickness = 1; + this.BarWidth = 1; + + this.TrackerFormatString = "{0}"; + this.LabelMargin = 4; + + this.MinimumLabelFormatString = "{0}"; + this.MaximumLabelFormatString = "{0}"; + } + + /// + /// Gets or sets the width of the bars (as a fraction of the available width). The default value is 0.5 (50%) + /// + /// + /// The width of the bars. + /// + public double BarWidth { get; set; } + + /// + /// Gets or sets the base value. + /// + /// + /// The base value. + /// + public double BaseValue { get; set; } + + /// + /// Gets the tornado bar items. + /// + /// + /// The items. + /// + public IList Items { get; private set; } + + /// + /// Gets or sets the label color. + /// + public OxyColor LabelColor { get; set; } + + /// + /// Gets or sets the label field. + /// + public string LabelField { get; set; } + + /// + /// Gets or sets the label margins. + /// + public double LabelMargin { get; set; } + + /// + /// Gets or sets the maximum value field. + /// + public string MaximumField { get; set; } + + /// + /// Gets or sets the color of the interior of the Maximum bars. + /// + /// + /// The color. + /// + public OxyColor MaximumFillColor { get; set; } + + /// + /// Gets the actual fill color. + /// + /// The actual color. + public OxyColor ActualMaximumFillColor + { + get { return this.MaximumFillColor ?? this.defaultMaximumFillColor; } + } + + /// + /// Gets or sets the format string for the maximum labels. + /// + public string MaximumLabelFormatString { get; set; } + + /// + /// Gets or sets the minimum value field. + /// + public string MinimumField { get; set; } + + /// + /// Gets or sets the default color of the interior of the Minimum bars. + /// + /// + /// The color. + /// + public OxyColor MinimumFillColor { get; set; } + + /// + /// Gets the actual minimum fill color. + /// + /// The actual color. + public OxyColor ActualMinimumFillColor + { + get { return this.MinimumFillColor ?? this.defaultMinimumFillColor; } + } + + /// + /// Gets or sets the format string for the minimum labels. + /// + public string MinimumLabelFormatString { get; set; } + + /// + /// Gets or sets the color of the border around the bars. + /// + /// + /// The color of the stroke. + /// + public OxyColor StrokeColor { get; set; } + + /// + /// Gets or sets the thickness of the bar border strokes. + /// + /// + /// The stroke thickness. + /// + public double StrokeThickness { get; set; } + + /// + /// Gets or sets the actual rectangles for the maximum bars. + /// + protected internal IList ActualMaximumBarRectangles { get; set; } + + /// + /// Gets or sets the actual rectangles for the minimum bars. + /// + protected internal IList ActualMinimumBarRectangles { get; set; } + + /// + /// Gets or sets the valid items + /// + protected internal IList ValidItems { get; set; } + + /// + /// Gets or sets the dictionary which stores the index-inversion for the valid items + /// + protected internal Dictionary ValidItemsIndexInversion { get; set; } + + /// + /// Gets the point in the dataset that is nearest the specified point. + /// + /// + /// The point. + /// + /// + /// The interpolate. + /// + /// + /// A TrackerHitResult for the current hit. + /// + public override TrackerHitResult GetNearestPoint(ScreenPoint point, bool interpolate) + { + for (int i = 0; i < this.ActualMinimumBarRectangles.Count; i++) + { + var r = this.ActualMinimumBarRectangles[i]; + if (r.Contains(point)) + { + var item = (TornadoBarItem)this.GetItem(this.ValidItemsIndexInversion[i]); + var categoryIndex = item.GetCategoryIndex(i); + var value = this.ValidItems[i].Minimum; + var dp = new DataPoint(categoryIndex, value); + var text = StringHelper.Format(this.ActualCulture, this.TrackerFormatString, item, value); + return new TrackerHitResult(this, dp, point, item, i, text); + } + + r = this.ActualMaximumBarRectangles[i]; + if (r.Contains(point)) + { + var item = (TornadoBarItem)this.GetItem(this.ValidItemsIndexInversion[i]); + var categoryIndex = item.GetCategoryIndex(i); + var value = this.ValidItems[i].Maximum; + var dp = new DataPoint(categoryIndex, value); + var text = StringHelper.Format(this.ActualCulture, this.TrackerFormatString, item, value); + return new TrackerHitResult(this, dp, point, item, i, text); + } + } + + return null; + } + + /// + /// Checks if the specified value is valid. + /// + /// + /// The value. + /// + /// + /// The y axis. + /// + /// + /// True if the value is valid. + /// + public virtual bool IsValidPoint(double v, Axis yaxis) + { + return !double.IsNaN(v) && !double.IsInfinity(v); + } + + /// + /// Renders the Series on the specified rendering context. + /// + /// + /// The rendering context. + /// + /// + /// The model. + /// + public override void Render(IRenderContext rc, PlotModel model) + { + this.ActualMinimumBarRectangles = new List(); + this.ActualMaximumBarRectangles = new List(); + + if (this.ValidItems.Count == 0) + { + return; + } + + var clippingRect = this.GetClippingRect(); + var categoryAxis = this.GetCategoryAxis(); + var actualBarWidth = this.GetActualBarWidth(); + + for (var i = 0; i < this.ValidItems.Count; i++) + { + var item = this.ValidItems[i]; + + var categoryIndex = item.GetCategoryIndex(i); + + var baseValue = double.IsNaN(item.BaseValue) ? this.BaseValue : item.BaseValue; + + var p0 = this.Transform(item.Minimum, categoryIndex - 0.5 + categoryAxis.BarOffset[categoryIndex]); + var p1 = this.Transform( + item.Maximum, categoryIndex - 0.5 + categoryAxis.BarOffset[categoryIndex] + actualBarWidth); + var p2 = this.Transform(baseValue, categoryIndex - 0.5 + categoryAxis.BarOffset[categoryIndex]); + p2.X = (int)p2.X; + + var minimumRectangle = OxyRect.Create(p0.X, p0.Y, p2.X, p1.Y); + var maximumRectangle = OxyRect.Create(p2.X, p0.Y, p1.X, p1.Y); + + this.ActualMinimumBarRectangles.Add(minimumRectangle); + this.ActualMaximumBarRectangles.Add(maximumRectangle); + + rc.DrawClippedRectangleAsPolygon( + minimumRectangle, + clippingRect, + item.MinimumColor ?? this.ActualMinimumFillColor, + this.StrokeColor, + this.StrokeThickness); + rc.DrawClippedRectangleAsPolygon( + maximumRectangle, + clippingRect, + item.MaximumColor ?? this.ActualMaximumFillColor, + this.StrokeColor, + this.StrokeThickness); + + if (this.MinimumLabelFormatString != null) + { + var s = StringHelper.Format( + this.ActualCulture, + this.MinimumLabelFormatString, + this.GetItem(this.ValidItemsIndexInversion[i]), + item.Minimum); + var pt = new ScreenPoint( + minimumRectangle.Left - this.LabelMargin, (minimumRectangle.Top + minimumRectangle.Bottom) / 2); + + rc.DrawClippedText( + clippingRect, + pt, + s, + this.ActualTextColor, + this.ActualFont, + this.ActualFontSize, + this.ActualFontWeight, + 0, + HorizontalAlignment.Right, + VerticalAlignment.Middle); + } + + if (this.MaximumLabelFormatString != null) + { + var s = StringHelper.Format( + this.ActualCulture, + this.MaximumLabelFormatString, + this.GetItem(this.ValidItemsIndexInversion[i]), + item.Maximum); + var pt = new ScreenPoint( + maximumRectangle.Right + this.LabelMargin, (maximumRectangle.Top + maximumRectangle.Bottom) / 2); + + rc.DrawClippedText( + clippingRect, + pt, + s, + this.ActualTextColor, + this.ActualFont, + this.ActualFontSize, + this.ActualFontWeight, + 0, + HorizontalAlignment.Left, + VerticalAlignment.Middle); + } + } + } + + /// + /// Renders the legend symbol on the specified rendering context. + /// + /// + /// The rendering context. + /// + /// + /// The legend rectangle. + /// + public override void RenderLegend(IRenderContext rc, OxyRect legendBox) + { + double xmid = (legendBox.Left + legendBox.Right) / 2; + double ymid = (legendBox.Top + legendBox.Bottom) / 2; + double height = (legendBox.Bottom - legendBox.Top) * 0.8; + double width = height; + rc.DrawRectangleAsPolygon( + new OxyRect(xmid - (0.5 * width), ymid - (0.5 * height), 0.5 * width, height), + this.ActualMinimumFillColor, + this.StrokeColor, + this.StrokeThickness); + rc.DrawRectangleAsPolygon( + new OxyRect(xmid, ymid - (0.5 * height), 0.5 * width, height), + this.ActualMaximumFillColor, + this.StrokeColor, + this.StrokeThickness); + } + + /// + /// Gets or sets the width/height of the columns/bars (as a fraction of the available space). + /// + /// + /// The fractional width. + /// + /// + /// The width of the bars. + /// + /// + /// The available space will be determined by the GapWidth of the CategoryAxis used by this series. + /// + internal override double GetBarWidth() + { + return this.BarWidth; + } + + /// + /// Gets the items of this series. + /// + /// + /// The items. + /// + protected internal override IList GetItems() + { + return this.Items.Cast().ToList(); + } + + /// + /// Check if the data series is using the specified axis. + /// + /// + /// An axis which should be checked if used + /// + /// + /// True if the axis is in use. + /// + protected internal override bool IsUsing(Axis axis) + { + return this.XAxis == axis || this.YAxis == axis; + } + + /// + /// The set default values. + /// + /// + /// The model. + /// + protected internal override void SetDefaultValues(PlotModel model) + { + if (this.MaximumFillColor == null) + { + this.defaultMaximumFillColor = model.GetDefaultColor(); + } + + if (this.MinimumFillColor == null) + { + this.defaultMinimumFillColor = model.GetDefaultColor(); + } + } + + /// + /// Updates the axis maximum and minimum values. + /// + protected internal override void UpdateAxisMaxMin() + { + this.XAxis.Include(this.MinX); + this.XAxis.Include(this.MaxX); + } + + /// + /// Updates the data. + /// + protected internal override void UpdateData() + { + if (this.ItemsSource != null) + { + this.Items.Clear(); + + var filler = new ListFiller(); + filler.Add(this.MinimumField, (item, value) => item.Minimum = Convert.ToDouble(value)); + filler.Add(this.MaximumField, (item, value) => item.Maximum = Convert.ToDouble(value)); + filler.FillT(this.Items, this.ItemsSource); + } + } + + /// + /// Updates the maximum/minimum value on the value axis from the bar values. + /// + protected internal override void UpdateMaxMin() + { + base.UpdateMaxMin(); + + if (this.ValidItems == null || this.ValidItems.Count == 0) + { + return; + } + + double minValue = double.MaxValue; + double maxValue = double.MinValue; + + foreach (var item in this.ValidItems) + { + minValue = Math.Min(minValue, item.Minimum); + maxValue = Math.Max(maxValue, item.Maximum); + } + + this.MinX = minValue; + this.MaxX = maxValue; + } + + /// + /// Updates the valid items + /// + protected internal override void UpdateValidData() + { + this.ValidItems = new List(); + this.ValidItemsIndexInversion = new Dictionary(); + var valueAxis = this.GetValueAxis(); + + for (var i = 0; i < this.Items.Count; i++) + { + var item = this.Items[i]; + if (valueAxis.IsValidValue(item.Minimum) && valueAxis.IsValidValue(item.Maximum)) + { + this.ValidItemsIndexInversion.Add(this.ValidItems.Count, i); + this.ValidItems.Add(item); + } + } + } + + /// + /// Gets the actual width/height of the items of this series. + /// + /// + /// The width or height. + /// + /// + /// The actual width is also influenced by the GapWidth of the CategoryAxis used by this series. + /// + protected override double GetActualBarWidth() + { + var categoryAxis = this.GetCategoryAxis(); + return this.BarWidth / (1 + categoryAxis.GapWidth) / categoryAxis.MaxWidth; + } + + /// + /// Gets the category axis. + /// + /// + /// The category axis. + /// + protected override CategoryAxis GetCategoryAxis() + { + var categoryAxis = this.YAxis as CategoryAxis; + if (categoryAxis == null) + { + throw new InvalidOperationException("No category axis defined."); + } + + return categoryAxis; + } + + /// + /// Gets the item at the specified index. + /// + /// + /// The index of the item. + /// + /// + /// The item of the index. + /// + protected override object GetItem(int i) + { + if (this.ItemsSource != null || this.Items == null || this.Items.Count == 0) + { + return base.GetItem(i); + } + + return this.Items[i]; + } + + /// + /// Gets the value axis. + /// + /// + /// The value axis. + /// + private Axis GetValueAxis() + { + return this.XAxis; + } + + } +} \ No newline at end of file diff -r 88d699a65cc2 -r 5be8f2773237 External/OxyPlot/OxyPlot/Series/BoxPlotItem.cs --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/External/OxyPlot/OxyPlot/Series/BoxPlotItem.cs Sat Jun 08 16:53:22 2013 +0000 @@ -0,0 +1,167 @@ +// -------------------------------------------------------------------------------------------------------------------- +// +// The MIT License (MIT) +// +// Copyright (c) 2012 Oystein Bjorke +// +// Permission is hereby granted, free of charge, to any person obtaining a +// copy of this software and associated documentation files (the +// "Software"), to deal in the Software without restriction, including +// without limitation the rights to use, copy, modify, merge, publish, +// distribute, sublicense, and/or sell copies of the Software, and to +// permit persons to whom the Software is furnished to do so, subject to +// the following conditions: +// +// The above copyright notice and this permission notice shall be included +// in all copies or substantial portions of the Software. +// +// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS +// OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF +// MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. +// IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY +// CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, +// TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE +// SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. +// +// +// Represents an item in a BoxPlotSeries. +// +// -------------------------------------------------------------------------------------------------------------------- +namespace OxyPlot.Series +{ + using System.Collections.Generic; + + /// + /// Represents an item in a . + /// + public struct BoxPlotItem + { + /// + /// Initializes a new instance of the struct. + /// + /// + /// The x. + /// + /// + /// The lower whisker. + /// + /// + /// The box bottom. + /// + /// + /// The median. + /// + /// + /// The box top. + /// + /// + /// The upper whisker. + /// + /// + /// The outliers. + /// + /// + /// The tag. + /// + public BoxPlotItem( + double x, + double lowerWhisker, + double boxBottom, + double median, + double boxTop, + double upperWhisker, + IList outliers, + object tag = null) + : this() + { + this.X = x; + this.LowerWhisker = lowerWhisker; + this.BoxBottom = boxBottom; + this.Median = median; + this.BoxTop = boxTop; + this.UpperWhisker = upperWhisker; + this.Outliers = outliers; + this.Tag = tag; + } + + /// + /// Gets or sets the box bottom value (usually the 25th percentile, Q1). + /// + /// The lower quartile value. + public double BoxBottom { get; set; } + + /// + /// Gets or sets the box top value (usually the 75th percentile, Q3)). + /// + /// The box top value. + public double BoxTop { get; set; } + + /// + /// Gets or sets the lower whisker value. + /// + /// The lower whisker value. + public double LowerWhisker { get; set; } + + /// + /// Gets or sets the median. + /// + /// The median. + public double Median { get; set; } + + /// + /// Gets or sets the outliers. + /// + /// The outliers. + public IList Outliers { get; set; } + + /// + /// Gets or sets the tag. + /// + /// The tag. + public object Tag { get; set; } + + /// + /// Gets or sets the upper whisker value. + /// + /// The upper whisker value. + public double UpperWhisker { get; set; } + + /// + /// Gets a list of all the values in the item. + /// + public IList Values + { + get + { + var values = new List { this.LowerWhisker, this.BoxBottom, this.Median, this.BoxTop, this.UpperWhisker }; + values.AddRange(this.Outliers); + return values; + } + } + + /// + /// Gets or sets the X value. + /// + /// The X value. + public double X { get; set; } + + /// + /// Returns a that represents this instance. + /// + /// + /// A that represents this instance. + /// + public override string ToString() + { + return string.Format( + "{0} {1} {2} {3} {4} {5} ", + this.X, + this.LowerWhisker, + this.BoxBottom, + this.Median, + this.BoxTop, + this.UpperWhisker); + } + + } +} \ No newline at end of file diff -r 88d699a65cc2 -r 5be8f2773237 External/OxyPlot/OxyPlot/Series/BoxPlotSeries.cs --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/External/OxyPlot/OxyPlot/Series/BoxPlotSeries.cs Sat Jun 08 16:53:22 2013 +0000 @@ -0,0 +1,615 @@ +// -------------------------------------------------------------------------------------------------------------------- +// +// The MIT License (MIT) +// +// Copyright (c) 2012 Oystein Bjorke +// +// Permission is hereby granted, free of charge, to any person obtaining a +// copy of this software and associated documentation files (the +// "Software"), to deal in the Software without restriction, including +// without limitation the rights to use, copy, modify, merge, publish, +// distribute, sublicense, and/or sell copies of the Software, and to +// permit persons to whom the Software is furnished to do so, subject to +// the following conditions: +// +// The above copyright notice and this permission notice shall be included +// in all copies or substantial portions of the Software. +// +// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS +// OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF +// MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. +// IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY +// CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, +// TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE +// SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. +// +// +// Represents a series for box plots. +// +// -------------------------------------------------------------------------------------------------------------------- + +namespace OxyPlot.Series +{ + using System.Collections.Generic; + using System.Linq; + + using OxyPlot.Axes; + + /// + /// Represents a series for box plots. + /// + public class BoxPlotSeries : XYAxisSeries + { + /// + /// Initializes a new instance of the class. + /// + public BoxPlotSeries() + { + this.Items = new List(); + this.TrackerFormatString = + "X: {1:0.00}\nUpper Whisker: {2:0.00}\nThird Quartil: {3:0.00}\nMedian: {4:0.00}\nFirst Quartil: {5:0.00}\nLower Whisker: {6:0.00}"; + this.OutlierTrackerFormatString = "X: {1:0.00}\nY: {2:0.00}"; + this.Title = null; + this.Fill = null; + this.Stroke = OxyColors.Black; + this.BoxWidth = 0.3; + this.StrokeThickness = 1; + this.MedianThickness = 2; + this.OutlierSize = 2; + this.OutlierType = MarkerType.Circle; + this.MedianPointSize = 2; + this.WhiskerWidth = 0.5; + this.LineStyle = LineStyle.Solid; + this.ShowMedianAsDot = false; + this.ShowBox = true; + } + + /// + /// Gets or sets the width of the boxes (specified in x-axis units). + /// + /// + /// The width of the boxes. + /// + public double BoxWidth { get; set; } + + /// + /// Gets or sets the fill color. If null, this color will be automatically set. + /// + /// + /// The fill color. + /// + public OxyColor Fill { get; set; } + + /// + /// Gets or sets the box plot items. + /// + /// + /// The items. + /// + public IList Items { get; set; } + + /// + /// Gets or sets the line style. + /// + /// + /// The line style. + /// + public LineStyle LineStyle { get; set; } + + /// + /// Gets or sets the size of the median point. + /// + /// + /// This property is only used when MedianStyle = Dot. + /// + public double MedianPointSize { get; set; } + + /// + /// Gets or sets the median thickness, relative to the StrokeThickness. + /// + /// + /// The median thickness. + /// + public double MedianThickness { get; set; } + + /// + /// Gets or sets the diameter of the outlier circles (specified in points). + /// + /// + /// The size of the outlier. + /// + public double OutlierSize { get; set; } + + /// + /// Gets or sets the tracker format string for the outliers. + /// + /// + /// The tracker format string for the outliers. + /// + /// + /// Use {0} for series title, {1} for x- and {2} for y-value. + /// + public string OutlierTrackerFormatString { get; set; } + + /// + /// Gets or sets the type of the outliers. + /// + /// + /// The type of the outliers. + /// + /// + /// MarkerType.Custom is currently not supported. + /// + public MarkerType OutlierType { get; set; } + + /// + /// Gets or sets a value indicating whether to show the boxes. + /// + public bool ShowBox { get; set; } + + /// + /// Gets or sets a value indicating whether to show the median as a dot. + /// + public bool ShowMedianAsDot { get; set; } + + /// + /// Gets or sets the stroke. + /// + /// + /// The stroke. + /// + public OxyColor Stroke { get; set; } + + /// + /// Gets or sets the stroke thickness. + /// + /// + /// The stroke thickness. + /// + public double StrokeThickness { get; set; } + + /// + /// Gets or sets the width of the whiskers (relative to the BoxWidth). + /// + /// + /// The width of the whiskers. + /// + public double WhiskerWidth { get; set; } + + /// + /// Gets the nearest point. + /// + /// + /// The point. + /// + /// + /// interpolate if set to true . + /// + /// + /// A TrackerHitResult for the current hit. + /// + public override TrackerHitResult GetNearestPoint(ScreenPoint point, bool interpolate) + { + if (this.XAxis == null || this.YAxis == null) + { + return null; + } + + double minimumDistance = double.MaxValue; + var result = new TrackerHitResult(this, DataPoint.Undefined, ScreenPoint.Undefined); + foreach (var item in this.Items) + { + foreach (var outlier in item.Outliers) + { + var sp = this.Transform(item.X, outlier); + double d = (sp - point).LengthSquared; + if (d < minimumDistance) + { + result.DataPoint = new DataPoint(item.X, outlier); + result.Position = sp; + result.Item = item; + result.Text = StringHelper.Format( + this.ActualCulture, + this.OutlierTrackerFormatString, + item, + this.Title, + this.XAxis.GetValue(result.DataPoint.X), + outlier); + minimumDistance = d; + } + } + + // check if we are inside the box rectangle + var rect = this.GetBoxRect(item); + if (rect.Contains(point)) + { + result.DataPoint = new DataPoint(item.X, this.YAxis.InverseTransform(point.Y)); + result.Position = this.Transform(result.DataPoint); + result.Item = item; + + result.Text = StringHelper.Format( + this.ActualCulture, + this.TrackerFormatString, + item, + this.Title, + this.XAxis.GetValue(result.DataPoint.X), + item.UpperWhisker, + item.BoxTop, + item.Median, + item.BoxBottom, + item.LowerWhisker); + + minimumDistance = 0; + } + + var topWhisker = this.Transform(item.X, item.UpperWhisker); + var bottomWhisker = this.Transform(item.X, item.LowerWhisker); + + // check if we are near the line + var p = ScreenPointHelper.FindPointOnLine(point, topWhisker, bottomWhisker); + double d2 = (p - point).LengthSquared; + if (d2 < minimumDistance) + { + result.DataPoint = this.InverseTransform(p); + result.Position = this.Transform(result.DataPoint); + result.Item = item; + result.Text = StringHelper.Format( + this.ActualCulture, + this.TrackerFormatString, + item, + this.Title, + this.XAxis.GetValue(result.DataPoint.X), + item.UpperWhisker, + item.BoxTop, + item.Median, + item.BoxBottom, + item.LowerWhisker); + minimumDistance = d2; + } + } + + if (minimumDistance < double.MaxValue) + { + return result; + } + + return null; + } + + /// + /// Determines whether the specified item contains a valid point. + /// + /// + /// The item. + /// + /// + /// The x axis. + /// + /// + /// The y axis. + /// + /// + /// true if the point is valid; otherwise, false . + /// + public virtual bool IsValidPoint(BoxPlotItem item, Axis xaxis, Axis yaxis) + { + return !double.IsNaN(item.X) && !double.IsInfinity(item.X) && !item.Values.Any(double.IsNaN) + && !item.Values.Any(double.IsInfinity) && (xaxis != null && xaxis.IsValidValue(item.X)) + && (yaxis != null && item.Values.All(yaxis.IsValidValue)); + } + + /// + /// Renders the series on the specified render context. + /// + /// + /// The rendering context. + /// + /// + /// The model. + /// + public override void Render(IRenderContext rc, PlotModel model) + { + if (this.Items.Count == 0) + { + return; + } + + var clippingRect = this.GetClippingRect(); + + var outlierScreenPoints = new List(); + var halfBoxWidth = this.BoxWidth * 0.5; + var halfWhiskerWidth = halfBoxWidth * this.WhiskerWidth; + var strokeColor = this.GetSelectableColor(this.Stroke); + var fillColor = this.GetSelectableFillColor(this.Fill); + + foreach (var item in this.Items) + { + // Add the outlier points + outlierScreenPoints.AddRange(item.Outliers.Select(outlier => this.Transform(item.X, outlier))); + + var topWhiskerTop = this.Transform(item.X, item.UpperWhisker); + var topWhiskerBottom = this.Transform(item.X, item.BoxTop); + var bottomWhiskerTop = this.Transform(item.X, item.BoxBottom); + var bottomWhiskerBottom = this.Transform(item.X, item.LowerWhisker); + rc.DrawClippedLine( + new[] { topWhiskerTop, topWhiskerBottom }, + clippingRect, + 0, + strokeColor, + this.StrokeThickness, + this.LineStyle, + OxyPenLineJoin.Miter, + true); + rc.DrawClippedLine( + new[] { bottomWhiskerTop, bottomWhiskerBottom }, + clippingRect, + 0, + strokeColor, + this.StrokeThickness, + this.LineStyle, + OxyPenLineJoin.Miter, + true); + + // Draw the whiskers + if (this.WhiskerWidth > 0) + { + var topWhiskerLine1 = this.Transform(item.X - halfWhiskerWidth, item.UpperWhisker); + var topWhiskerLine2 = this.Transform(item.X + halfWhiskerWidth, item.UpperWhisker); + var bottomWhiskerLine1 = this.Transform(item.X - halfWhiskerWidth, item.LowerWhisker); + var bottomWhiskerLine2 = this.Transform(item.X + halfWhiskerWidth, item.LowerWhisker); + + rc.DrawClippedLine( + new[] { topWhiskerLine1, topWhiskerLine2 }, + clippingRect, + 0, + strokeColor, + this.StrokeThickness, + LineStyle.Solid, + OxyPenLineJoin.Miter, + true); + rc.DrawClippedLine( + new[] { bottomWhiskerLine1, bottomWhiskerLine2 }, + clippingRect, + 0, + strokeColor, + this.StrokeThickness, + LineStyle.Solid, + OxyPenLineJoin.Miter, + true); + } + + if (this.ShowBox) + { + // Draw the box + var rect = this.GetBoxRect(item); + rc.DrawClippedRectangleAsPolygon(rect, clippingRect, fillColor, strokeColor, this.StrokeThickness); + } + + if (!this.ShowMedianAsDot) + { + // Draw the median line + var medianLeft = this.Transform(item.X - halfBoxWidth, item.Median); + var medianRight = this.Transform(item.X + halfBoxWidth, item.Median); + rc.DrawClippedLine( + new[] { medianLeft, medianRight }, + clippingRect, + 0, + strokeColor, + this.StrokeThickness * this.MedianThickness, + LineStyle.Solid, + OxyPenLineJoin.Miter, + true); + } + else + { + var mc = this.Transform(item.X, item.Median); + if (clippingRect.Contains(mc)) + { + var ellipseRect = new OxyRect( + mc.X - this.MedianPointSize, + mc.Y - this.MedianPointSize, + this.MedianPointSize * 2, + this.MedianPointSize * 2); + rc.DrawEllipse(ellipseRect, fillColor, null, 0); + } + } + } + + // Draw the outlier(s) + var markerSizes = outlierScreenPoints.Select(o => this.OutlierSize).ToList(); + rc.DrawMarkers( + outlierScreenPoints, + clippingRect, + this.OutlierType, + null, + markerSizes, + fillColor, + strokeColor, + this.StrokeThickness); + } + + /// + /// Renders the legend symbol on the specified rendering context. + /// + /// + /// The rendering context. + /// + /// + /// The legend rectangle. + /// + public override void RenderLegend(IRenderContext rc, OxyRect legendBox) + { + double xmid = (legendBox.Left + legendBox.Right) / 2; + double ybottom = legendBox.Top + ((legendBox.Bottom - legendBox.Top) * 0.7); + double ytop = legendBox.Top + ((legendBox.Bottom - legendBox.Top) * 0.3); + double ymid = (ybottom + ytop) * 0.5; + + var halfBoxWidth = legendBox.Width * 0.24; + var halfWhiskerWidth = halfBoxWidth * this.WhiskerWidth; + const double LegendStrokeThickness = 1; + var strokeColor = this.GetSelectableColor(this.Stroke); + var fillColor = this.GetSelectableFillColor(this.Fill); + + rc.DrawLine( + new[] { new ScreenPoint(xmid, legendBox.Top), new ScreenPoint(xmid, ytop) }, + strokeColor, + LegendStrokeThickness, + LineStyle.Solid.GetDashArray(), + OxyPenLineJoin.Miter, + true); + + rc.DrawLine( + new[] { new ScreenPoint(xmid, ybottom), new ScreenPoint(xmid, legendBox.Bottom) }, + strokeColor, + LegendStrokeThickness, + LineStyle.Solid.GetDashArray(), + OxyPenLineJoin.Miter, + true); + + if (this.WhiskerWidth > 0) + { + // top whisker + rc.DrawLine( + new[] + { + new ScreenPoint(xmid - halfWhiskerWidth - 1, legendBox.Bottom), + new ScreenPoint(xmid + halfWhiskerWidth, legendBox.Bottom) + }, + strokeColor, + LegendStrokeThickness, + LineStyle.Solid.GetDashArray(), + OxyPenLineJoin.Miter, + true); + + // bottom whisker + rc.DrawLine( + new[] + { + new ScreenPoint(xmid - halfWhiskerWidth - 1, legendBox.Top), + new ScreenPoint(xmid + halfWhiskerWidth, legendBox.Top) + }, + strokeColor, + LegendStrokeThickness, + LineStyle.Solid.GetDashArray(), + OxyPenLineJoin.Miter, + true); + } + + if (this.ShowBox) + { + // box + rc.DrawRectangleAsPolygon( + new OxyRect(xmid - halfBoxWidth, ytop, 2 * halfBoxWidth, ybottom - ytop), + fillColor, + strokeColor, + LegendStrokeThickness); + } + + // median + if (!this.ShowMedianAsDot) + { + rc.DrawLine( + new[] { new ScreenPoint(xmid - halfBoxWidth, ymid), new ScreenPoint(xmid + halfBoxWidth, ymid) }, + strokeColor, + LegendStrokeThickness * this.MedianThickness, + LineStyle.Solid.GetDashArray(), + OxyPenLineJoin.Miter, + true); + } + else + { + var ellipseRect = new OxyRect( + xmid - this.MedianPointSize, + ymid - this.MedianPointSize, + this.MedianPointSize * 2, + this.MedianPointSize * 2); + rc.DrawEllipse(ellipseRect, fillColor, null); + } + } + + /// + /// Updates the max/minimum values. + /// + protected internal override void UpdateMaxMin() + { + base.UpdateMaxMin(); + this.InternalUpdateMaxMin(this.Items); + } + + /// + /// Updates the max and min of the series. + /// + /// + /// The items. + /// + protected void InternalUpdateMaxMin(IList items) + { + if (items == null || items.Count == 0) + { + return; + } + + double minx = this.MinX; + double miny = this.MinY; + double maxx = this.MaxX; + double maxy = this.MaxY; + + foreach (var pt in items) + { + if (!this.IsValidPoint(pt, this.XAxis, this.YAxis)) + { + continue; + } + + var x = pt.X; + if (x < minx || double.IsNaN(minx)) + { + minx = x; + } + + if (x > maxx || double.IsNaN(maxx)) + { + maxx = x; + } + + foreach (var y in pt.Values) + { + if (y < miny || double.IsNaN(miny)) + { + miny = y; + } + + if (y > maxy || double.IsNaN(maxy)) + { + maxy = y; + } + } + } + + this.MinX = minx; + this.MinY = miny; + this.MaxX = maxx; + this.MaxY = maxy; + } + + /// + /// Gets the screen rectangle for the box. + /// + /// + /// The box item. + /// + /// + /// A rectangle. + /// + private OxyRect GetBoxRect(BoxPlotItem item) + { + var halfBoxWidth = this.BoxWidth * 0.5; + + var boxTop = this.Transform(item.X - halfBoxWidth, item.BoxTop); + var boxBottom = this.Transform(item.X + halfBoxWidth, item.BoxBottom); + + var rect = new OxyRect(boxTop.X, boxTop.Y, boxBottom.X - boxTop.X, boxBottom.Y - boxTop.Y); + return rect; + } + } +} \ No newline at end of file diff -r 88d699a65cc2 -r 5be8f2773237 External/OxyPlot/OxyPlot/Series/CandleStickSeries.cs --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/External/OxyPlot/OxyPlot/Series/CandleStickSeries.cs Sat Jun 08 16:53:22 2013 +0000 @@ -0,0 +1,201 @@ +// -------------------------------------------------------------------------------------------------------------------- +// +// The MIT License (MIT) +// +// Copyright (c) 2012 Oystein Bjorke +// +// Permission is hereby granted, free of charge, to any person obtaining a +// copy of this software and associated documentation files (the +// "Software"), to deal in the Software without restriction, including +// without limitation the rights to use, copy, modify, merge, publish, +// distribute, sublicense, and/or sell copies of the Software, and to +// permit persons to whom the Software is furnished to do so, subject to +// the following conditions: +// +// The above copyright notice and this permission notice shall be included +// in all copies or substantial portions of the Software. +// +// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS +// OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF +// MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. +// IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY +// CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, +// TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE +// SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. +// +// +// Represents a series for candlestick charts. +// +// -------------------------------------------------------------------------------------------------------------------- +namespace OxyPlot.Series +{ + using System; + + /// + /// Represents a series for candlestick charts. + /// + /// + /// http://en.wikipedia.org/wiki/Candlestick_chart + /// http://www.mathworks.com/help/toolbox/finance/candle.html + /// + public class CandleStickSeries : HighLowSeries + { + /// + /// Initializes a new instance of the class. + /// + public CandleStickSeries() + { + this.CandleWidth = 10; + } + + /// + /// Initializes a new instance of the class. + /// + /// + /// The title. + /// + public CandleStickSeries(string title) + : this() + { + this.Title = title; + } + + /// + /// Initializes a new instance of the class. + /// + /// + /// The color. + /// + /// + /// The stroke thickness. + /// + /// + /// The title. + /// + public CandleStickSeries(OxyColor color, double strokeThickness = 1, string title = null) + : this() + { + this.Color = color; + this.StrokeThickness = strokeThickness; + this.Title = title; + } + + /// + /// Gets or sets the width of the candle. + /// + /// The width of the candle. + public double CandleWidth { get; set; } + + /// + /// Renders the series on the specified rendering context. + /// + /// + /// The rendering context. + /// + /// + /// The owner plot model. + /// + public override void Render(IRenderContext rc, PlotModel model) + { + if (this.Items.Count == 0) + { + return; + } + + this.VerifyAxes(); + + var clippingRect = this.GetClippingRect(); + + foreach (var v in this.Items) + { + if (!this.IsValidItem(v, this.XAxis, this.YAxis)) + { + continue; + } + + if (this.StrokeThickness > 0 && this.LineStyle != LineStyle.None) + { + var high = this.Transform(v.X, v.High); + var low = this.Transform(v.X, v.Low); + + if (double.IsNaN(v.Open) || double.IsNaN(v.Close)) + { + rc.DrawClippedLine( + new[] { low, high }, + clippingRect, + 0, + this.GetSelectableColor(this.ActualColor), + this.StrokeThickness, + this.LineStyle, + this.LineJoin, + false); + } + else + { + var open = this.Transform(v.X, v.Open); + var close = this.Transform(v.X, v.Close); + var max = new ScreenPoint(open.X, Math.Max(open.Y, close.Y)); + var min = new ScreenPoint(open.X, Math.Min(open.Y, close.Y)); + + rc.DrawClippedLine( + new[] { high, min }, + clippingRect, + 0, + this.GetSelectableColor(this.ActualColor), + this.StrokeThickness, + this.LineStyle, + this.LineJoin, + true); + + rc.DrawClippedLine( + new[] { max, low }, + clippingRect, + 0, + this.GetSelectableColor(this.ActualColor), + this.StrokeThickness, + this.LineStyle, + this.LineJoin, + true); + var openLeft = open; + openLeft.X -= this.CandleWidth * 0.5; + var closeRight = close; + closeRight.X += this.CandleWidth * 0.5; + var rect = new OxyRect(openLeft.X, min.Y, this.CandleWidth, max.Y - min.Y); + rc.DrawClippedRectangleAsPolygon( + rect, clippingRect, v.Open > v.Close ? this.GetSelectableFillColor(this.ActualColor) : null, this.GetSelectableColor(this.ActualColor), this.StrokeThickness); + } + } + } + } + + /// + /// Renders the legend symbol for the series on the specified rendering context. + /// + /// + /// The rendering context. + /// + /// + /// The bounding rectangle of the legend box. + /// + public override void RenderLegend(IRenderContext rc, OxyRect legendBox) + { + double xmid = (legendBox.Left + legendBox.Right) / 2; + double yopen = legendBox.Top + ((legendBox.Bottom - legendBox.Top) * 0.7); + double yclose = legendBox.Top + ((legendBox.Bottom - legendBox.Top) * 0.3); + double[] dashArray = LineStyleHelper.GetDashArray(this.LineStyle); + rc.DrawLine( + new[] { new ScreenPoint(xmid, legendBox.Top), new ScreenPoint(xmid, legendBox.Bottom) }, + this.GetSelectableColor(this.ActualColor), + this.StrokeThickness, + dashArray, + OxyPenLineJoin.Miter, + true); + rc.DrawRectangleAsPolygon( + new OxyRect(xmid - (this.CandleWidth * 0.5), yclose, this.CandleWidth, yopen - yclose), + this.GetSelectableFillColor(this.ActualColor), + this.GetSelectableColor(this.ActualColor), + this.StrokeThickness); + } + + } +} \ No newline at end of file diff -r 88d699a65cc2 -r 5be8f2773237 External/OxyPlot/OxyPlot/Series/ContourSeries.cs --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/External/OxyPlot/OxyPlot/Series/ContourSeries.cs Sat Jun 08 16:53:22 2013 +0000 @@ -0,0 +1,770 @@ +// -------------------------------------------------------------------------------------------------------------------- +// +// The MIT License (MIT) +// +// Copyright (c) 2012 Oystein Bjorke +// +// Permission is hereby granted, free of charge, to any person obtaining a +// copy of this software and associated documentation files (the +// "Software"), to deal in the Software without restriction, including +// without limitation the rights to use, copy, modify, merge, publish, +// distribute, sublicense, and/or sell copies of the Software, and to +// permit persons to whom the Software is furnished to do so, subject to +// the following conditions: +// +// The above copyright notice and this permission notice shall be included +// in all copies or substantial portions of the Software. +// +// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS +// OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF +// MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. +// IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY +// CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, +// TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE +// SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. +// +// +// Represents a series for contour plots. +// +// -------------------------------------------------------------------------------------------------------------------- +namespace OxyPlot.Series +{ + using System; + using System.Collections.Generic; + using System.Linq; + + /// + /// Represents a series that renders contours. + /// + /// + /// See http://en.wikipedia.org/wiki/Contour_line and http://www.mathworks.se/help/techdoc/ref/contour.html. + /// + public class ContourSeries : XYAxisSeries + { + /// + /// The contour collection. + /// + private List contours; + + /// + /// The temporary segment collection. + /// + private List segments; + + /// + /// The default color. + /// + private OxyColor defaultColor; + + /// + /// Initializes a new instance of the class. + /// + public ContourSeries() + { + this.ContourLevelStep = double.NaN; + + this.LabelSpacing = double.NaN; + this.LabelStep = 1; + this.LabelBackground = OxyColor.FromAColor(220, OxyColors.White); + + this.Color = null; + this.StrokeThickness = 1.0; + this.LineStyle = LineStyle.Solid; + + this.TrackerFormatString = "{1}: {2:0.####}\n{3}: {4:0.####}\n{5}: {6:0.####}"; + } + + /// + /// Gets or sets the color. + /// + /// The color. + public OxyColor Color { get; set; } + + /// + /// Gets the actual color. + /// + /// The actual color. + public OxyColor ActualColor + { + get { return this.Color ?? this.defaultColor; } + } + + /// + /// Gets or sets the column coordinates. + /// + /// The column coordinates. + public double[] ColumnCoordinates { get; set; } + + /// + /// Gets or sets the contour level step size. + /// This property is not used if the ContourLevels vector is set. + /// + /// The contour level step size. + public double ContourLevelStep { get; set; } + + /// + /// Gets or sets the contour levels. + /// + /// The contour levels. + public double[] ContourLevels { get; set; } + + /// + /// Gets or sets the contour colors. + /// + /// The contour colors. + /// + /// These colors will override the Color of the series. + /// If there are less colors than the number of contour levels, the colors will cycle. + /// + public OxyColor[] ContourColors { get; set; } + + /// + /// Gets or sets the data. + /// + /// The data. + public double[,] Data { get; set; } + + /// + /// Gets or sets the text background color. + /// + /// The text background color. + public OxyColor LabelBackground { get; set; } + + /// + /// Gets or sets the format string for contour values. + /// + /// The format string. + public string LabelFormatString { get; set; } + + /// + /// Gets or sets the label spacing. + /// + /// The label spacing. + public double LabelSpacing { get; set; } + + /// + /// Gets or sets the label step (number of contours per label). + /// + /// The label step. + public int LabelStep { get; set; } + + /// + /// Gets or sets the line style. + /// + /// The line style. + public LineStyle LineStyle { get; set; } + + /// + /// Gets or sets the row coordinates. + /// + /// The row coordinates. + public double[] RowCoordinates { get; set; } + + /// + /// Gets or sets the stroke thickness. + /// + /// The stroke thickness. + public double StrokeThickness { get; set; } + + /// + /// Calculates the contours. + /// + public void CalculateContours() + { + if (this.Data == null) + { + return; + } + + double[] actualContourLevels = this.ContourLevels; + + this.segments = new List(); + Conrec.RendererDelegate renderer = (startX, startY, endX, endY, contourLevel) => + this.segments.Add(new ContourSegment(new DataPoint(startX, startY), new DataPoint(endX, endY), contourLevel)); + + if (actualContourLevels == null) + { + double max = this.Data[0, 0]; + double min = this.Data[0, 0]; + for (int i = 0; i < this.Data.GetUpperBound(0); i++) + { + for (int j = 0; j < this.Data.GetUpperBound(1); j++) + { + max = Math.Max(max, this.Data[i, j]); + min = Math.Min(min, this.Data[i, j]); + } + } + + double actualStep = this.ContourLevelStep; + if (double.IsNaN(actualStep)) + { + double range = max - min; + double step = range / 20; + actualStep = Math.Pow(10, Math.Floor(step.GetExponent())); + } + + max = max.ToUpperMultiple(actualStep); + min = min.ToLowerMultiple(actualStep); + actualContourLevels = ArrayHelper.CreateVector(min, max, actualStep); + } + + Conrec.Contour(this.Data, this.RowCoordinates, this.ColumnCoordinates, actualContourLevels, renderer); + + this.JoinContourSegments(); + + if (this.ContourColors != null && this.ContourColors.Length > 0) + { + foreach (var c in this.contours) + { + // get the index of the contour's level + var index = IndexOf(actualContourLevels, c.ContourLevel); + if (index >= 0) + { + // clamp the index to the range of the ContourColors array + index = index % this.ContourColors.Length; + c.Color = this.ContourColors[index]; + } + } + } + } + + /// + /// Gets the point in the dataset that is nearest the specified point. + /// + /// + /// The point. + /// + /// + /// The interpolate. + /// + /// + /// A hit result object. + /// + public override TrackerHitResult GetNearestPoint(ScreenPoint point, bool interpolate) + { + TrackerHitResult result = null; + + var xaxisTitle = this.XAxis.Title ?? "X"; + var yaxisTitle = this.YAxis.Title ?? "Y"; + var zaxisTitle = "Z"; + + foreach (var c in this.contours) + { + var r = interpolate ? this.GetNearestInterpolatedPointInternal(c.Points, point) : this.GetNearestPointInternal(c.Points, point); + if (r != null) + { + if (result == null || result.Position.DistanceToSquared(point) > r.Position.DistanceToSquared(point)) + { + result = r; + result.Text = StringHelper.Format( + this.ActualCulture, + this.TrackerFormatString, + null, + this.Title, + xaxisTitle, + r.DataPoint.X, + yaxisTitle, + r.DataPoint.Y, + zaxisTitle, + c.ContourLevel); + } + } + } + + return result; + } + + /// + /// Renders the series on the specified rendering context. + /// + /// + /// The rendering context. + /// + /// + /// The model. + /// + public override void Render(IRenderContext rc, PlotModel model) + { + if (this.contours == null) + { + this.CalculateContours(); + } + + if (this.contours.Count == 0) + { + return; + } + + this.VerifyAxes(); + + var clippingRect = this.GetClippingRect(); + + var contourLabels = new List(); + + foreach (var contour in this.contours) + { + if (this.StrokeThickness > 0 && this.LineStyle != LineStyle.None) + { + var pts = new ScreenPoint[contour.Points.Count]; + { + int i = 0; + foreach (var pt in contour.Points) + { + pts[i++] = this.Transform(pt.X, pt.Y); + } + } + + rc.DrawClippedLine( + pts, + clippingRect, + 4, + this.GetSelectableColor(contour.Color ?? this.ActualColor), + this.StrokeThickness, + this.LineStyle, + OxyPenLineJoin.Miter, + false); + + // rc.DrawClippedPolygon(pts, clippingRect, 4, model.GetDefaultColor(), OxyColors.Black); + if (pts.Length > 10) + { + this.AddContourLabels(contour, pts, clippingRect, contourLabels); + } + } + } + + foreach (var cl in contourLabels) + { + this.RenderLabelBackground(rc, cl); + } + + foreach (var cl in contourLabels) + { + this.RenderLabel(rc, cl); + } + } + + /// + /// Sets default values from the plotmodel. + /// + /// + /// The plot model. + /// + protected internal override void SetDefaultValues(PlotModel model) + { + if (this.Color == null) + { + this.LineStyle = model.GetDefaultLineStyle(); + this.defaultColor = model.GetDefaultColor(); + } + } + + /// + /// Updates the max/min from the datapoints. + /// + protected internal override void UpdateMaxMin() + { + this.MinX = this.ColumnCoordinates.Min(); + this.MaxX = this.ColumnCoordinates.Max(); + this.MinY = this.RowCoordinates.Min(); + this.MaxY = this.RowCoordinates.Max(); + } + + /// + /// Determines if two values are close. + /// + /// + /// The first value. + /// + /// + /// The second value. + /// + /// + /// The squared tolerance. + /// + /// + /// True if the values are close. + /// + private static bool AreClose(double x1, double x2, double eps = 1e-6) + { + double dx = x1 - x2; + return dx * dx < eps; + } + + /// + /// Determines if two points are close. + /// + /// + /// The first point. + /// + /// + /// The second point. + /// + /// + /// The squared tolerance. + /// + /// + /// True if the points are close. + /// + private static bool AreClose(DataPoint p0, DataPoint p1, double eps = 1e-6) + { + double dx = p0.X - p1.X; + double dy = p0.Y - p1.Y; + return (dx * dx) + (dy * dy) < eps; + } + + /// + /// Gets the index of item that is closest to the specified value. + /// + /// A list of values. + /// A value. + /// An index. + private static int IndexOf(IList values, double value) + { + double min = double.MaxValue; + int index = -1; + for (int i = 0; i < values.Count; i++) + { + var d = Math.Abs(values[i] - value); + if (d < min) + { + min = d; + index = i; + } + } + + return index; + } + + /// + /// The add contour labels. + /// + /// + /// The contour. + /// + /// + /// The pts. + /// + /// + /// The clipping rect. + /// + /// + /// The contour labels. + /// + private void AddContourLabels( + Contour contour, ScreenPoint[] pts, OxyRect clippingRect, List contourLabels) + { + // todo: support label spacing and label step + if (pts.Length < 2) + { + return; + } + + // Calculate position and angle of the label + double i = (pts.Length - 1) * 0.5; + var i0 = (int)i; + int i1 = i0 + 1; + double dx = pts[i1].X - pts[i0].X; + double dy = pts[i1].Y - pts[i0].Y; + double x = pts[i0].X + (dx * (i - i0)); + double y = pts[i0].Y + (dy * (i - i0)); + if (!clippingRect.Contains(x, y)) + { + return; + } + + var pos = new ScreenPoint(x, y); + double angle = Math.Atan2(dy, dx) * 180 / Math.PI; + if (angle > 90) + { + angle -= 180; + } + + if (angle < -90) + { + angle += 180; + } + + string text = contour.ContourLevel.ToString(this.LabelFormatString, this.ActualCulture); + contourLabels.Add(new ContourLabel { Position = pos, Angle = angle, Text = text }); + } + + /// + /// Finds the connected segment. + /// + /// + /// The point. + /// + /// + /// The contour level. + /// + /// + /// The eps. + /// + /// + /// reverse the segment if set to true. + /// + /// + /// The connected segment, or null if no segment was found. + /// + private ContourSegment FindConnectedSegment(DataPoint point, double contourLevel, double eps, out bool reverse) + { + reverse = false; + foreach (var s in this.segments) + { + if (!AreClose(s.ContourLevel, contourLevel, eps)) + { + continue; + } + + if (AreClose(point, s.StartPoint, eps)) + { + return s; + } + + if (AreClose(point, s.EndPoint, eps)) + { + reverse = true; + return s; + } + } + + return null; + } + + /// + /// Joins the contour segments. + /// + /// + /// The tolerance for segment ends to connect (squared distance). + /// + private void JoinContourSegments(double eps = 1e-10) + { + // This is a simple, slow, naïve method - should be improved: + // http://stackoverflow.com/questions/1436091/joining-unordered-line-segments + this.contours = new List(); + var contourPoints = new List(); + int contourPointsCount = 0; + + ContourSegment firstSegment = null; + int segmentCount = this.segments.Count; + while (segmentCount > 0) + { + ContourSegment segment1 = null, segment2 = null; + + if (firstSegment != null) + { + bool reverse; + + // Find a segment that is connected to the head of the contour + segment1 = this.FindConnectedSegment( + (DataPoint)contourPoints[0], firstSegment.ContourLevel, eps, out reverse); + if (segment1 != null) + { + contourPoints.Insert(0, reverse ? segment1.StartPoint : segment1.EndPoint); + contourPointsCount++; + this.segments.Remove(segment1); + segmentCount--; + } + + // Find a segment that is connected to the tail of the contour + segment2 = this.FindConnectedSegment( + (DataPoint)contourPoints[contourPointsCount - 1], firstSegment.ContourLevel, eps, out reverse); + if (segment2 != null) + { + contourPoints.Add(reverse ? segment2.StartPoint : segment2.EndPoint); + contourPointsCount++; + this.segments.Remove(segment2); + segmentCount--; + } + } + + if ((segment1 == null && segment2 == null) || segmentCount == 0) + { + if (contourPointsCount > 0 && firstSegment != null) + { + this.contours.Add(new Contour(contourPoints, firstSegment.ContourLevel)); + contourPoints = new List(); + contourPointsCount = 0; + } + + if (segmentCount > 0) + { + firstSegment = this.segments.First(); + contourPoints.Add(firstSegment.StartPoint); + contourPoints.Add(firstSegment.EndPoint); + contourPointsCount += 2; + this.segments.Remove(firstSegment); + segmentCount--; + } + } + } + } + + /// + /// Renders the contour label. + /// + /// + /// The render context. + /// + /// + /// The contour label. + /// + private void RenderLabel(IRenderContext rc, ContourLabel cl) + { + if (this.ActualFontSize > 0) + { + rc.DrawText( + cl.Position, + cl.Text, + this.ActualTextColor, + this.ActualFont, + this.ActualFontSize, + this.ActualFontWeight, + cl.Angle, + HorizontalAlignment.Center, + VerticalAlignment.Middle); + } + } + + /// + /// Renders the contour label background. + /// + /// + /// The render context. + /// + /// + /// The contour label. + /// + private void RenderLabelBackground(IRenderContext rc, ContourLabel cl) + { + if (this.LabelBackground != null) + { + // Calculate background polygon + var size = rc.MeasureText(cl.Text, this.ActualFont, this.ActualFontSize, this.ActualFontWeight); + double a = cl.Angle / 180 * Math.PI; + double dx = Math.Cos(a); + double dy = Math.Sin(a); + + double ux = dx * 0.6; + double uy = dy * 0.6; + double vx = -dy * 0.5; + double vy = dx * 0.5; + double x = cl.Position.X; + double y = cl.Position.Y; + + var bpts = new[] + { + new ScreenPoint(x - (size.Width * ux) - (size.Height * vx), y - (size.Width * uy) - (size.Height * vy)), + new ScreenPoint(x + (size.Width * ux) - (size.Height * vx), y + (size.Width * uy) - (size.Height * vy)), + new ScreenPoint(x + (size.Width * ux) + (size.Height * vx), y + (size.Width * uy) + (size.Height * vy)), + new ScreenPoint(x - (size.Width * ux) + (size.Height * vx), y - (size.Width * uy) + (size.Height * vy)) + }; + rc.DrawPolygon(bpts, this.LabelBackground, null); + } + } + + /// + /// Represents a contour. + /// + private class Contour + { + /// + /// Gets or sets the contour level. + /// + /// The contour level. + internal readonly double ContourLevel; + + /// + /// Gets or sets the points. + /// + /// The points. + internal readonly IList Points; + + /// + /// Initializes a new instance of the class. + /// + /// + /// The points. + /// + /// + /// The contour level. + /// + public Contour(IList points, double contourLevel) + { + this.Points = points; + this.ContourLevel = contourLevel; + } + + /// + /// Gets or sets the color of the contour. + /// + public OxyColor Color { get; set; } + } + + /// + /// Represents a contour label. + /// + private class ContourLabel + { + /// + /// Gets or sets the angle. + /// + /// The angle. + public double Angle { get; set; } + + /// + /// Gets or sets the position. + /// + /// The position. + public ScreenPoint Position { get; set; } + + /// + /// Gets or sets the text. + /// + /// The text. + public string Text { get; set; } + + } + + /// + /// Represents a contour segment. + /// + private class ContourSegment + { + /// + /// The contour level. + /// + internal readonly double ContourLevel; + + /// + /// The end point. + /// + internal readonly DataPoint EndPoint; + + /// + /// The start point. + /// + internal readonly DataPoint StartPoint; + + /// + /// Initializes a new instance of the class. + /// + /// + /// The start point. + /// + /// + /// The end point. + /// + /// + /// The contour level. + /// + public ContourSegment(DataPoint startPoint, DataPoint endPoint, double contourLevel) + { + this.ContourLevel = contourLevel; + this.StartPoint = startPoint; + this.EndPoint = endPoint; + } + + } + } +} \ No newline at end of file diff -r 88d699a65cc2 -r 5be8f2773237 External/OxyPlot/OxyPlot/Series/DataPointSeries.cs --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/External/OxyPlot/OxyPlot/Series/DataPointSeries.cs Sat Jun 08 16:53:22 2013 +0000 @@ -0,0 +1,325 @@ +// -------------------------------------------------------------------------------------------------------------------- +// +// The MIT License (MIT) +// +// Copyright (c) 2012 Oystein Bjorke +// +// Permission is hereby granted, free of charge, to any person obtaining a +// copy of this software and associated documentation files (the +// "Software"), to deal in the Software without restriction, including +// without limitation the rights to use, copy, modify, merge, publish, +// distribute, sublicense, and/or sell copies of the Software, and to +// permit persons to whom the Software is furnished to do so, subject to +// the following conditions: +// +// The above copyright notice and this permission notice shall be included +// in all copies or substantial portions of the Software. +// +// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS +// OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF +// MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. +// IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY +// CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, +// TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE +// SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. +// +// +// Base class for series that contain a collection of IDataPoints. +// +// -------------------------------------------------------------------------------------------------------------------- +namespace OxyPlot.Series +{ + using System; + using System.Collections; + using System.Collections.Generic; + using System.Reflection; + + /// + /// Provides an abstract base class for series that contain a collection of s. + /// + public abstract class DataPointSeries : XYAxisSeries + { + /// + /// The list of data points. + /// + private IList points = new List(); + + /// + /// Initializes a new instance of the class. + /// + protected DataPointSeries() + { + this.DataFieldX = null; + this.DataFieldY = null; + } + + /// + /// Gets or sets a value indicating whether the tracker can interpolate points. + /// + public bool CanTrackerInterpolatePoints { get; set; } + + /// + /// Gets or sets the data field X. + /// + /// The data field X. + public string DataFieldX { get; set; } + + /// + /// Gets or sets the data field Y. + /// + /// The data field Y. + public string DataFieldY { get; set; } + + /// + /// Gets or sets the mapping delegate. + /// Example: series1.Mapping = item => new DataPoint(((MyType)item).Time,((MyType)item).Value); + /// + /// The mapping. + public Func Mapping { get; set; } + + /// + /// Gets or sets the points list. + /// + /// The points list. + public IList Points + { + get + { + return this.points; + } + + set + { + this.points = value; + } + } + + /// + /// Gets or sets a value indicating whether this is smooth. + /// + /// true if smooth; otherwise, false. + public bool Smooth { get; set; } + + /// + /// Gets the point on the series that is nearest the specified point. + /// + /// The point. + /// Interpolate the series if this flag is set to true. + /// + /// A TrackerHitResult for the current hit. + /// + public override TrackerHitResult GetNearestPoint(ScreenPoint point, bool interpolate) + { + if (interpolate && !this.CanTrackerInterpolatePoints) + { + return null; + } + + if (interpolate) + { + return this.GetNearestInterpolatedPointInternal(this.Points, point); + } + + return this.GetNearestPointInternal(this.Points, point); + } + + /// + /// Gets the item at the specified index. + /// + /// The index of the item. + /// The item of the index. + protected override object GetItem(int i) + { + if (this.ItemsSource == null && this.Points != null && i < this.Points.Count) + { + return this.Points[i]; + } + + return base.GetItem(i); + } + + /// + /// The update data. + /// + protected internal override void UpdateData() + { + if (this.ItemsSource == null) + { + return; + } + + this.AddDataPoints(this.Points); + } + + /// + /// Updates the max/min from the datapoints. + /// + protected internal override void UpdateMaxMin() + { + base.UpdateMaxMin(); + this.InternalUpdateMaxMin(this.Points); + } + + /// + /// The add data points. + /// + /// + /// The points. + /// + protected void AddDataPoints(IList pts) + { + pts.Clear(); + + // Use the mapping to generate the points + if (this.Mapping != null) + { + foreach (var item in this.ItemsSource) + { + pts.Add(this.Mapping(item)); + } + + return; + } + + // Get DataPoints from the items in ItemsSource + // if they implement IDataPointProvider + // If DataFields are set, this is not used + if (this.DataFieldX == null || this.DataFieldY == null) + { + foreach (var item in this.ItemsSource) + { + var dp = item as IDataPoint; + if (dp != null) + { + pts.Add(dp); + continue; + } + + var idpp = item as IDataPointProvider; + if (idpp == null) + { + continue; + } + + pts.Add(idpp.GetDataPoint()); + } + } + else + { + // TODO: is there a better way to do this? + // http://msdn.microsoft.com/en-us/library/bb613546.aspx + + // Using reflection on DataFieldX and DataFieldY + this.AddDataPoints((IList)pts, this.ItemsSource, this.DataFieldX, this.DataFieldY); + } + } + + /// + /// The add data points. + /// + /// + /// The dest. + /// + /// + /// The items source. + /// + /// + /// The data field x. + /// + /// + /// The data field y. + /// + protected void AddDataPoints(IList dest, IEnumerable itemsSource, string dataFieldX, string dataFieldY) + { + PropertyInfo pix = null; + PropertyInfo piy = null; + Type t = null; + + foreach (var o in itemsSource) + { + if (pix == null || o.GetType() != t) + { + t = o.GetType(); + pix = t.GetProperty(dataFieldX); + piy = t.GetProperty(dataFieldY); + if (pix == null) + { + throw new InvalidOperationException( + string.Format("Could not find data field {0} on type {1}", this.DataFieldX, t)); + } + + if (piy == null) + { + throw new InvalidOperationException( + string.Format("Could not find data field {0} on type {1}", this.DataFieldY, t)); + } + } + + double x = this.ToDouble(pix.GetValue(o, null)); + double y = this.ToDouble(piy.GetValue(o, null)); + + var pp = new DataPoint(x, y); + dest.Add(pp); + } + + //var filler = new ListFiller(); + //filler.Add(dataFieldX, (item, value) => item.X = this.ToDouble(value)); + //filler.Add(dataFieldY, (item, value) => item.Y = this.ToDouble(value)); + //filler.Fill(dest, itemsSource); + } + + /// + /// Updates the Max/Min limits from the specified point list. + /// + /// + /// The points. + /// + protected void InternalUpdateMaxMin(IList pts) + { + if (pts == null || pts.Count == 0) + { + return; + } + + double minx = this.MinX; + double miny = this.MinY; + double maxx = this.MaxX; + double maxy = this.MaxY; + + foreach (var pt in pts) + { + if (!this.IsValidPoint(pt, this.XAxis, this.YAxis)) + { + continue; + } + + double x = pt.X; + double y = pt.Y; + if (x < minx || double.IsNaN(minx)) + { + minx = x; + } + + if (x > maxx || double.IsNaN(maxx)) + { + maxx = x; + } + + if (y < miny || double.IsNaN(miny)) + { + miny = y; + } + + if (y > maxy || double.IsNaN(maxy)) + { + maxy = y; + } + } + + this.MinX = minx; + this.MinY = miny; + this.MaxX = maxx; + this.MaxY = maxy; + } + } +} \ No newline at end of file diff -r 88d699a65cc2 -r 5be8f2773237 External/OxyPlot/OxyPlot/Series/DataSeries.cs --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/External/OxyPlot/OxyPlot/Series/DataSeries.cs Sat Jun 08 16:53:22 2013 +0000 @@ -0,0 +1,391 @@ +// -------------------------------------------------------------------------------------------------------------------- +// +// The MIT License (MIT) +// +// Copyright (c) 2012 Oystein Bjorke +// +// Permission is hereby granted, free of charge, to any person obtaining a +// copy of this software and associated documentation files (the +// "Software"), to deal in the Software without restriction, including +// without limitation the rights to use, copy, modify, merge, publish, +// distribute, sublicense, and/or sell copies of the Software, and to +// permit persons to whom the Software is furnished to do so, subject to +// the following conditions: +// +// The above copyright notice and this permission notice shall be included +// in all copies or substantial portions of the Software. +// +// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS +// OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF +// MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. +// IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY +// CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, +// TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE +// SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. +// +// +// DataPointProvider interface. +// +// -------------------------------------------------------------------------------------------------------------------- +using System; +using System.Collections; +using System.Collections.Generic; +using System.Collections.ObjectModel; +using System.ComponentModel; +using System.Linq; +using System.Reflection; + +namespace OxyPlot +{ + /// + /// DataPointProvider interface. + /// + public interface IDataPointProvider + { + /// + /// Gets the data point. + /// + /// + DataPoint GetDataPoint(); + } + + public abstract class DataSeries : PlotSeriesBase + { + protected IList points; + + protected DataSeries() + { + points = new Collection(); + DataFieldX = "X"; + DataFieldY = "Y"; + CanTrackerInterpolatePoints = false; + } + + /// + /// Gets or sets the items source. + /// + /// The items source. + public IEnumerable ItemsSource { get; set; } + + /// + /// Gets or sets the data field X. + /// + /// The data field X. + public string DataFieldX { get; set; } + + /// + /// Gets or sets the data field Y. + /// + /// The data field Y. + public string DataFieldY { get; set; } + + /// + /// Gets or sets the mapping deleagte. + /// Example: series1.Mapping = item => new DataPoint(((MyType)item).Time,((MyType)item).Value); + /// + /// The mapping. + public Func Mapping { get; set; } + + /// + /// Gets or sets the points. + /// + /// The points. + [Browsable(false)] + public IList Points + { + get { return points; } + set { points = value; } + } + + /// + /// Gets or sets a value indicating whether this is smooth. + /// + /// true if smooth; otherwise, false. + public bool Smooth { get; set; } + + public override void UpdateData() + { + if (ItemsSource == null) + { + return; + } + + points.Clear(); + + // Use the mapping to generate the points + if (Mapping != null) + { + foreach (var item in ItemsSource) + { + points.Add(Mapping(item)); + } + } + + // Get DataPoints from the items in ItemsSource + // if they implement IDataPointProvider + // If DataFields are set, this is not used + if (DataFieldX == null || DataFieldY == null) + { + foreach (var item in ItemsSource) + { + var idpp = item as IDataPointProvider; + if (idpp == null) + { + continue; + } + + points.Add(idpp.GetDataPoint()); + } + + return; + } + + // TODO: is there a better way to do this? + // http://msdn.microsoft.com/en-us/library/bb613546.aspx + + // Using reflection on DataFieldX and DataFieldY + AddDataPoints(points, ItemsSource, DataFieldX, DataFieldY); + } + + /// + /// Converts the value of the specified object to a double precision floating point number. + /// DateTime objects are converted using DateTimeAxis.ToDouble + /// TimeSpan objects are converted using TimeSpanAxis.ToDouble + /// + /// The value. + /// + protected virtual double ToDouble(object value) + { + if (value is DateTime) + { + return DateTimeAxis.ToDouble((DateTime)value); + } + + if (value is TimeSpan) + { + return ((TimeSpan)value).TotalSeconds; + } + + return Convert.ToDouble(value); + } + + /// + /// Updates the max/min from the datapoints. + /// + public override void UpdateMaxMin() + { + base.UpdateMaxMin(); + InternalUpdateMaxMin(points); + } + + /// + /// Gets the point in the dataset that is nearest the specified point. + /// + /// The point. + /// The nearest point (data coordinates). + /// The nearest point (screen coordinates). + /// + public override bool GetNearestPoint(ScreenPoint point, out DataPoint dpn, out ScreenPoint spn) + { + spn = default(ScreenPoint); + dpn = default(DataPoint); + + double minimumDistance = double.MaxValue; + foreach (var p in points) + { + var sp = AxisBase.Transform(p, XAxis, YAxis); + double dx = sp.x - point.x; + double dy = sp.y - point.y; + double d2 = dx * dx + dy * dy; + + if (d2 < minimumDistance) + { + dpn = p; + spn = sp; + minimumDistance = d2; + } + } + + return minimumDistance < double.MaxValue; + } + + /// + /// Gets the point on the curve that is nearest the specified point. + /// + /// The point. + /// The nearest point (data coordinates). + /// The nearest point (screen coordinates). + /// + public override bool GetNearestInterpolatedPoint(ScreenPoint point, out DataPoint dpn, out ScreenPoint spn) + { + spn = default(ScreenPoint); + dpn = default(DataPoint); + + // http://local.wasp.uwa.edu.au/~pbourke/geometry/pointline/ + double minimumDistance = double.MaxValue; + + for (int i = 0; i + 1 < points.Count; i++) + { + var p1 = points[i]; + var p2 = points[i + 1]; + var sp1 = AxisBase.Transform(p1, XAxis, YAxis); + var sp2 = AxisBase.Transform(p2, XAxis, YAxis); + + double sp21X = sp2.x - sp1.x; + double sp21Y = sp2.y - sp1.y; + double u1 = (point.x - sp1.x) * sp21X + (point.y - sp1.y) * sp21Y; + double u2 = sp21X * sp21X + sp21Y * sp21Y; + double ds = sp21X * sp21X + sp21Y * sp21Y; + + if (ds < 4) + { + // if the points are very close, we can get numerical problems, just use the first point... + u1 = 0; u2 = 1; + } + + if (u2 == 0) + { + continue; // P1 && P2 coincident + } + + double u = u1 / u2; + if (u < 0 || u > 1) + { + continue; // outside line + } + + double sx = sp1.x + u * sp21X; + double sy = sp1.y + u * sp21Y; + + double dx = point.x - sx; + double dy = point.y - sy; + double distance = dx * dx + dy * dy; + + if (distance < minimumDistance) + { + double px = p1.x + u * (p2.x - p1.x); + double py = p1.y + u * (p2.y - p1.y); + dpn = new DataPoint(px, py); + spn = new ScreenPoint(sx, sy); + minimumDistance = distance; + } + } + + return minimumDistance < double.MaxValue; + } + + protected void AddDataPoints(ICollection points, IEnumerable itemsSource, string dataFieldX, string dataFieldY) + { + PropertyInfo pix = null; + PropertyInfo piy = null; + Type t = null; + + foreach (var o in itemsSource) + { + if (pix == null || o.GetType() != t) + { + t = o.GetType(); + pix = t.GetProperty(dataFieldX); + piy = t.GetProperty(dataFieldY); + if (pix == null) + { + throw new InvalidOperationException(string.Format("Could not find data field {0} on type {1}", + DataFieldX, t)); + } + + if (piy == null) + { + throw new InvalidOperationException(string.Format("Could not find data field {0} on type {1}", + DataFieldY, t)); + } + } + + var x = ToDouble(pix.GetValue(o, null)); + var y = ToDouble(piy.GetValue(o, null)); + + var pp = new DataPoint(x, y); + points.Add(pp); + } + } + + /// + /// Updates the Max/Min limits from the specified point list. + /// + /// The PTS. + protected void InternalUpdateMaxMin(IList pts) + { + if (pts == null || pts.Count == 0) + { + return; + } + + double minx = MinX; + double miny = MinY; + double maxx = MaxX; + double maxy = MaxY; + + foreach (var pt in pts) + { + if (!IsValidPoint(pt,XAxis,YAxis)) + continue; + if (pt.x < minx || double.IsNaN(minx)) minx = pt.x; + if (pt.x > maxx || double.IsNaN(maxx)) maxx = pt.x; + if (pt.y < miny || double.IsNaN(miny)) miny = pt.y; + if (pt.y > maxy || double.IsNaN(maxy)) maxy = pt.y; + } + + MinX = minx; + MinY = miny; + MaxX = maxx; + MaxY = maxy; + + XAxis.Include(MinX); + XAxis.Include(MaxX); + YAxis.Include(MinY); + YAxis.Include(MaxY); + } + + /// + /// Gets the value from the specified X. + /// + /// The x. + /// + public double? GetValueFromX(double x) + { + for (int i = 0; i + 1 < points.Count; i++) + { + if (IsBetween(x, points[i].x, points[i + 1].x)) + { + return points[i].y + + (points[i + 1].y - points[i].y) / + (points[i + 1].x - points[i].x) * (x - points[i].x); + } + } + + return null; + } + + private static bool IsBetween(double x, double x0, double x1) + { + if (x >= x0 && x <= x1) + { + return true; + } + + if (x >= x1 && x <= x0) + { + return true; + } + + return false; + } + + public virtual bool IsValidPoint(DataPoint pt, IAxis xAxis, IAxis yAxis) + { + return !double.IsNaN(pt.X) && !double.IsInfinity(pt.X) + && !double.IsNaN(pt.Y) && !double.IsInfinity(pt.Y) + && (xAxis!=null && xAxis.IsValidValue(pt.X)) + && (yAxis!=null && yAxis.IsValidValue(pt.Y)); + } + } +} \ No newline at end of file diff -r 88d699a65cc2 -r 5be8f2773237 External/OxyPlot/OxyPlot/Series/FunctionSeries.cs --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/External/OxyPlot/OxyPlot/Series/FunctionSeries.cs Sat Jun 08 16:53:22 2013 +0000 @@ -0,0 +1,157 @@ +// -------------------------------------------------------------------------------------------------------------------- +// +// The MIT License (MIT) +// +// Copyright (c) 2012 Oystein Bjorke +// +// Permission is hereby granted, free of charge, to any person obtaining a +// copy of this software and associated documentation files (the +// "Software"), to deal in the Software without restriction, including +// without limitation the rights to use, copy, modify, merge, publish, +// distribute, sublicense, and/or sell copies of the Software, and to +// permit persons to whom the Software is furnished to do so, subject to +// the following conditions: +// +// The above copyright notice and this permission notice shall be included +// in all copies or substantial portions of the Software. +// +// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS +// OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF +// MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. +// IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY +// CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, +// TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE +// SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. +// +// +// Represents a line series that generates its dataset from a function. +// +// -------------------------------------------------------------------------------------------------------------------- +namespace OxyPlot.Series +{ + using System; + + /// + /// Represents a line series that generates its dataset from a function. + /// + /// + /// Define f(x) and make a plot on the range [x0,x1] or define fx(t) and fy(t) and make a plot on the range [t0,t1]. + /// + public class FunctionSeries : LineSeries + { + /// + /// Initializes a new instance of the class. + /// + public FunctionSeries() + { + } + + /// + /// Initializes a new instance of the class. + /// + /// + /// The function f(x). + /// + /// + /// The start x value. + /// + /// + /// The end x value. + /// + /// + /// The increment in x. + /// + /// + /// The title (optional). + /// + public FunctionSeries(Func f, double x0, double x1, double dx, string title = null) + { + this.Title = title; + for (double x = x0; x <= x1 + (dx * 0.5); x += dx) + { + this.Points.Add(new DataPoint(x, f(x))); + } + } + + /// + /// Initializes a new instance of the class. + /// + /// + /// The function f(x). + /// + /// + /// The start x value. + /// + /// + /// The end x value. + /// + /// + /// The number of points. + /// + /// + /// The title (optional). + /// + public FunctionSeries(Func f, double x0, double x1, int n, string title = null) + : this(f, x0, x1, (x1 - x0) / (n - 1), title) + { + } + + /// + /// Initializes a new instance of the class. + /// + /// + /// The function fx(t). + /// + /// + /// The function fy(t). + /// + /// + /// The t0. + /// + /// + /// The t1. + /// + /// + /// The increment dt. + /// + /// + /// The title. + /// + public FunctionSeries(Func fx, Func fy, double t0, double t1, double dt, string title = null) + { + this.Title = title; + for (double t = t0; t <= t1 + (dt * 0.5); t += dt) + { + this.Points.Add(new DataPoint(fx(t), fy(t))); + } + } + + /// + /// Initializes a new instance of the class. + /// + /// + /// The function fx(t). + /// + /// + /// The function fy(t). + /// + /// + /// The t0. + /// + /// + /// The t1. + /// + /// + /// The number of points. + /// + /// + /// The title. + /// + public FunctionSeries( + Func fx, Func fy, double t0, double t1, int n, string title = null) + : this(fx, fy, t0, t1, (t1 - t0) / (n - 1), title) + { + } + + } +} \ No newline at end of file diff -r 88d699a65cc2 -r 5be8f2773237 External/OxyPlot/OxyPlot/Series/HeatMapSeries.cs --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/External/OxyPlot/OxyPlot/Series/HeatMapSeries.cs Sat Jun 08 16:53:22 2013 +0000 @@ -0,0 +1,238 @@ +// -------------------------------------------------------------------------------------------------------------------- +// +// The MIT License (MIT) +// +// Copyright (c) 2012 Oystein Bjorke +// +// Permission is hereby granted, free of charge, to any person obtaining a +// copy of this software and associated documentation files (the +// "Software"), to deal in the Software without restriction, including +// without limitation the rights to use, copy, modify, merge, publish, +// distribute, sublicense, and/or sell copies of the Software, and to +// permit persons to whom the Software is furnished to do so, subject to +// the following conditions: +// +// The above copyright notice and this permission notice shall be included +// in all copies or substantial portions of the Software. +// +// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS +// OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF +// MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. +// IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY +// CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, +// TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE +// SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. +// +// +// The heat map series. +// +// -------------------------------------------------------------------------------------------------------------------- + +namespace OxyPlot.Series +{ + using System; + using System.Collections.Generic; + using System.Linq; + + using OxyPlot.Axes; + + /// + /// The heat map series. + /// + /// + /// Does not work with Silverlight. Silverlight does not support bitmaps, only PNG and JPG. + /// + public class HeatMapSeries : XYAxisSeries + { + /// + /// The hash code of the current data. + /// + private int dataHash; + + /// + /// The image + /// + private OxyImage image; + + /// + /// Gets or sets the x 0. + /// + public double X0 { get; set; } + + /// + /// Gets or sets the x 1. + /// + public double X1 { get; set; } + + /// + /// Gets or sets the y 0. + /// + public double Y0 { get; set; } + + /// + /// Gets or sets the y 1. + /// + public double Y1 { get; set; } + + /// + /// Gets or sets the data. + /// + public double[,] Data { get; set; } + + /// + /// Gets or sets the minimum value of the dataset. + /// + public double MinValue { get; protected set; } + + /// + /// Gets or sets the maximum value of the dataset. + /// + public double MaxValue { get; protected set; } + + /// + /// Gets or sets the color axis. + /// + /// + /// The color axis. + /// + public ColorAxis ColorAxis { get; protected set; } + + /// + /// Gets or sets the color axis key. + /// + /// The color axis key. + public string ColorAxisKey { get; set; } + + /// + /// Renders the series on the specified render context. + /// + /// + /// The rendering context. + /// + /// + /// The model. + /// + public override void Render(IRenderContext rc, PlotModel model) + { + if (this.Data == null) + { + this.image = null; + return; + } + + int m = this.Data.GetLength(0); + int n = this.Data.GetLength(1); + double dx = (this.X1 - this.X0) / m; + double left = this.X0 - (dx * 0.5); + double right = this.X1 + (dx * 0.5); + double dy = (this.Y1 - this.Y0) / n; + double bottom = this.Y0 - (dy * 0.5); + double top = this.Y1 + (dy * 0.5); + var s00 = this.Transform(left, bottom); + var s11 = this.Transform(right, top); + var rect = OxyRect.Create(s00, s11); + + if (this.image == null || this.Data.GetHashCode() != this.dataHash) + { + this.UpdateImage(); + this.dataHash = this.Data.GetHashCode(); + } + + if (this.image != null) + { + var clip = this.GetClippingRect(); + rc.DrawClippedImage(clip, this.image, rect.Left, rect.Top, rect.Width, rect.Height, 1, true); + } + } + + /// + /// Gets the point on the series that is nearest the specified point. + /// + /// + /// The point. + /// + /// + /// Interpolate the series if this flag is set to true. + /// + /// + /// A TrackerHitResult for the current hit. + /// + public override TrackerHitResult GetNearestPoint(ScreenPoint point, bool interpolate) + { + return null; + } + + /// + /// Ensures that the axes of the series is defined. + /// + protected internal override void EnsureAxes() + { + base.EnsureAxes(); + + this.ColorAxis = + this.PlotModel.GetAxisOrDefault(this.ColorAxisKey, this.PlotModel.DefaultColorAxis) as ColorAxis; + } + + /// + /// Updates the max/minimum values. + /// + protected internal override void UpdateMaxMin() + { + base.UpdateMaxMin(); + + this.MinX = Math.Min(this.X0, this.X1); + this.MaxX = Math.Max(this.X0, this.X1); + + this.MinY = Math.Min(this.Y0, this.Y1); + this.MaxY = Math.Max(this.Y0, this.Y1); + + this.MinValue = this.GetData().Min(); + this.MaxValue = this.GetData().Max(); + + this.XAxis.Include(this.MinX); + this.XAxis.Include(this.MaxX); + + this.YAxis.Include(this.MinY); + this.YAxis.Include(this.MaxY); + + this.ColorAxis.Include(this.MinValue); + this.ColorAxis.Include(this.MaxValue); + } + + /// + /// Gets the data as a sequence (LINQ-friendly). + /// + /// The sequence of data. + protected IEnumerable GetData() + { + int m = this.Data.GetLength(0); + int n = this.Data.GetLength(1); + for (int i = 0; i < m; i++) + { + for (int j = 0; j < n; j++) + { + yield return this.Data[i, j]; + } + } + } + + /// + /// Updates the image. + /// + private void UpdateImage() + { + int m = this.Data.GetLength(0); + int n = this.Data.GetLength(1); + var buffer = new OxyColor[n, m]; + for (int i = 0; i < m; i++) + { + for (int j = 0; j < n; j++) + { + buffer[j, i] = this.ColorAxis.GetColor(this.Data[i, j]); + } + } + + this.image = OxyImage.PngFromArgb(buffer); + } + } +} \ No newline at end of file diff -r 88d699a65cc2 -r 5be8f2773237 External/OxyPlot/OxyPlot/Series/HighLowItem.cs --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/External/OxyPlot/OxyPlot/Series/HighLowItem.cs Sat Jun 08 16:53:22 2013 +0000 @@ -0,0 +1,187 @@ +// -------------------------------------------------------------------------------------------------------------------- +// +// The MIT License (MIT) +// +// Copyright (c) 2012 Oystein Bjorke +// +// Permission is hereby granted, free of charge, to any person obtaining a +// copy of this software and associated documentation files (the +// "Software"), to deal in the Software without restriction, including +// without limitation the rights to use, copy, modify, merge, publish, +// distribute, sublicense, and/or sell copies of the Software, and to +// permit persons to whom the Software is furnished to do so, subject to +// the following conditions: +// +// The above copyright notice and this permission notice shall be included +// in all copies or substantial portions of the Software. +// +// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS +// OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF +// MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. +// IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY +// CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, +// TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE +// SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. +// +// +// Represents an item in a HighLowSeries. +// +// -------------------------------------------------------------------------------------------------------------------- +namespace OxyPlot.Series +{ + /// + /// Represents an item in a . + /// + public class HighLowItem + { + /// + /// The undefined. + /// + public static readonly HighLowItem Undefined = new HighLowItem(double.NaN, double.NaN, double.NaN); + + /// + /// The close. + /// + private double close; + + /// + /// The high. + /// + private double high; + + /// + /// The low. + /// + private double low; + + /// + /// The open. + /// + private double open; + + /// + /// The x. + /// + private double x; + + /// + /// Initializes a new instance of the class. + /// + public HighLowItem() + { + } + + /// + /// Initializes a new instance of the struct. + /// + /// + /// The x value. + /// + /// + /// The high value. + /// + /// + /// The low value. + /// + /// + /// The open value. + /// + /// + /// The close value. + /// + public HighLowItem(double x, double high, double low, double open = double.NaN, double close = double.NaN) + { + this.x = x; + this.high = high; + this.low = low; + this.open = open; + this.close = close; + } + + /// + /// Gets or sets the close value. + /// + /// The close value. + public double Close + { + get + { + return this.close; + } + + set + { + this.close = value; + } + } + + /// + /// Gets or sets the high value. + /// + /// The high value. + public double High + { + get + { + return this.high; + } + + set + { + this.high = value; + } + } + + /// + /// Gets or sets the low value. + /// + /// The low value. + public double Low + { + get + { + return this.low; + } + + set + { + this.low = value; + } + } + + /// + /// Gets or sets the open value. + /// + /// The open value. + public double Open + { + get + { + return this.open; + } + + set + { + this.open = value; + } + } + + /// + /// Gets or sets the X value (time). + /// + /// The X value. + public double X + { + get + { + return this.x; + } + + set + { + this.x = value; + } + } + + } +} \ No newline at end of file diff -r 88d699a65cc2 -r 5be8f2773237 External/OxyPlot/OxyPlot/Series/HighLowSeries.cs --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/External/OxyPlot/OxyPlot/Series/HighLowSeries.cs Sat Jun 08 16:53:22 2013 +0000 @@ -0,0 +1,502 @@ +// -------------------------------------------------------------------------------------------------------------------- +// +// The MIT License (MIT) +// +// Copyright (c) 2012 Oystein Bjorke +// +// Permission is hereby granted, free of charge, to any person obtaining a +// copy of this software and associated documentation files (the +// "Software"), to deal in the Software without restriction, including +// without limitation the rights to use, copy, modify, merge, publish, +// distribute, sublicense, and/or sell copies of the Software, and to +// permit persons to whom the Software is furnished to do so, subject to +// the following conditions: +// +// The above copyright notice and this permission notice shall be included +// in all copies or substantial portions of the Software. +// +// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS +// OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF +// MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. +// IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY +// CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, +// TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE +// SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. +// +// +// Represents a series for high-low plots. +// +// -------------------------------------------------------------------------------------------------------------------- +namespace OxyPlot.Series +{ + using System; + using System.Collections.Generic; + + using OxyPlot.Axes; + + /// + /// Represents a series for high-low plots. + /// + /// + /// See http://www.mathworks.com/help/toolbox/finance/highlowfts.html + /// + public class HighLowSeries : XYAxisSeries + { + /// + /// High/low items + /// + private IList items; + + /// + /// The default color. + /// + private OxyColor defaultColor; + + /// + /// Initializes a new instance of the class. + /// + public HighLowSeries() + { + this.items = new List(); + this.TickLength = 4; + this.StrokeThickness = 1; + this.TrackerFormatString = "X: {1:0.00}\nHigh: {2:0.00}\nLow: {3:0.00}\nOpen: {4:0.00}\nClose: {5:0.00}"; + } + + /// + /// Initializes a new instance of the class. + /// + /// + /// The title. + /// + public HighLowSeries(string title) + : this() + { + this.Title = title; + } + + /// + /// Initializes a new instance of the class. + /// + /// + /// The color. + /// + /// + /// The stroke thickness. + /// + /// + /// The title. + /// + public HighLowSeries(OxyColor color, double strokeThickness = 1, string title = null) + : this() + { + this.Color = color; + this.StrokeThickness = strokeThickness; + this.Title = title; + } + + /// + /// Gets or sets the color of the curve. + /// + /// The color. + public OxyColor Color { get; set; } + + /// + /// Gets the actual color. + /// + /// The actual color. + public OxyColor ActualColor + { + get { return this.Color ?? this.defaultColor; } + } + + /// + /// Gets or sets the dashes array. + /// If this is not null it overrides the LineStyle property. + /// + /// The dashes. + public double[] Dashes { get; set; } + + /// + /// Gets or sets the data field for the Close value. + /// + public string DataFieldClose { get; set; } + + /// + /// Gets or sets the data field for the High value. + /// + public string DataFieldHigh { get; set; } + + /// + /// Gets or sets the data field for the Low value. + /// + public string DataFieldLow { get; set; } + + /// + /// Gets or sets the data field for the Open value. + /// + public string DataFieldOpen { get; set; } + + /// + /// Gets or sets the x data field (time). + /// + public string DataFieldX { get; set; } + + /// + /// Gets or sets the points. + /// + /// The points. + public IList Items + { + get + { + return this.items; + } + + set + { + this.items = value; + } + } + + /// + /// Gets or sets the line join. + /// + /// The line join. + public OxyPenLineJoin LineJoin { get; set; } + + /// + /// Gets or sets the line style. + /// + /// The line style. + public LineStyle LineStyle { get; set; } + + /// + /// Gets or sets the mapping deleagte. + /// Example: series1.Mapping = item => new HighLowItem(((MyType)item).Time,((MyType)item).Value); + /// + /// The mapping. + public Func Mapping { get; set; } + + /// + /// Gets or sets the thickness of the curve. + /// + /// The stroke thickness. + public double StrokeThickness { get; set; } + + /// + /// Gets or sets the length of the open/close ticks (screen coordinates). + /// + /// The length of the open/close ticks. + public double TickLength { get; set; } + + /// + /// Gets the point on the series that is nearest the specified point. + /// + /// The point. + /// Interpolate the series if this flag is set to true. + /// + /// A TrackerHitResult for the current hit. + /// + public override TrackerHitResult GetNearestPoint(ScreenPoint point, bool interpolate) + { + if (this.XAxis == null || this.YAxis == null) + { + return null; + } + + if (interpolate) + { + return null; + } + + double minimumDistance = double.MaxValue; + var result = new TrackerHitResult(this, DataPoint.Undefined, ScreenPoint.Undefined); + + Action check = (p, item, index) => + { + var sp = this.Transform(p); + double dx = sp.x - point.x; + double dy = sp.y - point.y; + double d2 = (dx * dx) + (dy * dy); + + if (d2 < minimumDistance) + { + result.DataPoint = p; + result.Position = sp; + result.Item = item; + result.Index = index; + if (this.TrackerFormatString != null) + { + result.Text = StringHelper.Format( + this.ActualCulture, + this.TrackerFormatString, + item, + this.Title, + this.XAxis.GetValue(p.X), + item.High, + item.Low, + item.Open, + item.Close); + } + + minimumDistance = d2; + } + }; + int i = 0; + foreach (var item in this.items) + { + check(new DataPoint(item.X, item.High), item, i); + check(new DataPoint(item.X, item.Low), item, i); + check(new DataPoint(item.X, item.Open), item, i); + check(new DataPoint(item.X, item.Close), item, i++); + } + + if (minimumDistance < double.MaxValue) + { + return result; + } + + return null; + } + + /// + /// Determines whether the point is valid. + /// + /// The point. + /// The x axis. + /// The y axis. + /// + /// true if [is valid point] [the specified pt]; otherwise, false. + /// + public virtual bool IsValidItem(HighLowItem pt, Axis xaxis, Axis yaxis) + { + return !double.IsNaN(pt.X) && !double.IsInfinity(pt.X) && !double.IsNaN(pt.High) + && !double.IsInfinity(pt.High) && !double.IsNaN(pt.Low) && !double.IsInfinity(pt.Low); + } + + /// + /// Renders the series on the specified rendering context. + /// + /// + /// The rendering context. + /// + /// + /// The owner plot model. + /// + public override void Render(IRenderContext rc, PlotModel model) + { + if (this.items.Count == 0) + { + return; + } + + this.VerifyAxes(); + + var clippingRect = this.GetClippingRect(); + + foreach (var v in this.items) + { + if (!this.IsValidItem(v, this.XAxis, this.YAxis)) + { + continue; + } + + if (this.StrokeThickness > 0 && this.LineStyle != LineStyle.None) + { + ScreenPoint high = this.Transform(v.X, v.High); + ScreenPoint low = this.Transform(v.X, v.Low); + + rc.DrawClippedLine( + new[] { low, high }, + clippingRect, + 0, + this.GetSelectableColor(this.ActualColor), + this.StrokeThickness, + this.LineStyle, + this.LineJoin, + true); + if (!double.IsNaN(v.Open)) + { + ScreenPoint open = this.Transform(v.X, v.Open); + ScreenPoint openTick = open; + openTick.X -= this.TickLength; + rc.DrawClippedLine( + new[] { open, openTick }, + clippingRect, + 0, + this.GetSelectableColor(this.ActualColor), + this.StrokeThickness, + this.LineStyle, + this.LineJoin, + true); + } + + if (!double.IsNaN(v.Close)) + { + ScreenPoint close = this.Transform(v.X, v.Close); + ScreenPoint closeTick = close; + closeTick.X += this.TickLength; + rc.DrawClippedLine( + new[] { close, closeTick }, + clippingRect, + 0, + this.GetSelectableColor(this.ActualColor), + this.StrokeThickness, + this.LineStyle, + this.LineJoin, + true); + } + } + } + } + + /// + /// Renders the legend symbol for the series on the specified rendering context. + /// + /// + /// The rendering context. + /// + /// + /// The bounding rectangle of the legend box. + /// + public override void RenderLegend(IRenderContext rc, OxyRect legendBox) + { + double xmid = (legendBox.Left + legendBox.Right) / 2; + double yopen = legendBox.Top + ((legendBox.Bottom - legendBox.Top) * 0.7); + double yclose = legendBox.Top + ((legendBox.Bottom - legendBox.Top) * 0.3); + double[] dashArray = LineStyleHelper.GetDashArray(this.LineStyle); + var color = this.GetSelectableColor(this.ActualColor); + rc.DrawLine( + new[] { new ScreenPoint(xmid, legendBox.Top), new ScreenPoint(xmid, legendBox.Bottom) }, + color, + this.StrokeThickness, + dashArray, + OxyPenLineJoin.Miter, + true); + rc.DrawLine( + new[] { new ScreenPoint(xmid - this.TickLength, yopen), new ScreenPoint(xmid, yopen) }, + color, + this.StrokeThickness, + dashArray, + OxyPenLineJoin.Miter, + true); + rc.DrawLine( + new[] { new ScreenPoint(xmid + this.TickLength, yclose), new ScreenPoint(xmid, yclose) }, + color, + this.StrokeThickness, + dashArray, + OxyPenLineJoin.Miter, + true); + } + + /// + /// Sets the default values. + /// + /// + /// The model. + /// + protected internal override void SetDefaultValues(PlotModel model) + { + if (this.Color == null) + { + this.LineStyle = model.GetDefaultLineStyle(); + this.defaultColor = model.GetDefaultColor(); + } + } + + /// + /// Updates the data. + /// + protected internal override void UpdateData() + { + if (this.ItemsSource == null) + { + return; + } + + this.items.Clear(); + + // Use the mapping to generate the points + if (this.Mapping != null) + { + foreach (var item in this.ItemsSource) + { + this.items.Add(this.Mapping(item)); + } + + return; + } + + var filler = new ListFiller(); + filler.Add(this.DataFieldX, (p, v) => p.X = this.ToDouble(v)); + filler.Add(this.DataFieldHigh, (p, v) => p.High = this.ToDouble(v)); + filler.Add(this.DataFieldLow, (p, v) => p.Low = this.ToDouble(v)); + filler.Add(this.DataFieldOpen, (p, v) => p.Open = this.ToDouble(v)); + filler.Add(this.DataFieldClose, (p, v) => p.Close = this.ToDouble(v)); + filler.FillT(this.items, this.ItemsSource); + } + + /// + /// Updates the max/min values. + /// + protected internal override void UpdateMaxMin() + { + base.UpdateMaxMin(); + this.InternalUpdateMaxMin(this.items); + } + + /// + /// Updates the Max/Min limits from the specified point list. + /// + /// + /// The PTS. + /// + protected void InternalUpdateMaxMin(IList pts) + { + if (pts == null || pts.Count == 0) + { + return; + } + + double minx = this.MinX; + double miny = this.MinY; + double maxx = this.MaxX; + double maxy = this.MaxY; + + foreach (var pt in pts) + { + if (!this.IsValidItem(pt, this.XAxis, this.YAxis)) + { + continue; + } + + if (pt.X < minx || double.IsNaN(minx)) + { + minx = pt.X; + } + + if (pt.X > maxx || double.IsNaN(maxx)) + { + maxx = pt.X; + } + + if (pt.Low < miny || double.IsNaN(miny)) + { + miny = pt.Low; + } + + if (pt.High > maxy || double.IsNaN(maxy)) + { + maxy = pt.High; + } + } + + this.MinX = minx; + this.MinY = miny; + this.MaxX = maxx; + this.MaxY = maxy; + } + + } +} \ No newline at end of file diff -r 88d699a65cc2 -r 5be8f2773237 External/OxyPlot/OxyPlot/Series/ITrackableSeries.cs --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/External/OxyPlot/OxyPlot/Series/ITrackableSeries.cs Sat Jun 08 16:53:22 2013 +0000 @@ -0,0 +1,67 @@ +// -------------------------------------------------------------------------------------------------------------------- +// +// The MIT License (MIT) +// +// Copyright (c) 2012 Oystein Bjorke +// +// Permission is hereby granted, free of charge, to any person obtaining a +// copy of this software and associated documentation files (the +// "Software"), to deal in the Software without restriction, including +// without limitation the rights to use, copy, modify, merge, publish, +// distribute, sublicense, and/or sell copies of the Software, and to +// permit persons to whom the Software is furnished to do so, subject to +// the following conditions: +// +// The above copyright notice and this permission notice shall be included +// in all copies or substantial portions of the Software. +// +// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS +// OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF +// MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. +// IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY +// CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, +// TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE +// SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. +// +// +// Interface for Series that can be 'tracked' +// +// -------------------------------------------------------------------------------------------------------------------- +namespace OxyPlot.Series +{ + /// + /// Provides functionality to return data for a tracker control. + /// + /// + /// The plot control will show a tracker with the current value when moving the mouse over the data. + /// + public interface ITrackableSeries + { + /// + /// Gets a format string used for the tracker. + /// + /// + /// The fields that can be used in the format string depends on the series. + /// + string TrackerFormatString { get; } + + /// + /// Gets the tracker key. + /// + string TrackerKey { get; } + + /// + /// Gets the point on the series that is nearest the specified point. + /// + /// + /// The point. + /// + /// + /// Interpolate the series if this flag is set to true. + /// + /// + /// A TrackerHitResult for the current hit. + /// + TrackerHitResult GetNearestPoint(ScreenPoint point, bool interpolate); + } +} \ No newline at end of file diff -r 88d699a65cc2 -r 5be8f2773237 External/OxyPlot/OxyPlot/Series/ItemsSeries.cs --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/External/OxyPlot/OxyPlot/Series/ItemsSeries.cs Sat Jun 08 16:53:22 2013 +0000 @@ -0,0 +1,96 @@ +// -------------------------------------------------------------------------------------------------------------------- +// +// The MIT License (MIT) +// +// Copyright (c) 2012 Oystein Bjorke +// +// Permission is hereby granted, free of charge, to any person obtaining a +// copy of this software and associated documentation files (the +// "Software"), to deal in the Software without restriction, including +// without limitation the rights to use, copy, modify, merge, publish, +// distribute, sublicense, and/or sell copies of the Software, and to +// permit persons to whom the Software is furnished to do so, subject to +// the following conditions: +// +// The above copyright notice and this permission notice shall be included +// in all copies or substantial portions of the Software. +// +// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS +// OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF +// MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. +// IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY +// CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, +// TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE +// SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. +// +// +// Abstract base class for series that can contain items. +// +// -------------------------------------------------------------------------------------------------------------------- +namespace OxyPlot.Series +{ + using System.Collections; + using System.Linq; + + /// + /// Abstract base class for series that can contain items. + /// + public abstract class ItemsSeries : Series + { + /// + /// Gets or sets the items source. + /// + /// The items source. + [CodeGeneration(false)] + public IEnumerable ItemsSource { get; set; } + + /// + /// Updates the valid items + /// + protected internal override void UpdateValidData() + { + } + + /// + /// Gets the item for the specified index. + /// + /// The items source. + /// The index. + /// The get item. + /// + /// Returns null if ItemsSource is not set, or the index is outside the boundaries. + /// + protected static object GetItem(IEnumerable itemsSource, int index) + { + if (itemsSource == null || index < 0) + { + return null; + } + + var list = itemsSource as IList; + if (list != null) + { + if (index < list.Count && index >= 0) + { + return list[index]; + } + + return null; + } + + var i = 0; + return itemsSource.Cast().FirstOrDefault(item => i++ == index); + } + + /// + /// Gets the item at the specified index. + /// + /// The index of the item. + /// The item of the index. + protected virtual object GetItem(int i) + { + return GetItem(this.ItemsSource, i); + } + + } +} \ No newline at end of file diff -r 88d699a65cc2 -r 5be8f2773237 External/OxyPlot/OxyPlot/Series/LineLegendPosition.cs --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/External/OxyPlot/OxyPlot/Series/LineLegendPosition.cs Sat Jun 08 16:53:22 2013 +0000 @@ -0,0 +1,52 @@ +// -------------------------------------------------------------------------------------------------------------------- +// +// The MIT License (MIT) +// +// Copyright (c) 2012 Oystein Bjorke +// +// Permission is hereby granted, free of charge, to any person obtaining a +// copy of this software and associated documentation files (the +// "Software"), to deal in the Software without restriction, including +// without limitation the rights to use, copy, modify, merge, publish, +// distribute, sublicense, and/or sell copies of the Software, and to +// permit persons to whom the Software is furnished to do so, subject to +// the following conditions: +// +// The above copyright notice and this permission notice shall be included +// in all copies or substantial portions of the Software. +// +// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS +// OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF +// MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. +// IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY +// CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, +// TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE +// SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. +// +// +// Specifies the position of legends rendered on a line series. +// +// -------------------------------------------------------------------------------------------------------------------- +namespace OxyPlot.Series +{ + /// + /// Specifies the position of legends rendered on a . + /// + public enum LineLegendPosition + { + /// + /// Do not render legend on the line. + /// + None, + + /// + /// Render legend at the start of the line. + /// + Start, + + /// + /// Render legend at the end of the line. + /// + End + } +} \ No newline at end of file diff -r 88d699a65cc2 -r 5be8f2773237 External/OxyPlot/OxyPlot/Series/LineSeries.cs --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/External/OxyPlot/OxyPlot/Series/LineSeries.cs Sat Jun 08 16:53:22 2013 +0000 @@ -0,0 +1,644 @@ +// -------------------------------------------------------------------------------------------------------------------- +// +// The MIT License (MIT) +// +// Copyright (c) 2012 Oystein Bjorke +// +// Permission is hereby granted, free of charge, to any person obtaining a +// copy of this software and associated documentation files (the +// "Software"), to deal in the Software without restriction, including +// without limitation the rights to use, copy, modify, merge, publish, +// distribute, sublicense, and/or sell copies of the Software, and to +// permit persons to whom the Software is furnished to do so, subject to +// the following conditions: +// +// The above copyright notice and this permission notice shall be included +// in all copies or substantial portions of the Software. +// +// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS +// OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF +// MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. +// IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY +// CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, +// TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE +// SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. +// +// +// Represents a line series. +// +// -------------------------------------------------------------------------------------------------------------------- + +namespace OxyPlot.Series +{ + using System; + using System.Collections.Generic; + + /// + /// Represents a line series. + /// + public class LineSeries : DataPointSeries + { + /// + /// The divisor value used to calculate tolerance for line smoothing. + /// + private const double ToleranceDivisor = 200; + + /// + /// The default color. + /// + private OxyColor defaultColor; + + /// + /// The smoothed points. + /// + private IList smoothedPoints; + + /// + /// Initializes a new instance of the class. + /// + public LineSeries() + { + this.MinimumSegmentLength = 2; + this.StrokeThickness = 2; + this.LineJoin = OxyPenLineJoin.Bevel; + this.LineStyle = LineStyle.Undefined; + this.MarkerSize = 3; + this.MarkerStrokeThickness = 1; + this.CanTrackerInterpolatePoints = true; + this.LabelMargin = 6; + } + + /// + /// Initializes a new instance of the class. + /// + /// + /// The title. + /// + public LineSeries(string title) + : this() + { + this.Title = title; + } + + /// + /// Initializes a new instance of the class. + /// + /// + /// The color of the line stroke. + /// + /// + /// The stroke thickness (optional). + /// + /// + /// The title (optional). + /// + public LineSeries(OxyColor color, double strokeThickness = 1, string title = null) + : this() + { + this.Color = color; + this.StrokeThickness = strokeThickness; + this.BrokenLineThickness = 0; + this.Title = title; + } + + /// + /// Gets or sets the color of the curve. + /// + /// The color. + public OxyColor Color { get; set; } + + /// + /// Gets or sets the color of the broken line segments. + /// + /// + /// Add DataPoint.Undefined in the Points collection to create breaks in the line. + /// + public OxyColor BrokenLineColor { get; set; } + + /// + /// Gets or sets the broken line style. + /// + public LineStyle BrokenLineStyle { get; set; } + + /// + /// Gets or sets the broken line thickness. + /// + public double BrokenLineThickness { get; set; } + + /// + /// Gets or sets the dashes array. + /// If this is not null it overrides the LineStyle property. + /// + /// The dashes. + public double[] Dashes { get; set; } + + /// + /// Gets or sets the label format string. + /// + /// The label format string. + public string LabelFormatString { get; set; } + + /// + /// Gets or sets the label margins. + /// + public double LabelMargin { get; set; } + + /// + /// Gets or sets the line join. + /// + /// The line join. + public OxyPenLineJoin LineJoin { get; set; } + + /// + /// Gets or sets the line style. + /// + /// The line style. + public LineStyle LineStyle { get; set; } + + /// + /// Gets or sets a value specifying the position of a legend rendered on the line. + /// + /// A value specifying the position of the legend. + public LineLegendPosition LineLegendPosition { get; set; } + + /// + /// Gets or sets the marker fill color. + /// + /// The marker fill. + public OxyColor MarkerFill { get; set; } + + /// + /// Gets or sets the marker outline polygon. + /// If this property is set, the MarkerType will not be used. + /// + /// The marker outline. + public ScreenPoint[] MarkerOutline { get; set; } + + /// + /// Gets or sets the size of the marker. + /// + /// The size of the marker. + public double MarkerSize { get; set; } + + /// + /// Gets or sets the marker stroke. + /// + /// The marker stroke. + public OxyColor MarkerStroke { get; set; } + + /// + /// Gets or sets the marker stroke thickness. + /// + /// The marker stroke thickness. + public double MarkerStrokeThickness { get; set; } + + /// + /// Gets or sets the type of the marker. + /// + /// The type of the marker. + /// + /// If MarkerType.Custom is used, the MarkerOutline property must be specified. + /// + public MarkerType MarkerType { get; set; } + + /// + /// Gets or sets the minimum length of the segment. + /// Increasing this number will increase performance, + /// but make the curve less accurate. + /// + /// The minimum length of the segment. + public double MinimumSegmentLength { get; set; } + + /// + /// Gets or sets the thickness of the curve. + /// + /// The stroke thickness. + public double StrokeThickness { get; set; } + + /// + /// Gets the actual color. + /// + /// The actual color. + protected OxyColor ActualColor + { + get + { + return this.Color ?? this.defaultColor; + } + } + + /// + /// Gets the actual line style. + /// + /// + /// The actual line style. + /// + protected LineStyle ActualLineStyle + { + get + { + return this.LineStyle != LineStyle.Undefined ? this.LineStyle : LineStyle.Solid; + } + } + + /// + /// Gets the smoothed points. + /// + /// The smoothed points. + protected IList SmoothedPoints + { + get + { + return this.smoothedPoints; + } + } + + /// + /// Gets the point on the series that is nearest the specified point. + /// + /// The point. + /// Interpolate the series if this flag is set to true. + /// + /// A TrackerHitResult for the current hit. + /// + public override TrackerHitResult GetNearestPoint(ScreenPoint point, bool interpolate) + { + if (interpolate) + { + // Cannot interpolate if there is no line + if (this.ActualColor == null || this.StrokeThickness.IsZero()) + { + return null; + } + + if (!this.CanTrackerInterpolatePoints) + { + return null; + } + } + + if (interpolate && this.Smooth && this.SmoothedPoints != null) + { + return this.GetNearestInterpolatedPointInternal(this.SmoothedPoints, point); + } + + return base.GetNearestPoint(point, interpolate); + } + + /// + /// Renders the series on the specified rendering context. + /// + /// + /// The rendering context. + /// + /// + /// The owner plot model. + /// + public override void Render(IRenderContext rc, PlotModel model) + { + if (this.Points.Count == 0) + { + return; + } + + this.VerifyAxes(); + + var clippingRect = this.GetClippingRect(); + var transformedPoints = new List(); + var lineBreakSegments = new List(); + + ScreenPoint lastValidPoint = default(ScreenPoint); + bool isBroken = false; + var renderBrokenLineSegments = this.BrokenLineThickness > 0 && this.BrokenLineStyle != LineStyle.None; + + // Transform all points to screen coordinates + // Render the line when invalid points occur + foreach (var point in this.Points) + { + if (!this.IsValidPoint(point, this.XAxis, this.YAxis)) + { + this.RenderPoints(rc, clippingRect, transformedPoints); + transformedPoints.Clear(); + isBroken = true; + continue; + } + + var pt = this.XAxis.Transform(point.X, point.Y, this.YAxis); + transformedPoints.Add(pt); + + if (renderBrokenLineSegments) + { + if (isBroken) + { + lineBreakSegments.Add(lastValidPoint); + lineBreakSegments.Add(pt); + isBroken = false; + } + + lastValidPoint = pt; + } + } + + // Render the remaining points + this.RenderPoints(rc, clippingRect, transformedPoints); + + if (renderBrokenLineSegments) + { + // Render line breaks + rc.DrawClippedLineSegments( + lineBreakSegments, + clippingRect, + this.BrokenLineColor, + this.BrokenLineThickness, + this.BrokenLineStyle, + this.LineJoin, + false); + } + + if (this.LabelFormatString != null) + { + // render point labels (not optimized for performance) + this.RenderPointLabels(rc, clippingRect); + } + + if (this.LineLegendPosition != LineLegendPosition.None && this.Points.Count > 0 + && !string.IsNullOrEmpty(this.Title)) + { + // renders a legend on the line + this.RenderLegendOnLine(rc, clippingRect); + } + } + + /// + /// Renders the legend symbol for the line series on the + /// specified rendering context. + /// + /// + /// The rendering context. + /// + /// + /// The bounding rectangle of the legend box. + /// + public override void RenderLegend(IRenderContext rc, OxyRect legendBox) + { + double xmid = (legendBox.Left + legendBox.Right) / 2; + double ymid = (legendBox.Top + legendBox.Bottom) / 2; + var pts = new[] { new ScreenPoint(legendBox.Left, ymid), new ScreenPoint(legendBox.Right, ymid) }; + rc.DrawLine( + pts, + this.GetSelectableColor(this.ActualColor), + this.StrokeThickness, + this.ActualLineStyle.GetDashArray()); + var midpt = new ScreenPoint(xmid, ymid); + rc.DrawMarker( + midpt, + legendBox, + this.MarkerType, + this.MarkerOutline, + this.MarkerSize, + this.MarkerFill, + this.MarkerStroke, + this.MarkerStrokeThickness); + } + + /// + /// The set default values. + /// + /// + /// The model. + /// + protected internal override void SetDefaultValues(PlotModel model) + { + // todo: should use ActualLineStyle + if (this.Color == null) + { + if (this.LineStyle == LineStyle.Undefined) + { + this.LineStyle = model.GetDefaultLineStyle(); + } + + this.defaultColor = model.GetDefaultColor(); + + // And MarkerFill will be overridden if not set to null + if (this.MarkerFill == null) + { + this.MarkerFill = this.defaultColor; + } + } + } + + /// + /// Updates the axes to include the max and min of this series. + /// + protected internal override void UpdateMaxMin() + { + if (this.Smooth) + { + // Update the max/min from the control points + base.UpdateMaxMin(); + + // Make sure the smooth points are re-evaluated. + this.ResetSmoothedPoints(); + + // Update the max/min from the smoothed points + foreach (var pt in this.SmoothedPoints) + { + this.MinX = Math.Min(this.MinX, pt.X); + this.MinY = Math.Min(this.MinY, pt.Y); + this.MaxX = Math.Max(this.MaxX, pt.X); + this.MaxY = Math.Max(this.MaxY, pt.Y); + } + } + else + { + base.UpdateMaxMin(); + } + } + + /// + /// Renders the point labels. + /// + /// The render context. + /// The clipping rectangle. + protected void RenderPointLabels(IRenderContext rc, OxyRect clippingRect) + { + int index = -1; + foreach (var point in this.Points) + { + index++; + + if (!this.IsValidPoint(point, this.XAxis, this.YAxis)) + { + continue; + } + + var pt = this.XAxis.Transform(point.X, point.Y, this.YAxis); + pt.Y -= this.LabelMargin; + + if (!clippingRect.Contains(pt)) + { + continue; + } + + var s = StringHelper.Format( + this.ActualCulture, this.LabelFormatString, this.GetItem(index), point.X, point.Y); + +#if SUPPORTLABELPLACEMENT + switch (this.LabelPlacement) + { + case LabelPlacement.Inside: + pt = new ScreenPoint(rect.Right - this.LabelMargin, (rect.Top + rect.Bottom) / 2); + ha = HorizontalAlignment.Right; + break; + case LabelPlacement.Middle: + pt = new ScreenPoint((rect.Left + rect.Right) / 2, (rect.Top + rect.Bottom) / 2); + ha = HorizontalAlignment.Center; + break; + case LabelPlacement.Base: + pt = new ScreenPoint(rect.Left + this.LabelMargin, (rect.Top + rect.Bottom) / 2); + ha = HorizontalAlignment.Left; + break; + default: // Outside + pt = new ScreenPoint(rect.Right + this.LabelMargin, (rect.Top + rect.Bottom) / 2); + ha = HorizontalAlignment.Left; + break; + } +#endif + + rc.DrawClippedText( + clippingRect, + pt, + s, + this.ActualTextColor, + this.ActualFont, + this.ActualFontSize, + this.ActualFontWeight, + 0, + HorizontalAlignment.Center, + VerticalAlignment.Bottom); + } + } + + /// + /// Renders a legend on the line. + /// + /// The render context. + /// The clipping rectangle. + protected void RenderLegendOnLine(IRenderContext rc, OxyRect clippingRect) + { + // Find the position + IDataPoint point; + var ha = HorizontalAlignment.Left; + double dx; + switch (this.LineLegendPosition) + { + case LineLegendPosition.Start: + + // start position + point = this.Points[0]; + ha = HorizontalAlignment.Right; + dx = -4; + break; + default: + + // end position + point = this.Points[this.Points.Count - 1]; + dx = 4; + break; + } + + var pt = this.XAxis.Transform(point.X, point.Y, this.YAxis); + pt.X += dx; + + // Render the legend + rc.DrawClippedText( + clippingRect, + pt, + this.Title, + this.ActualTextColor, + this.ActualFont, + this.ActualFontSize, + this.ActualFontWeight, + 0, + ha, + VerticalAlignment.Middle); + } + + /// + /// Renders the transformed points. + /// + /// + /// The render context. + /// + /// + /// The clipping rectangle. + /// + /// + /// The points to render. + /// + protected void RenderPoints(IRenderContext rc, OxyRect clippingRect, IList pointsToRender) + { + var screenPoints = pointsToRender; + if (this.Smooth) + { + // spline smoothing (should only be used on small datasets) + var resampledPoints = ScreenPointHelper.ResamplePoints(pointsToRender, this.MinimumSegmentLength); + screenPoints = CanonicalSplineHelper.CreateSpline(resampledPoints, 0.5, null, false, 0.25); + } + + // clip the line segments with the clipping rectangle + if (this.StrokeThickness > 0 && this.ActualLineStyle != LineStyle.None) + { + this.RenderSmoothedLine(rc, clippingRect, screenPoints); + } + + if (this.MarkerType != MarkerType.None) + { + rc.DrawMarkers( + pointsToRender, + clippingRect, + this.MarkerType, + this.MarkerOutline, + new[] { this.MarkerSize }, + this.MarkerFill, + this.MarkerStroke, + this.MarkerStrokeThickness); + } + } + + /// + /// Renders the (smoothed) line. + /// + /// + /// The render context. + /// + /// + /// The clipping rectangle. + /// + /// + /// The points to render. + /// + protected virtual void RenderSmoothedLine( + IRenderContext rc, OxyRect clippingRect, IList pointsToRender) + { + rc.DrawClippedLine( + pointsToRender, + clippingRect, + this.MinimumSegmentLength * this.MinimumSegmentLength, + this.GetSelectableColor(this.ActualColor), + this.StrokeThickness, + this.ActualLineStyle, + this.LineJoin, + false); + } + + /// + /// Force the smoothed points to be re-evaluated. + /// + protected void ResetSmoothedPoints() + { + double tolerance = Math.Abs(Math.Max(this.MaxX - this.MinX, this.MaxY - this.MinY) / ToleranceDivisor); + this.smoothedPoints = CanonicalSplineHelper.CreateSpline(this.Points, 0.5, null, false, tolerance); + } + } +} \ No newline at end of file diff -r 88d699a65cc2 -r 5be8f2773237 External/OxyPlot/OxyPlot/Series/PieSeries.cs --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/External/OxyPlot/OxyPlot/Series/PieSeries.cs Sat Jun 08 16:53:22 2013 +0000 @@ -0,0 +1,481 @@ +// -------------------------------------------------------------------------------------------------------------------- +// +// The MIT License (MIT) +// +// Copyright (c) 2012 Oystein Bjorke +// +// Permission is hereby granted, free of charge, to any person obtaining a +// copy of this software and associated documentation files (the +// "Software"), to deal in the Software without restriction, including +// without limitation the rights to use, copy, modify, merge, publish, +// distribute, sublicense, and/or sell copies of the Software, and to +// permit persons to whom the Software is furnished to do so, subject to +// the following conditions: +// +// The above copyright notice and this permission notice shall be included +// in all copies or substantial portions of the Software. +// +// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS +// OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF +// MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. +// IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY +// CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, +// TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE +// SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. +// +// +// Represents a series for pie/circle/doughnut charts. +// +// -------------------------------------------------------------------------------------------------------------------- +namespace OxyPlot.Series +{ + using System; + using System.Collections.Generic; + using System.Linq; + + using OxyPlot.Axes; + + /// + /// Represents a series for pie/circle/doughnut charts. + /// + /// + /// The arc length/central angle/area of each slice is proportional to the quantity it represents. See http://en.wikipedia.org/wiki/Pie_chart + /// + public class PieSeries : ItemsSeries + { + /// + /// The slices. + /// + private IList slices; + + /// + /// Initializes a new instance of the class. + /// + public PieSeries() + { + this.slices = new List(); + + this.Stroke = OxyColors.White; + this.StrokeThickness = 1.0; + this.Diameter = 1.0; + this.InnerDiameter = 0.0; + this.StartAngle = 0.0; + this.AngleSpan = 360.0; + this.AngleIncrement = 1.0; + + this.LegendFormat = null; + this.OutsideLabelFormat = "{2:0} %"; + this.InsideLabelFormat = "{1}"; + this.TickDistance = 0; + this.TickRadialLength = 6; + this.TickHorizontalLength = 8; + this.TickLabelDistance = 4; + this.InsideLabelPosition = 0.5; + this.FontSize = 12; + } + + /// + /// Gets or sets AngleIncrement. + /// + public double AngleIncrement { get; set; } + + /// + /// Gets or sets AngleSpan. + /// + public double AngleSpan { get; set; } + + /// + /// Gets or sets a value indicating whether AreInsideLabelsAngled. + /// + public bool AreInsideLabelsAngled { get; set; } + + /// + /// Gets or sets the name of the property containing the color. + /// + /// The color field. + public string ColorField { get; set; } + + /// + /// Gets or sets the diameter. + /// + /// The diameter. + public double Diameter { get; set; } + + /// + /// Gets or sets the exploded distance. + /// + /// The exploded distance. + public double ExplodedDistance { get; set; } + + /// + /// Gets or sets the inner diameter. + /// + /// The inner diameter. + public double InnerDiameter { get; set; } + + /// + /// Gets or sets the inside label format. + /// + /// The inside label format. + public string InsideLabelFormat { get; set; } + + /// + /// Gets or sets the inside label position. + /// + /// The inside label position. + public double InsideLabelPosition { get; set; } + + /// + /// Gets or sets the is exploded field. + /// + /// The is exploded field. + public string IsExplodedField { get; set; } + + /// + /// Gets or sets the label field. + /// + /// The label field. + public string LabelField { get; set; } + + /// + /// Gets or sets the legend format. + /// + /// The legend format. + public string LegendFormat { get; set; } + + /// + /// Gets or sets the outside label format. + /// + /// The outside label format. + public string OutsideLabelFormat { get; set; } + + /// + /// Gets or sets the slices. + /// + /// The slices. + public IList Slices + { + get + { + return this.slices; + } + + set + { + this.slices = value; + } + } + + /// + /// Gets or sets the start angle. + /// + /// The start angle. + public double StartAngle { get; set; } + + /// + /// Gets or sets the stroke. + /// + /// The stroke. + public OxyColor Stroke { get; set; } + + /// + /// Gets or sets the stroke thickness. + /// + /// The stroke thickness. + public double StrokeThickness { get; set; } + + /// + /// Gets or sets the tick distance. + /// + /// The tick distance. + public double TickDistance { get; set; } + + /// + /// Gets or sets the length of the horizontal part of the tick. + /// + /// The length. + public double TickHorizontalLength { get; set; } + + /// + /// Gets or sets the tick label distance. + /// + /// The tick label distance. + public double TickLabelDistance { get; set; } + + /// + /// Gets or sets the length of the tick radial. + /// + /// The length of the tick radial. + public double TickRadialLength { get; set; } + + /// + /// Gets or sets the name of the property containing the value. + /// + /// The value field. + public string ValueField { get; set; } + + /// + /// Gets the point on the series that is nearest the specified point. + /// + /// + /// The point. + /// + /// + /// Interpolate the series if this flag is set to true . + /// + /// + /// A TrackerHitResult for the current hit. + /// + public override TrackerHitResult GetNearestPoint(ScreenPoint point, bool interpolate) + { + return null; + } + + /// + /// Renders the series on the specified render context. + /// + /// + /// The rendering context. + /// + /// + /// The model. + /// + public override void Render(IRenderContext rc, PlotModel model) + { + if (this.Slices.Count == 0) + { + return; + } + + double total = this.slices.Sum(slice => slice.Value); + if (Math.Abs(total) < double.Epsilon) + { + return; + } + + // todo: reduce available size due to the labels + double radius = Math.Min(model.PlotArea.Width, model.PlotArea.Height) / 2; + + double outerRadius = radius * (this.Diameter - this.ExplodedDistance); + double innerRadius = radius * this.InnerDiameter; + + double angle = this.StartAngle; + var midPoint = new ScreenPoint( + (model.PlotArea.Left + model.PlotArea.Right) * 0.5, (model.PlotArea.Top + model.PlotArea.Bottom) * 0.5); + + foreach (var slice in this.slices) + { + var outerPoints = new List(); + var innerPoints = new List(); + + double sliceAngle = slice.Value / total * this.AngleSpan; + double endAngle = angle + sliceAngle; + double explodedRadius = slice.IsExploded ? this.ExplodedDistance * radius : 0.0; + + double midAngle = angle + (sliceAngle / 2); + double midAngleRadians = midAngle * Math.PI / 180; + var mp = new ScreenPoint( + midPoint.X + (explodedRadius * Math.Cos(midAngleRadians)), + midPoint.Y + (explodedRadius * Math.Sin(midAngleRadians))); + + // Create the pie sector points for both outside and inside arcs + while (true) + { + bool stop = false; + if (angle >= endAngle) + { + angle = endAngle; + stop = true; + } + + double a = angle * Math.PI / 180; + var op = new ScreenPoint(mp.X + (outerRadius * Math.Cos(a)), mp.Y + (outerRadius * Math.Sin(a))); + outerPoints.Add(op); + var ip = new ScreenPoint(mp.X + (innerRadius * Math.Cos(a)), mp.Y + (innerRadius * Math.Sin(a))); + if (innerRadius + explodedRadius > 0) + { + innerPoints.Add(ip); + } + + if (stop) + { + break; + } + + angle += this.AngleIncrement; + } + + innerPoints.Reverse(); + if (innerPoints.Count == 0) + { + innerPoints.Add(mp); + } + + innerPoints.Add(outerPoints[0]); + + var points = outerPoints; + points.AddRange(innerPoints); + + rc.DrawPolygon(points, slice.ActualFillColor, this.Stroke, this.StrokeThickness, null, OxyPenLineJoin.Bevel); + + // Render label outside the slice + if (this.OutsideLabelFormat != null) + { + string label = string.Format( + this.OutsideLabelFormat, slice.Value, slice.Label, slice.Value / total * 100); + int sign = Math.Sign(Math.Cos(midAngleRadians)); + + // tick points + var tp0 = new ScreenPoint( + mp.X + ((outerRadius + this.TickDistance) * Math.Cos(midAngleRadians)), + mp.Y + ((outerRadius + this.TickDistance) * Math.Sin(midAngleRadians))); + var tp1 = new ScreenPoint( + tp0.X + (this.TickRadialLength * Math.Cos(midAngleRadians)), + tp0.Y + (this.TickRadialLength * Math.Sin(midAngleRadians))); + var tp2 = new ScreenPoint(tp1.X + (this.TickHorizontalLength * sign), tp1.Y); + rc.DrawLine(new[] { tp0, tp1, tp2 }, this.Stroke, this.StrokeThickness, null, OxyPenLineJoin.Bevel); + + // label + var labelPosition = new ScreenPoint(tp2.X + (this.TickLabelDistance * sign), tp2.Y); + rc.DrawText( + labelPosition, + label, + this.ActualTextColor, + this.ActualFont, + this.ActualFontSize, + this.ActualFontWeight, + 0, + sign > 0 ? HorizontalAlignment.Left : HorizontalAlignment.Right, + VerticalAlignment.Middle); + } + + // Render label inside the slice + if (this.InsideLabelFormat != null) + { + string label = string.Format( + this.InsideLabelFormat, slice.Value, slice.Label, slice.Value / total * 100); + double r = (innerRadius * (1 - this.InsideLabelPosition)) + (outerRadius * this.InsideLabelPosition); + var labelPosition = new ScreenPoint( + mp.X + (r * Math.Cos(midAngleRadians)), mp.Y + (r * Math.Sin(midAngleRadians))); + double textAngle = 0; + if (this.AreInsideLabelsAngled) + { + textAngle = midAngle; + if (Math.Cos(midAngleRadians) < 0) + { + textAngle += 180; + } + } + + rc.DrawText( + labelPosition, + label, + this.ActualTextColor, + this.ActualFont, + this.ActualFontSize, + this.ActualFontWeight, + textAngle, + HorizontalAlignment.Center, + VerticalAlignment.Middle); + } + } + } + + /// + /// Renders the legend symbol on the specified render context. + /// + /// + /// The rendering context. + /// + /// + /// The legend rectangle. + /// + public override void RenderLegend(IRenderContext rc, OxyRect legendBox) + { + } + + /// + /// Check if this data series requires X/Y axes. (e.g. Pie series do not require axes) + /// + /// + /// True if no axes are required. + /// + protected internal override bool AreAxesRequired() + { + return false; + } + + /// + /// Ensures that the axes of the series is defined. + /// + protected internal override void EnsureAxes() + { + } + + /// + /// Check if the data series is using the specified axis. + /// + /// + /// An axis. + /// + /// + /// True if the axis is in use. + /// + protected internal override bool IsUsing(Axis axis) + { + return false; + } + + /// + /// The set default values. + /// + /// + /// The model. + /// + protected internal override void SetDefaultValues(PlotModel model) + { + foreach (var slice in this.Slices) + { + if (slice.Fill == null) + { + slice.DefaultFillColor = model.GetDefaultColor(); + } + } + } + + /// + /// The update axis max min. + /// + protected internal override void UpdateAxisMaxMin() + { + } + + /// + /// Updates the data. + /// + protected internal override void UpdateData() + { + if (this.ItemsSource == null) + { + return; + } + + this.slices.Clear(); + + var filler = new ListFiller(); + filler.Add(this.LabelField, (item, value) => item.Label = Convert.ToString(value)); + filler.Add(this.ValueField, (item, value) => item.Value = Convert.ToDouble(value)); + filler.Add(this.ColorField, (item, value) => item.Fill = (OxyColor)value); + filler.Add(this.IsExplodedField, (item, value) => item.IsExploded = (bool)value); + filler.FillT(this.slices, this.ItemsSource); + } + + /// + /// The update max min. + /// + protected internal override void UpdateMaxMin() + { + } + + } +} \ No newline at end of file diff -r 88d699a65cc2 -r 5be8f2773237 External/OxyPlot/OxyPlot/Series/PieSlice.cs --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/External/OxyPlot/OxyPlot/Series/PieSlice.cs Sat Jun 08 16:53:22 2013 +0000 @@ -0,0 +1,99 @@ +// -------------------------------------------------------------------------------------------------------------------- +// +// The MIT License (MIT) +// +// Copyright (c) 2012 Oystein Bjorke +// +// Permission is hereby granted, free of charge, to any person obtaining a +// copy of this software and associated documentation files (the +// "Software"), to deal in the Software without restriction, including +// without limitation the rights to use, copy, modify, merge, publish, +// distribute, sublicense, and/or sell copies of the Software, and to +// permit persons to whom the Software is furnished to do so, subject to +// the following conditions: +// +// The above copyright notice and this permission notice shall be included +// in all copies or substantial portions of the Software. +// +// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS +// OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF +// MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. +// IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY +// CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, +// TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE +// SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. +// +// +// Represent a slice of a PieSeries. +// +// -------------------------------------------------------------------------------------------------------------------- +namespace OxyPlot.Series +{ + /// + /// Represent a slice of a . + /// + public class PieSlice + { + /// + /// Initializes a new instance of the class. + /// + public PieSlice() + { + } + + /// + /// Initializes a new instance of the class. + /// + /// + /// The label. + /// + /// + /// The value. + /// + /// + /// The fill. + /// + public PieSlice(string label, double value, OxyColor fill = null) + { + this.Label = label; + this.Value = value; + this.Fill = fill; + } + + /// + /// Gets or sets Fill. + /// + public OxyColor Fill { get; set; } + + /// + /// Gets the actual fill color. + /// + /// The actual color. + public OxyColor ActualFillColor + { + get { return this.Fill ?? this.DefaultFillColor; } + } + + /// + /// Gets or sets a value indicating whether IsExploded. + /// + public bool IsExploded { get; set; } + + /// + /// Gets or sets Label. + /// + public string Label { get; set; } + + /// + /// Gets or sets Value. + /// + public double Value { get; set; } + + /// + /// Gets or sets the default fill color. + /// + /// The default fill color. + internal OxyColor DefaultFillColor { get; set; } + + } +} \ No newline at end of file diff -r 88d699a65cc2 -r 5be8f2773237 External/OxyPlot/OxyPlot/Series/PlotSeriesBase.cs --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/External/OxyPlot/OxyPlot/Series/PlotSeriesBase.cs Sat Jun 08 16:53:22 2013 +0000 @@ -0,0 +1,302 @@ +// -------------------------------------------------------------------------------------------------------------------- +// +// The MIT License (MIT) +// +// Copyright (c) 2012 Oystein Bjorke +// +// Permission is hereby granted, free of charge, to any person obtaining a +// copy of this software and associated documentation files (the +// "Software"), to deal in the Software without restriction, including +// without limitation the rights to use, copy, modify, merge, publish, +// distribute, sublicense, and/or sell copies of the Software, and to +// permit persons to whom the Software is furnished to do so, subject to +// the following conditions: +// +// The above copyright notice and this permission notice shall be included +// in all copies or substantial portions of the Software. +// +// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS +// OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF +// MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. +// IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY +// CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, +// TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE +// SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. +// +// +// Abstract base class for Series that contains an X-axis and Y-axis +// +// -------------------------------------------------------------------------------------------------------------------- +namespace OxyPlot +{ + using System; + using System.Collections; + using System.Collections.Generic; + using System.Collections.ObjectModel; + using System.Linq; + + /// + /// Abstract base class for Series that contains an X-axis and Y-axis + /// + public abstract class PlotSeriesBase : ItemsSeries + { + /// + /// Gets or sets the maximum x-coordinate of the dataset. + /// + /// The maximum x-coordinate. + public double MaxX { get; protected set; } + + /// + /// Gets or sets the maximum y-coordinate of the dataset. + /// + /// The maximum y-coordinate. + public double MaxY { get; protected set; } + + /// + /// Gets or sets the minimum x-coordinate of the dataset. + /// + /// The minimum x-coordinate. + public double MinX { get; protected set; } + + /// + /// Gets or sets the minimum y-coordinate of the dataset. + /// + /// The minimum y-coordinate. + public double MinY { get; protected set; } + + /// + /// Gets or sets the x-axis. + /// + /// The x-axis. + public IAxis XAxis { get; set; } + + /// + /// Gets or sets the x-axis key. + /// + /// The x-axis key. + public string XAxisKey { get; set; } + + /// + /// Gets or sets the y-axis. + /// + /// The y-axis. + public IAxis YAxis { get; set; } + + /// + /// Gets or sets the y-axis key. + /// + /// The y-axis key. + public string YAxisKey { get; set; } + + /// + /// Check if this data series requires X/Y axes. + /// (e.g. Pie series do not require axes) + /// + /// + public override bool AreAxesRequired() + { + return true; + } + + public override void EnsureAxes(Collection axes, IAxis defaultXAxis, IAxis defaultYAxis) + { + if (this.XAxisKey != null) + { + this.XAxis = axes.FirstOrDefault(a => a.Key == this.XAxisKey); + } + + if (this.YAxisKey != null) + { + this.YAxis = axes.FirstOrDefault(a => a.Key == this.YAxisKey); + } + + // If axes are not found, use the default axes + if (this.XAxis == null) + { + this.XAxis = defaultXAxis; + } + + if (this.YAxis == null) + { + this.YAxis = defaultYAxis; + } + } + + /// + /// Gets the rectangle the series uses on the screen (screen coordinates). + /// + /// + public OxyRect GetScreenRectangle() + { + return this.GetClippingRect(); + } + + public override bool IsUsing(IAxis axis) + { + return this.XAxis == axis || this.YAxis == axis; + } + + /// + /// Renders the Series on the specified rendering context. + /// + /// The rendering context. + /// The model. + public override void Render(IRenderContext rc, PlotModel model) + { + } + + /// + /// Renders the legend symbol on the specified rendering context. + /// + /// The rendering context. + /// The legend rectangle. + public override void RenderLegend(IRenderContext rc, OxyRect legendBox) + { + } + + public override void SetDefaultValues(PlotModel model) + { + } + + public override void UpdateData() + { + } + + /// + /// Updates the max/minimum values. + /// + public override void UpdateMaxMin() + { + this.MinX = this.MinY = this.MaxX = this.MaxY = double.NaN; + } + + protected OxyRect GetClippingRect() + { + double minX = Math.Min(this.XAxis.ScreenMin.X, this.XAxis.ScreenMax.X); + double minY = Math.Min(this.YAxis.ScreenMin.Y, this.YAxis.ScreenMax.Y); + double maxX = Math.Max(this.XAxis.ScreenMin.X, this.XAxis.ScreenMax.X); + double maxY = Math.Max(this.YAxis.ScreenMin.Y, this.YAxis.ScreenMax.Y); + + return new OxyRect(minX, minY, maxX - minX, maxY - minY); + } + + /// + /// Gets the point on the curve that is nearest the specified point. + /// + /// The point. + /// The nearest point (data coordinates). + /// The nearest point (screen coordinates). + /// + protected bool GetNearestInterpolatedPointInternal( + IList points, ScreenPoint point, out DataPoint dpn, out ScreenPoint spn, out int index) + { + spn = default(ScreenPoint); + dpn = default(DataPoint); + index = -1; + + // http://local.wasp.uwa.edu.au/~pbourke/geometry/pointline/ + double minimumDistance = double.MaxValue; + + for (int i = 0; i + 1 < points.Count; i++) + { + IDataPoint p1 = points[i]; + IDataPoint p2 = points[i + 1]; + ScreenPoint sp1 = AxisBase.Transform(p1, this.XAxis, this.YAxis); + ScreenPoint sp2 = AxisBase.Transform(p2, this.XAxis, this.YAxis); + + double sp21X = sp2.x - sp1.x; + double sp21Y = sp2.y - sp1.y; + double u1 = (point.x - sp1.x) * sp21X + (point.y - sp1.y) * sp21Y; + double u2 = sp21X * sp21X + sp21Y * sp21Y; + double ds = sp21X * sp21X + sp21Y * sp21Y; + + if (ds < 4) + { + // if the points are very close, we can get numerical problems, just use the first point... + u1 = 0; + u2 = 1; + } + + if (u2 < double.Epsilon && u2 > -double.Epsilon) + { + continue; // P1 && P2 coincident + } + + double u = u1 / u2; + if (u < 0) u = 0; + if (u > 1) u = 1; + + double sx = sp1.x + u * sp21X; + double sy = sp1.y + u * sp21Y; + + double dx = point.x - sx; + double dy = point.y - sy; + double distance = dx * dx + dy * dy; + + if (distance < minimumDistance) + { + double px = p1.X + u * (p2.X - p1.X); + double py = p1.Y + u * (p2.Y - p1.Y); + dpn = new DataPoint(px, py); + spn = new ScreenPoint(sx, sy); + minimumDistance = distance; + index = i; + } + } + + return minimumDistance < double.MaxValue; + } + + protected bool GetNearestPointInternal( + IEnumerable points, ScreenPoint point, out DataPoint dpn, out ScreenPoint spn, out int index) + { + spn = default(ScreenPoint); + dpn = default(DataPoint); + index = -1; + + double minimumDistance = double.MaxValue; + int i = 0; + foreach (DataPoint p in points) + { + ScreenPoint sp = AxisBase.Transform(p, this.XAxis, this.YAxis); + double dx = sp.x - point.x; + double dy = sp.y - point.y; + double d2 = dx * dx + dy * dy; + + if (d2 < minimumDistance) + { + dpn = p; + spn = sp; + minimumDistance = d2; + index = i; + } + i++; + } + + return minimumDistance < double.MaxValue; + } + + /// + /// Converts the value of the specified object to a double precision floating point number. + /// DateTime objects are converted using DateTimeAxis.ToDouble + /// TimeSpan objects are converted using TimeSpanAxis.ToDouble + /// + /// The value. + /// + protected virtual double ToDouble(object value) + { + if (value is DateTime) + { + return DateTimeAxis.ToDouble((DateTime)value); + } + + if (value is TimeSpan) + { + return ((TimeSpan)value).TotalSeconds; + } + + return Convert.ToDouble(value); + } + + } +} \ No newline at end of file diff -r 88d699a65cc2 -r 5be8f2773237 External/OxyPlot/OxyPlot/Series/ScatterPoint.cs --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/External/OxyPlot/OxyPlot/Series/ScatterPoint.cs Sat Jun 08 16:53:22 2013 +0000 @@ -0,0 +1,232 @@ +// -------------------------------------------------------------------------------------------------------------------- +// +// The MIT License (MIT) +// +// Copyright (c) 2012 Oystein Bjorke +// +// Permission is hereby granted, free of charge, to any person obtaining a +// copy of this software and associated documentation files (the +// "Software"), to deal in the Software without restriction, including +// without limitation the rights to use, copy, modify, merge, publish, +// distribute, sublicense, and/or sell copies of the Software, and to +// permit persons to whom the Software is furnished to do so, subject to +// the following conditions: +// +// The above copyright notice and this permission notice shall be included +// in all copies or substantial portions of the Software. +// +// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS +// OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF +// MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. +// IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY +// CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, +// TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE +// SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. +// +// +// Represents a point in a ScatterSeries. +// +// -------------------------------------------------------------------------------------------------------------------- +namespace OxyPlot.Series +{ + using System.Diagnostics.CodeAnalysis; + + /// + /// Represents a point in a . + /// + public class ScatterPoint : IDataPoint + { + // ReSharper disable InconsistentNaming + + /// + /// The size. + /// + [SuppressMessage("StyleCop.CSharp.NamingRules", "SA1307:AccessibleFieldsMustBeginWithUpperCaseLetter", Justification = "Reviewed. Suppression is OK here.")] + [SuppressMessage("StyleCop.CSharp.MaintainabilityRules", "SA1401:FieldsMustBePrivate", Justification = "Reviewed. Suppression is OK here.")] + internal double size; + + /// + /// The tag. + /// + [SuppressMessage("StyleCop.CSharp.NamingRules", "SA1307:AccessibleFieldsMustBeginWithUpperCaseLetter", Justification = "Reviewed. Suppression is OK here.")] + [SuppressMessage("StyleCop.CSharp.MaintainabilityRules", "SA1401:FieldsMustBePrivate", Justification = "Reviewed. Suppression is OK here.")] + internal object tag; + + /// + /// The value. + /// + [SuppressMessage("StyleCop.CSharp.NamingRules", "SA1307:AccessibleFieldsMustBeginWithUpperCaseLetter", Justification = "Reviewed. Suppression is OK here.")] + [SuppressMessage("StyleCop.CSharp.MaintainabilityRules", "SA1401:FieldsMustBePrivate", Justification = "Reviewed. Suppression is OK here.")] + internal double value; + + /// + /// The x. + /// + [SuppressMessage("StyleCop.CSharp.NamingRules", "SA1307:AccessibleFieldsMustBeginWithUpperCaseLetter", Justification = "Reviewed. Suppression is OK here.")] + [SuppressMessage("StyleCop.CSharp.MaintainabilityRules", "SA1401:FieldsMustBePrivate", Justification = "Reviewed. Suppression is OK here.")] + internal double x; + + /// + /// The y. + /// + [SuppressMessage("StyleCop.CSharp.NamingRules", "SA1307:AccessibleFieldsMustBeginWithUpperCaseLetter", Justification = "Reviewed. Suppression is OK here.")] + [SuppressMessage("StyleCop.CSharp.MaintainabilityRules", "SA1401:FieldsMustBePrivate", Justification = "Reviewed. Suppression is OK here.")] + internal double y; + + // ReSharper restore InconsistentNaming + /// + /// Initializes a new instance of the class. + /// + public ScatterPoint() + { + this.Size = double.NaN; + this.Value = double.NaN; + } + + /// + /// Initializes a new instance of the class. + /// + /// + /// The x. + /// + /// + /// The y. + /// + /// + /// The size. + /// + /// + /// The value. + /// + /// + /// The tag. + /// + public ScatterPoint(double x, double y, double size = double.NaN, double value = double.NaN, object tag = null) + { + this.x = x; + this.y = y; + this.size = size; + this.value = value; + this.tag = tag; + } + + /// + /// Gets or sets the size. + /// + /// The size. + public double Size + { + get + { + return this.size; + } + + set + { + this.size = value; + } + } + + /// + /// Gets or sets the tag. + /// + /// The tag. + public object Tag + { + get + { + return this.tag; + } + + set + { + this.tag = value; + } + } + + /// + /// Gets or sets the value. + /// + /// The value. + public double Value + { + get + { + return this.value; + } + + set + { + this.value = value; + } + } + + /// + /// Gets or sets the X. + /// + /// The X. + public double X + { + get + { + return this.x; + } + + set + { + this.x = value; + } + } + + /// + /// Gets or sets the Y. + /// + /// The Y. + public double Y + { + get + { + return this.y; + } + + set + { + this.y = value; + } + } + + /// + /// Returns C# code that generates this instance. + /// + /// + /// C# code. + /// + public string ToCode() + { + if (double.IsNaN(this.size) && double.IsNaN(this.value)) + { + return CodeGenerator.FormatConstructor(this.GetType(), "{0}, {1}", this.x, this.y); + } + + if (double.IsNaN(this.value)) + { + return CodeGenerator.FormatConstructor(this.GetType(), "{0}, {1}, {2}", this.x, this.y, this.size); + } + + return CodeGenerator.FormatConstructor( + this.GetType(), "{0}, {1}, {2}, {3}", this.x, this.y, this.size, this.value); + } + + /// + /// Returns a that represents this instance. + /// + /// + /// A that represents this instance. + /// + public override string ToString() + { + return this.x + " " + this.y; + } + + } +} \ No newline at end of file diff -r 88d699a65cc2 -r 5be8f2773237 External/OxyPlot/OxyPlot/Series/ScatterSeries.cs --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/External/OxyPlot/OxyPlot/Series/ScatterSeries.cs Sat Jun 08 16:53:22 2013 +0000 @@ -0,0 +1,621 @@ +// -------------------------------------------------------------------------------------------------------------------- +// +// The MIT License (MIT) +// +// Copyright (c) 2012 Oystein Bjorke +// +// Permission is hereby granted, free of charge, to any person obtaining a +// copy of this software and associated documentation files (the +// "Software"), to deal in the Software without restriction, including +// without limitation the rights to use, copy, modify, merge, publish, +// distribute, sublicense, and/or sell copies of the Software, and to +// permit persons to whom the Software is furnished to do so, subject to +// the following conditions: +// +// The above copyright notice and this permission notice shall be included +// in all copies or substantial portions of the Software. +// +// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS +// OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF +// MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. +// IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY +// CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, +// TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE +// SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. +// +// +// Represents a series for scatter plots. +// +// -------------------------------------------------------------------------------------------------------------------- + +namespace OxyPlot.Series +{ + using System; + using System.Collections; + using System.Collections.Generic; + + using OxyPlot.Axes; + + /// + /// Represents a series for scatter plots. + /// + /// + /// See http://en.wikipedia.org/wiki/Scatter_plot + /// + public class ScatterSeries : DataPointSeries + { + /// + /// The default fill color. + /// + private OxyColor defaultMarkerFillColor; + + /// + /// Initializes a new instance of the class. + /// + /// + /// The title. + /// + /// + /// The marker fill color. + /// + /// + /// Size of the markers (If ScatterPoint.Size is set, this value will be overridden). + /// + public ScatterSeries(string title, OxyColor markerFill = null, double markerSize = 5) + : this() + { + this.MarkerFill = markerFill; + this.MarkerSize = markerSize; + this.Title = title; + } + + /// + /// Initializes a new instance of the class. + /// + public ScatterSeries() + { + this.DataFieldSize = null; + this.DataFieldValue = null; + + this.MarkerFill = null; + this.MarkerSize = 5; + this.MarkerType = MarkerType.Square; + this.MarkerStroke = null; + this.MarkerStrokeThickness = 1.0; + } + + /// + /// Gets or sets the screen resolution. If this number is greater than 1, bins of that size is created for both x and y directions. Only one point will be drawn in each bin. + /// + public int BinSize { get; set; } + + /// + /// Gets or sets the color map. + /// + /// The color map. + /// + /// This is used to map scatter point values to colors. + /// + public ColorAxis ColorAxis { get; set; } + + /// + /// Gets or sets the color axis key. + /// + /// The color axis key. + public string ColorAxisKey { get; set; } + + /// + /// Gets or sets the data field for the size. + /// + /// The size data field. + public string DataFieldSize { get; set; } + + /// + /// Gets or sets the tag data field. + /// + /// The tag data field. + public string DataFieldTag { get; set; } + + /// + /// Gets or sets the value data field. + /// + /// The value data field. + public string DataFieldValue { get; set; } + + /// + /// Gets or sets the marker fill color. If null, this color will be automatically set. + /// + /// The marker fill color. + public OxyColor MarkerFill { get; set; } + + /// + /// Gets the actual fill color. + /// + /// The actual color. + public OxyColor ActualMarkerFillColor + { + get { return this.MarkerFill ?? this.defaultMarkerFillColor; } + } + + /// + /// Gets or sets the marker outline polygon. Set MarkerType to Custom to use this. + /// + /// The marker outline. + public ScreenPoint[] MarkerOutline { get; set; } + + /// + /// Gets or sets the size of the marker (same size for all items). + /// + /// The size of the markers. + public double MarkerSize { get; set; } + + /// + /// Gets or sets the marker stroke. + /// + /// The marker stroke. + public OxyColor MarkerStroke { get; set; } + + /// + /// Gets or sets the marker stroke thickness. + /// + /// The marker stroke thickness. + public double MarkerStrokeThickness { get; set; } + + /// + /// Gets or sets the type of the marker. + /// + /// The type of the marker. + /// + /// If MarkerType.Custom is used, the MarkerOutline property must be specified. + /// + public MarkerType MarkerType { get; set; } + + /// + /// Gets the max value of the points. + /// + public double MaxValue { get; private set; } + + /// + /// Gets the min value of the points. + /// + public double MinValue { get; private set; } + + /// + /// Gets the nearest point. + /// + /// + /// The point. + /// + /// + /// interpolate if set to true . + /// + /// + /// A TrackerHitResult for the current hit. + /// + public override TrackerHitResult GetNearestPoint(ScreenPoint point, bool interpolate) + { + if (this.XAxis == null || this.YAxis == null) + { + return null; + } + + if (interpolate) + { + return null; + } + + TrackerHitResult result = null; + double minimumDistance = double.MaxValue; + int i = 0; + + var xaxisTitle = this.XAxis.Title ?? "X"; + var yaxisTitle = this.YAxis.Title ?? "Y"; + var colorAxisTitle = (this.ColorAxis != null ? this.ColorAxis.Title : null) ?? "Z"; + + var formatString = TrackerFormatString; + if (string.IsNullOrEmpty(this.TrackerFormatString)) + { + // Create a default format string + formatString = "{1}: {2}\n{3}: {4}"; + if (this.ColorAxis != null) + { + formatString += "\n{5}: {6}"; + } + } + + foreach (var p in this.Points) + { + if (p.X < this.XAxis.ActualMinimum || p.X > this.XAxis.ActualMaximum || p.Y < this.YAxis.ActualMinimum || p.Y > this.YAxis.ActualMaximum) + { + i++; + continue; + } + + var dp = new DataPoint(p.X, p.Y); + var sp = Axis.Transform(dp, this.XAxis, this.YAxis); + double dx = sp.x - point.x; + double dy = sp.y - point.y; + double d2 = (dx * dx) + (dy * dy); + + if (d2 < minimumDistance) + { + var item = this.GetItem(i); + + object xvalue = this.XAxis.GetValue(dp.X); + object yvalue = this.YAxis.GetValue(dp.Y); + object zvalue = null; + + var scatterPoint = p as ScatterPoint; + if (scatterPoint != null) + { + if (!double.IsNaN(scatterPoint.Value) && !double.IsInfinity(scatterPoint.Value)) + { + zvalue = scatterPoint.Value; + } + } + + var text = StringHelper.Format( + this.ActualCulture, + formatString, + item, + this.Title, + xaxisTitle, + xvalue, + yaxisTitle, + yvalue, + colorAxisTitle, + zvalue); + + result = new TrackerHitResult(this, dp, sp, item, i, text); + + minimumDistance = d2; + } + + i++; + } + + return result; + } + + /// + /// Determines whether the specified point is valid. + /// + /// + /// The point. + /// + /// + /// The x axis. + /// + /// + /// The y axis. + /// + /// + /// true if the point is valid; otherwise, false . + /// + public virtual bool IsValidPoint(ScatterPoint pt, Axis xaxis, Axis yaxis) + { + return !double.IsNaN(pt.X) && !double.IsInfinity(pt.X) && !double.IsNaN(pt.Y) && !double.IsInfinity(pt.Y) + && (xaxis != null && xaxis.IsValidValue(pt.X)) && (yaxis != null && yaxis.IsValidValue(pt.Y)); + } + + /// + /// Renders the series on the specified rendering context. + /// + /// + /// The rendering context. + /// + /// + /// The owner plot model. + /// + public override void Render(IRenderContext rc, PlotModel model) + { + if (this.Points.Count == 0) + { + return; + } + + OxyRect clippingRect = this.GetClippingRect(); + + var points = this.Points; + int n = points.Count; + var groupPoints = new Dictionary>(); + var groupSizes = new Dictionary>(); + + ScreenPoint[] allPoints = null; + double[] markerSizes = null; + + if (this.ColorAxis == null) + { + allPoints = new ScreenPoint[n]; + markerSizes = new double[n]; + } + + // Transform all points to screen coordinates + for (int i = 0; i < n; i++) + { + var dp = new DataPoint(points[i].X, points[i].Y); + double size = double.NaN; + double value = double.NaN; + + var scatterPoint = points[i] as ScatterPoint; + if (scatterPoint != null) + { + size = scatterPoint.Size; + value = scatterPoint.Value; + } + + if (double.IsNaN(size)) + { + size = this.MarkerSize; + } + + var screenPoint = this.XAxis.Transform(dp.X, dp.Y, this.YAxis); + + if (this.ColorAxis != null) + { + if (!double.IsNaN(value)) + { + int group = this.ColorAxis.GetPaletteIndex(value); + if (!groupPoints.ContainsKey(group)) + { + groupPoints.Add(group, new List()); + groupSizes.Add(group, new List()); + } + + groupPoints[group].Add(screenPoint); + groupSizes[group].Add(size); + } + } + else + { + // ReSharper disable PossibleNullReferenceException + allPoints[i] = screenPoint; + markerSizes[i] = size; + // ReSharper restore PossibleNullReferenceException + } + } + + var binOffset = this.XAxis.Transform(this.MinX, this.MaxY, this.YAxis); + + // Draw the markers + if (this.ColorAxis != null) + { + var markerIsStrokedOnly = this.MarkerType == MarkerType.Plus || this.MarkerType == MarkerType.Star + || this.MarkerType == MarkerType.Cross; + foreach (var group in groupPoints) + { + var color = this.ColorAxis.GetColor(group.Key); + rc.DrawMarkers( + group.Value, + clippingRect, + this.MarkerType, + this.MarkerOutline, + groupSizes[group.Key], + color, + markerIsStrokedOnly ? color : this.MarkerStroke, + this.MarkerStrokeThickness, + this.BinSize, + binOffset); + } + } + else + { + rc.DrawMarkers( + allPoints, + clippingRect, + this.MarkerType, + this.MarkerOutline, + markerSizes, + this.ActualMarkerFillColor, + this.MarkerStroke, + this.MarkerStrokeThickness, + this.BinSize, + binOffset); + } + } + + /// + /// Renders the legend symbol for the line series on the specified rendering context. + /// + /// + /// The rendering context. + /// + /// + /// The bounding rectangle of the legend box. + /// + public override void RenderLegend(IRenderContext rc, OxyRect legendBox) + { + double xmid = (legendBox.Left + legendBox.Right) / 2; + double ymid = (legendBox.Top + legendBox.Bottom) / 2; + + var midpt = new ScreenPoint(xmid, ymid); + rc.DrawMarker( + midpt, + legendBox, + this.MarkerType, + this.MarkerOutline, + this.MarkerSize, + this.ActualMarkerFillColor, + this.MarkerStroke, + this.MarkerStrokeThickness); + } + + /// + /// Ensures that the axes of the series is defined. + /// + protected internal override void EnsureAxes() + { + base.EnsureAxes(); + + this.ColorAxis = PlotModel.GetAxisOrDefault(this.ColorAxisKey, PlotModel.DefaultColorAxis) as ColorAxis; + } + + /// + /// Sets the default values. + /// + /// + /// The model. + /// + protected internal override void SetDefaultValues(PlotModel model) + { + if (this.MarkerFill == null) + { + this.defaultMarkerFillColor = model.GetDefaultColor(); + } + } + + /// + /// The update data. + /// + protected internal override void UpdateData() + { + if (this.ItemsSource == null) + { + return; + } + + var points = this.Points; + points.Clear(); + + // Use the mapping to generate the points + if (this.Mapping != null) + { + foreach (var item in this.ItemsSource) + { + points.Add(this.Mapping(item)); + } + + return; + } + + // Get DataPoints from the items in ItemsSource + // if they implement IScatterPointProvider + // If DataFields are set, this is not used + /*if (DataFieldX == null || DataFieldY == null) + { + foreach (var item in ItemsSource) + { + var idpp = item as IScatterPointProvider; + if (idpp == null) + { + continue; + } + + points.Add(idpp.GetScatterPoint()); + } + + return; + }*/ + + var dest = new List(); + + // Using reflection to add points + var filler = new ListFiller(); + filler.Add(this.DataFieldX, (item, value) => item.X = Convert.ToDouble(value)); + filler.Add(this.DataFieldY, (item, value) => item.Y = Convert.ToDouble(value)); + filler.Add(this.DataFieldSize, (item, value) => item.Size = Convert.ToDouble(value)); + filler.Add(this.DataFieldValue, (item, value) => item.Value = Convert.ToDouble(value)); + filler.Add(this.DataFieldTag, (item, value) => item.Tag = value); + filler.Fill(dest, this.ItemsSource); + + this.Points = dest; + } + + /// + /// Updates the max/min from the data points. + /// + protected internal override void UpdateMaxMin() + { + base.UpdateMaxMin(); + this.InternalUpdateMaxMinValue(this.Points); + } + + /// + /// Adds scatter points specified by a items source and data fields. + /// + /// + /// The destination collection. + /// + /// + /// The items source. + /// + /// + /// The data field x. + /// + /// + /// The data field y. + /// + /// + /// The data field size. + /// + /// + /// The data field value. + /// + /// + /// The data field tag. + /// + protected void AddScatterPoints( + IList dest, + IEnumerable itemsSource, + string dataFieldX, + string dataFieldY, + string dataFieldSize, + string dataFieldValue, + string dataFieldTag) + { + var filler = new ListFiller(); + filler.Add(dataFieldX, (item, value) => item.X = Convert.ToDouble(value)); + filler.Add(dataFieldY, (item, value) => item.Y = Convert.ToDouble(value)); + filler.Add(dataFieldSize, (item, value) => item.Size = Convert.ToDouble(value)); + filler.Add(dataFieldValue, (item, value) => item.Value = Convert.ToDouble(value)); + filler.Add(dataFieldTag, (item, value) => item.Tag = value); + filler.FillT(dest, itemsSource); + } + + /// + /// Updates the Max/Min limits from the values in the specified point list. + /// + /// + /// The points. + /// + protected void InternalUpdateMaxMinValue(IList pts) + { + if (pts == null || pts.Count == 0) + { + return; + } + + double minvalue = double.NaN; + double maxvalue = double.NaN; + + foreach (var pt in pts) + { + if (!(pt is ScatterPoint)) + { + continue; + } + + double value = ((ScatterPoint)pt).value; + + if (value < minvalue || double.IsNaN(minvalue)) + { + minvalue = value; + } + + if (value > maxvalue || double.IsNaN(maxvalue)) + { + maxvalue = value; + } + } + + this.MinValue = minvalue; + this.MaxValue = maxvalue; + + if (this.ColorAxis != null) + { + this.ColorAxis.Include(this.MinValue); + this.ColorAxis.Include(this.MaxValue); + } + } + } +} \ No newline at end of file diff -r 88d699a65cc2 -r 5be8f2773237 External/OxyPlot/OxyPlot/Series/Series.cs --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/External/OxyPlot/OxyPlot/Series/Series.cs Sat Jun 08 16:53:22 2013 +0000 @@ -0,0 +1,204 @@ +// -------------------------------------------------------------------------------------------------------------------- +// +// The MIT License (MIT) +// +// Copyright (c) 2012 Oystein Bjorke +// +// Permission is hereby granted, free of charge, to any person obtaining a +// copy of this software and associated documentation files (the +// "Software"), to deal in the Software without restriction, including +// without limitation the rights to use, copy, modify, merge, publish, +// distribute, sublicense, and/or sell copies of the Software, and to +// permit persons to whom the Software is furnished to do so, subject to +// the following conditions: +// +// The above copyright notice and this permission notice shall be included +// in all copies or substantial portions of the Software. +// +// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS +// OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF +// MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. +// IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY +// CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, +// TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE +// SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. +// +// +// Abstract base class for all series. +// +// -------------------------------------------------------------------------------------------------------------------- +namespace OxyPlot.Series +{ + using System.Globalization; + + using OxyPlot.Axes; + + /// + /// Provides an abstract base class for plot series. + /// + /// + /// This class contains internal methods that should be called only from the PlotModel. + /// + public abstract class Series : UIPlotElement, ITrackableSeries + { + /// + /// Initializes a new instance of the class. + /// + protected Series() + { + this.IsVisible = true; + } + + /// + /// Gets the actual culture. + /// + /// + /// The culture is defined in the parent PlotModel. + /// + public CultureInfo ActualCulture + { + get + { + return this.PlotModel != null ? this.PlotModel.ActualCulture : CultureInfo.CurrentCulture; + } + } + + /// + /// Gets or sets the background color of the series. The background area is defined by the x and y axes. + /// + /// The background color. + public OxyColor Background { get; set; } + + /// + /// Gets or sets a value indicating whether this series is visible. + /// + public bool IsVisible { get; set; } + + /// + /// Gets or sets the title of the Series. + /// + /// The title. + public string Title { get; set; } + + /// + /// Gets or sets a format string used for the tracker. + /// + public string TrackerFormatString { get; set; } + + /// + /// Gets or sets the key for the tracker to use on this series. + /// + public string TrackerKey { get; set; } + + /// + /// Gets the point on the series that is nearest the specified point. + /// + /// The point. + /// Interpolate the series if this flag is set to true. + /// + /// A TrackerHitResult for the current hit. + /// + public abstract TrackerHitResult GetNearestPoint(ScreenPoint point, bool interpolate); + + /// + /// Renders the series on the specified render context. + /// + /// + /// The rendering context. + /// + /// + /// The model. + /// + public abstract void Render(IRenderContext rc, PlotModel model); + + /// + /// Renders the legend symbol on the specified render context. + /// + /// + /// The rendering context. + /// + /// + /// The legend rectangle. + /// + public abstract void RenderLegend(IRenderContext rc, OxyRect legendBox); + + /// + /// Tests if the plot element is hit by the specified point. + /// + /// The point. + /// The tolerance. + /// + /// A hit test result. + /// + protected internal override HitTestResult HitTest(ScreenPoint point, double tolerance) + { + var thr = this.GetNearestPoint(point, true) ?? this.GetNearestPoint(point, false); + + if (thr != null) + { + double distance = thr.Position.DistanceTo(point); + if (distance > tolerance) + { + return null; + } + + return new HitTestResult(thr.Position, thr.Item, thr.Index); + } + + return null; + } + + /// + /// Check if this data series requires X/Y axes. (e.g. Pie series do not require axes) + /// + /// + /// True if no axes are required. + /// + protected internal abstract bool AreAxesRequired(); + + /// + /// Ensures that the axes of the series is defined. + /// + protected internal abstract void EnsureAxes(); + + /// + /// Check if the data series is using the specified axis. + /// + /// + /// An axis which should be checked if used + /// + /// + /// True if the axis is in use. + /// + protected internal abstract bool IsUsing(Axis axis); + + /// + /// Sets default values (colors, line style etc) from the plot model. + /// + /// + /// A plot model. + /// + protected internal abstract void SetDefaultValues(PlotModel model); + + /// + /// Updates the axis maximum and minimum values. + /// + protected internal abstract void UpdateAxisMaxMin(); + + /// + /// Updates the data. + /// + protected internal abstract void UpdateData(); + + /// + /// Updates the valid data. + /// + protected internal abstract void UpdateValidData(); + + /// + /// Updates the maximum and minimum of the series. + /// + protected internal abstract void UpdateMaxMin(); + + } +} \ No newline at end of file diff -r 88d699a65cc2 -r 5be8f2773237 External/OxyPlot/OxyPlot/Series/StairStepSeries.cs --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/External/OxyPlot/OxyPlot/Series/StairStepSeries.cs Sat Jun 08 16:53:22 2013 +0000 @@ -0,0 +1,291 @@ +// -------------------------------------------------------------------------------------------------------------------- +// +// The MIT License (MIT) +// +// Copyright (c) 2012 Oystein Bjorke +// +// Permission is hereby granted, free of charge, to any person obtaining a +// copy of this software and associated documentation files (the +// "Software"), to deal in the Software without restriction, including +// without limitation the rights to use, copy, modify, merge, publish, +// distribute, sublicense, and/or sell copies of the Software, and to +// permit persons to whom the Software is furnished to do so, subject to +// the following conditions: +// +// The above copyright notice and this permission notice shall be included +// in all copies or substantial portions of the Software. +// +// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS +// OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF +// MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. +// IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY +// CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, +// TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE +// SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. +// +// +// Represents a series for stair step graphs. +// +// -------------------------------------------------------------------------------------------------------------------- +namespace OxyPlot.Series +{ + using System; + using System.Collections.Generic; + + /// + /// Represents a series for stair step graphs. + /// + public class StairStepSeries : LineSeries + { + /// + /// Initializes a new instance of the class. + /// + public StairStepSeries() + { + this.VerticalStrokeThickness = double.NaN; + this.VerticalLineStyle = this.LineStyle; + } + + /// + /// Initializes a new instance of the class. + /// + /// + /// The title. + /// + public StairStepSeries(string title) + : base(title) + { + this.VerticalStrokeThickness = double.NaN; + this.VerticalLineStyle = this.LineStyle; + this.Title = title; + } + + /// + /// Initializes a new instance of the class. + /// + /// + /// The color. + /// + /// + /// The stroke thickness. + /// + /// + /// The title. + /// + public StairStepSeries(OxyColor color, double strokeThickness = 1, string title = null) + : base(color, strokeThickness, title) + { + this.VerticalStrokeThickness = double.NaN; + this.VerticalLineStyle = this.LineStyle; + } + + /// + /// Gets or sets the stroke thickness of the vertical line segments. + /// + /// + /// Set the value to NaN to use the StrokeThickness property for both horizontal and vertical segments. + /// Using the VerticalStrokeThickness property will have a small performance hit. + /// + /// The vertical stroke thickness. + public double VerticalStrokeThickness { get; set; } + + /// + /// Gets or sets the line style of the vertical line segments. + /// + /// The vertical line style. + public LineStyle VerticalLineStyle { get; set; } + + /// + /// Gets the nearest point. + /// + /// + /// The point. + /// + /// + /// interpolate if set to true . + /// + /// + /// A TrackerHitResult for the current hit. + /// + public override TrackerHitResult GetNearestPoint(ScreenPoint point, bool interpolate) + { + if (this.XAxis == null || this.YAxis == null) + { + return null; + } + + TrackerHitResult result = null; + + // http://paulbourke.net/geometry/pointlineplane/ + double minimumDistance = double.MaxValue; + + for (int i = 0; i + 1 < this.Points.Count; i++) + { + var p1 = this.Points[i]; + var p2 = this.Points[i + 1]; + var sp1 = this.Transform(p1.X, p1.Y); + var sp2 = this.Transform(p2.X, p1.Y); + + double spdx = sp2.x - sp1.x; + double spdy = sp2.y - sp1.y; + double u1 = ((point.x - sp1.x) * spdx) + ((point.y - sp1.y) * spdy); + double u2 = (spdx * spdx) + (spdy * spdy); + double ds = (spdx * spdx) + (spdy * spdy); + + if (ds < 4) + { + // if the points are very close, we can get numerical problems, just use the first point... + u1 = 0; + u2 = 1; + } + + if (Math.Abs(u2) < double.Epsilon) + { + continue; // P1 && P2 coincident + } + + double u = u1 / u2; + if (u < 0 || u > 1) + { + continue; // outside line + } + + double sx = sp1.x + (u * spdx); + double sy = sp1.y + (u * spdy); + + double dx = point.x - sx; + double dy = point.y - sy; + double distance = (dx * dx) + (dy * dy); + + if (distance < minimumDistance) + { + double px = p1.X + (u * (p2.X - p1.X)); + double py = p1.Y; + result = new TrackerHitResult( + this, new DataPoint(px, py), new ScreenPoint(sx, sy), this.GetItem(i), i); + minimumDistance = distance; + } + } + + return result; + } + + /// + /// Renders the LineSeries on the specified rendering context. + /// + /// + /// The rendering context. + /// + /// + /// The owner plot model. + /// + public override void Render(IRenderContext rc, PlotModel model) + { + if (this.Points.Count == 0) + { + return; + } + + this.VerifyAxes(); + + var clippingRect = this.GetClippingRect(); + + Action, IList> renderPoints = (lpts, mpts) => + { + var lineStyle = this.ActualLineStyle; + + // clip the line segments with the clipping rectangle + if (this.StrokeThickness > 0 && lineStyle != LineStyle.None) + { + var verticalStrokeThickness = double.IsNaN(this.VerticalStrokeThickness) + ? this.StrokeThickness + : this.VerticalStrokeThickness; + if (!verticalStrokeThickness.Equals(this.StrokeThickness) || this.VerticalLineStyle != lineStyle) + { + var hlpts = new List(); + var vlpts = new List(); + for (int i = 0; i + 2 < lpts.Count; i += 2) + { + hlpts.Add(lpts[i]); + hlpts.Add(lpts[i + 1]); + vlpts.Add(lpts[i + 1]); + vlpts.Add(lpts[i + 2]); + } + + rc.DrawClippedLineSegments( + hlpts, + clippingRect, + this.GetSelectableColor(this.ActualColor), + this.StrokeThickness, + lineStyle, + this.LineJoin, + false); + rc.DrawClippedLineSegments( + vlpts, + clippingRect, + this.GetSelectableColor(this.ActualColor), + verticalStrokeThickness, + this.VerticalLineStyle, + this.LineJoin, + false); + } + else + { + rc.DrawClippedLine( + lpts, + clippingRect, + 0, + this.GetSelectableColor(this.ActualColor), + this.StrokeThickness, + lineStyle, + this.LineJoin, + false); + } + } + + if (this.MarkerType != MarkerType.None) + { + rc.DrawMarkers( + mpts, + clippingRect, + this.MarkerType, + this.MarkerOutline, + new[] { this.MarkerSize }, + this.MarkerFill, + this.MarkerStroke, + this.MarkerStrokeThickness); + } + }; + + // Transform all points to screen coordinates + // Render the line when invalid points occur + var linePoints = new List(); + var markerPoints = new List(); + double previousY = double.NaN; + foreach (var point in this.Points) + { + if (!this.IsValidPoint(point, this.XAxis, this.YAxis)) + { + renderPoints(linePoints, markerPoints); + linePoints.Clear(); + markerPoints.Clear(); + previousY = double.NaN; + continue; + } + + ScreenPoint transformedPoint = this.Transform(point); + if (!double.IsNaN(previousY)) + { + // Horizontal line from the previous point to the current x-coordinate + linePoints.Add(new ScreenPoint(transformedPoint.X, previousY)); + } + + linePoints.Add(transformedPoint); + markerPoints.Add(transformedPoint); + previousY = transformedPoint.Y; + } + + renderPoints(linePoints, markerPoints); + } + } +} \ No newline at end of file diff -r 88d699a65cc2 -r 5be8f2773237 External/OxyPlot/OxyPlot/Series/StemSeries.cs --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/External/OxyPlot/OxyPlot/Series/StemSeries.cs Sat Jun 08 16:53:22 2013 +0000 @@ -0,0 +1,212 @@ +// -------------------------------------------------------------------------------------------------------------------- +// +// The MIT License (MIT) +// +// Copyright (c) 2012 Oystein Bjorke +// +// Permission is hereby granted, free of charge, to any person obtaining a +// copy of this software and associated documentation files (the +// "Software"), to deal in the Software without restriction, including +// without limitation the rights to use, copy, modify, merge, publish, +// distribute, sublicense, and/or sell copies of the Software, and to +// permit persons to whom the Software is furnished to do so, subject to +// the following conditions: +// +// The above copyright notice and this permission notice shall be included +// in all copies or substantial portions of the Software. +// +// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS +// OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF +// MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. +// IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY +// CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, +// TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE +// SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. +// +// +// Represents a series that plots discrete data in a stem plot. +// +// -------------------------------------------------------------------------------------------------------------------- +namespace OxyPlot.Series +{ + using System.Collections.Generic; + + /// + /// Represents a series that plots discrete data in a stem plot. + /// + /// + /// See Stem plot and + /// stem. + /// + public class StemSeries : LineSeries + { + /// + /// Initializes a new instance of the class. + /// + public StemSeries() + { + this.Base = 0; + } + + /// + /// Initializes a new instance of the class. + /// + /// + /// The title. + /// + public StemSeries(string title) + : base(title) + { + this.Title = title; + } + + /// + /// Initializes a new instance of the class. + /// + /// + /// The color of the line stroke. + /// + /// + /// The stroke thickness (optional). + /// + /// + /// The title (optional). + /// + public StemSeries(OxyColor color, double strokeThickness = 1, string title = null) + : base(color, strokeThickness, title) + { + } + + /// + /// Gets or sets Base. + /// + public double Base { get; set; } + + /// + /// Gets the point on the series that is nearest the specified point. + /// + /// + /// The point. + /// + /// + /// Interpolate the series if this flag is set to true. + /// + /// + /// A TrackerHitResult for the current hit. + /// + public override TrackerHitResult GetNearestPoint(ScreenPoint point, bool interpolate) + { + if (this.XAxis == null || this.YAxis == null) + { + return null; + } + + if (interpolate) + { + return null; + } + + TrackerHitResult result = null; + + // http://paulbourke.net/geometry/pointlineplane/ + double minimumDistance = double.MaxValue; + var points = this.Points; + + for (int i = 0; i < points.Count; i++) + { + var p1 = points[i]; + var basePoint = new DataPoint(p1.X, this.Base); + var sp1 = this.Transform(p1); + var sp2 = this.Transform(basePoint); + var u = ScreenPointHelper.FindPositionOnLine(point, sp1, sp2); + + if (double.IsNaN(u)) + { + continue; + } + + if (u < 0 || u > 1) + { + continue; // outside line + } + + var sp = sp1 + ((sp2 - sp1) * u); + double distance = (point - sp).LengthSquared; + + if (distance < minimumDistance) + { + result = new TrackerHitResult( + this, new DataPoint(p1.X, p1.Y), new ScreenPoint(sp1.x, sp1.y), this.GetItem(i)); + minimumDistance = distance; + } + } + + return result; + } + + /// + /// Renders the LineSeries on the specified rendering context. + /// + /// + /// The rendering context. + /// + /// + /// The owner plot model. + /// + public override void Render(IRenderContext rc, PlotModel model) + { + if (this.Points.Count == 0) + { + return; + } + + this.VerifyAxes(); + + double minDistSquared = this.MinimumSegmentLength * this.MinimumSegmentLength; + + var clippingRect = this.GetClippingRect(); + + // Transform all points to screen coordinates + // Render the line when invalid points occur + var markerPoints = new List(); + foreach (var point in this.Points) + { + if (!this.IsValidPoint(point, this.XAxis, this.YAxis)) + { + continue; + } + + var p0 = this.Transform(point.X, this.Base); + var p1 = this.Transform(point.X, point.Y); + + if (this.StrokeThickness > 0 && this.ActualLineStyle != LineStyle.None) + { + rc.DrawClippedLine( + new[] { p0, p1 }, + clippingRect, + minDistSquared, + this.GetSelectableColor(this.ActualColor), + this.StrokeThickness, + this.ActualLineStyle, + this.LineJoin, + false); + } + + markerPoints.Add(p1); + } + + if (this.MarkerType != MarkerType.None) + { + rc.DrawMarkers( + markerPoints, + clippingRect, + this.MarkerType, + this.MarkerOutline, + new[] { this.MarkerSize }, + this.MarkerFill, + this.MarkerStroke, + this.MarkerStrokeThickness); + } + } + } +} \ No newline at end of file diff -r 88d699a65cc2 -r 5be8f2773237 External/OxyPlot/OxyPlot/Series/TwoColorLineSeries.cs --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/External/OxyPlot/OxyPlot/Series/TwoColorLineSeries.cs Sat Jun 08 16:53:22 2013 +0000 @@ -0,0 +1,163 @@ +// -------------------------------------------------------------------------------------------------------------------- +// +// The MIT License (MIT) +// +// Copyright (c) 2012 Oystein Bjorke +// +// Permission is hereby granted, free of charge, to any person obtaining a +// copy of this software and associated documentation files (the +// "Software"), to deal in the Software without restriction, including +// without limitation the rights to use, copy, modify, merge, publish, +// distribute, sublicense, and/or sell copies of the Software, and to +// permit persons to whom the Software is furnished to do so, subject to +// the following conditions: +// +// The above copyright notice and this permission notice shall be included +// in all copies or substantial portions of the Software. +// +// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS +// OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF +// MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. +// IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY +// CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, +// TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE +// SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. +// +// +// Represents a two-color line series. +// +// -------------------------------------------------------------------------------------------------------------------- +namespace OxyPlot.Series +{ + using System.Collections.Generic; + + /// + /// Represents a two-color line series. + /// + public class TwoColorLineSeries : LineSeries + { + /// + /// The default second color. + /// + private OxyColor defaultColor2; + + /// + /// Initializes a new instance of the class. + /// + public TwoColorLineSeries() + { + this.Limit = 0.0; + this.Color2 = OxyColors.Blue; + this.LineStyle2 = LineStyle.Solid; + } + + /// + /// Gets or sets the color for the part of the line that is below the limit. + /// + public OxyColor Color2 { get; set; } + + /// + /// Gets the actual second color. + /// + /// The actual color. + public OxyColor ActualColor2 + { + get { return this.Color2 ?? this.defaultColor2; } + } + + /// + /// Gets or sets the limit. + /// + /// + /// The parts of the line that is below this limit will be rendered with Color2. + /// The parts of the line that is above the limit will be rendered with Color. + /// + public double Limit { get; set; } + + /// + /// Gets or sets the line style for the part of the line that is below the limit. + /// + /// The line style. + public LineStyle LineStyle2 { get; set; } + + /// + /// Gets the actual line style for the part of the line that is below the limit. + /// + /// The line style. + public LineStyle ActualLineStyle2 + { + get + { + return this.LineStyle2 != LineStyle.Undefined ? this.LineStyle2 : LineStyle.Solid; + } + } + + /// + /// The set default values. + /// + /// + /// The model. + /// + protected internal override void SetDefaultValues(PlotModel model) + { + if (this.Color2 == null) + { + this.LineStyle2 = model.GetDefaultLineStyle(); + this.defaultColor2 = model.GetDefaultColor(); + } + } + + /// + /// Renders the smoothed line. + /// + /// + /// The render context. + /// + /// + /// The clipping rect. + /// + /// + /// The points. + /// + protected override void RenderSmoothedLine(IRenderContext rc, OxyRect clippingRect, IList pointsToRender) + { + double bottom = clippingRect.Bottom; + + // todo: this does not work when y axis is reversed + double y = this.YAxis.Transform(this.Limit); + + if (y < clippingRect.Top) + { + y = clippingRect.Top; + } + + if (y > clippingRect.Bottom) + { + y = clippingRect.Bottom; + } + + clippingRect.Bottom = y; + rc.DrawClippedLine( + pointsToRender, + clippingRect, + this.MinimumSegmentLength * this.MinimumSegmentLength, + this.GetSelectableColor(this.ActualColor), + this.StrokeThickness, + this.ActualLineStyle, + this.LineJoin, + false); + clippingRect.Top = y; + clippingRect.Height = bottom - y; + rc.DrawClippedLine( + pointsToRender, + clippingRect, + this.MinimumSegmentLength * this.MinimumSegmentLength, + this.GetSelectableColor(this.ActualColor2), + this.StrokeThickness, + this.ActualLineStyle2, + this.LineJoin, + false); + } + + } +} \ No newline at end of file diff -r 88d699a65cc2 -r 5be8f2773237 External/OxyPlot/OxyPlot/Series/XYAxisSeries.cs --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/External/OxyPlot/OxyPlot/Series/XYAxisSeries.cs Sat Jun 08 16:53:22 2013 +0000 @@ -0,0 +1,424 @@ +// -------------------------------------------------------------------------------------------------------------------- +// +// The MIT License (MIT) +// +// Copyright (c) 2012 Oystein Bjorke +// +// Permission is hereby granted, free of charge, to any person obtaining a +// copy of this software and associated documentation files (the +// "Software"), to deal in the Software without restriction, including +// without limitation the rights to use, copy, modify, merge, publish, +// distribute, sublicense, and/or sell copies of the Software, and to +// permit persons to whom the Software is furnished to do so, subject to +// the following conditions: +// +// The above copyright notice and this permission notice shall be included +// in all copies or substantial portions of the Software. +// +// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS +// OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF +// MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. +// IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY +// CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, +// TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE +// SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. +// +// +// Abstract base class for series that contains an X-axis and Y-axis. +// +// -------------------------------------------------------------------------------------------------------------------- + +namespace OxyPlot.Series +{ + using System; + using System.Collections.Generic; + + using OxyPlot.Axes; + + /// + /// Provides an abstract base class for series that are related to an X-axis and a Y-axis. + /// + public abstract class XYAxisSeries : ItemsSeries + { + /// + /// Gets or sets the maximum x-coordinate of the dataset. + /// + /// The maximum x-coordinate. + public double MaxX { get; protected set; } + + /// + /// Gets or sets the maximum y-coordinate of the dataset. + /// + /// The maximum y-coordinate. + public double MaxY { get; protected set; } + + /// + /// Gets or sets the minimum x-coordinate of the dataset. + /// + /// The minimum x-coordinate. + public double MinX { get; protected set; } + + /// + /// Gets or sets the minimum y-coordinate of the dataset. + /// + /// The minimum y-coordinate. + public double MinY { get; protected set; } + + /// + /// Gets the x-axis. + /// + /// The x-axis. + public Axis XAxis { get; private set; } + + /// + /// Gets or sets the x-axis key. + /// + /// The x-axis key. + public string XAxisKey { get; set; } + + /// + /// Gets the y-axis. + /// + /// The y-axis. + public Axis YAxis { get; private set; } + + /// + /// Gets or sets the y-axis key. + /// + /// The y-axis key. + public string YAxisKey { get; set; } + + /// + /// Gets the rectangle the series uses on the screen (screen coordinates). + /// + /// + /// The rectangle. + /// + public OxyRect GetScreenRectangle() + { + return this.GetClippingRect(); + } + + /// + /// Renders the legend symbol on the specified rendering context. + /// + /// + /// The rendering context. + /// + /// + /// The legend rectangle. + /// + public override void RenderLegend(IRenderContext rc, OxyRect legendBox) + { + } + + /// + /// Transforms from a screen point to a data point by the axes of this series. + /// + /// + /// The screen point. + /// + /// + /// A data point. + /// + public DataPoint InverseTransform(ScreenPoint p) + { + return this.XAxis.InverseTransform(p.X, p.Y, this.YAxis); + } + + /// + /// Transforms the specified coordinates to a screen point by the axes of this series. + /// + /// + /// The x coordinate. + /// + /// + /// The y coordinate. + /// + /// + /// A screen point. + /// + public ScreenPoint Transform(double x, double y) + { + return this.XAxis.Transform(x, y, this.YAxis); + } + + /// + /// Transforms the specified data point to a screen point by the axes of this series. + /// + /// + /// The point. + /// + /// + /// A screen point. + /// + public ScreenPoint Transform(IDataPoint p) + { + return this.XAxis.Transform(p.X, p.Y, this.YAxis); + } + + /// + /// Check if this data series requires X/Y axes. (e.g. Pie series do not require axes) + /// + /// + /// The are axes required. + /// + protected internal override bool AreAxesRequired() + { + return true; + } + + /// + /// Ensures that the axes of the series is defined. + /// + protected internal override void EnsureAxes() + { + this.XAxis = PlotModel.GetAxisOrDefault(this.XAxisKey, PlotModel.DefaultXAxis); + this.YAxis = PlotModel.GetAxisOrDefault(this.YAxisKey, PlotModel.DefaultYAxis); + } + + /// + /// Check if the data series is using the specified axis. + /// + /// + /// An axis. + /// + /// + /// True if the axis is in use. + /// + protected internal override bool IsUsing(Axis axis) + { + return false; + } + + /// + /// Sets default values from the plot model. + /// + /// + /// The plot model. + /// + protected internal override void SetDefaultValues(PlotModel model) + { + } + + /// + /// Updates the axes to include the max and min of this series. + /// + protected internal override void UpdateAxisMaxMin() + { + this.XAxis.Include(this.MinX); + this.XAxis.Include(this.MaxX); + this.YAxis.Include(this.MinY); + this.YAxis.Include(this.MaxY); + } + + /// + /// Updates the data. + /// + protected internal override void UpdateData() + { + } + + /// + /// Updates the max/minimum values. + /// + protected internal override void UpdateMaxMin() + { + this.MinX = this.MinY = this.MaxX = this.MaxY = double.NaN; + } + + /// + /// Gets the clipping rectangle. + /// + /// + /// The clipping rectangle. + /// + protected OxyRect GetClippingRect() + { + double minX = Math.Min(this.XAxis.ScreenMin.X, this.XAxis.ScreenMax.X); + double minY = Math.Min(this.YAxis.ScreenMin.Y, this.YAxis.ScreenMax.Y); + double maxX = Math.Max(this.XAxis.ScreenMin.X, this.XAxis.ScreenMax.X); + double maxY = Math.Max(this.YAxis.ScreenMin.Y, this.YAxis.ScreenMax.Y); + + return new OxyRect(minX, minY, maxX - minX, maxY - minY); + } + + /// + /// Gets the point on the curve that is nearest the specified point. + /// + /// + /// The point list. + /// + /// + /// The point. + /// + /// + /// A tracker hit result if a point was found. + /// + protected TrackerHitResult GetNearestInterpolatedPointInternal(IList points, ScreenPoint point) + { + if (this.XAxis == null || this.YAxis == null || points == null) + { + return null; + } + + var spn = default(ScreenPoint); + var dpn = default(DataPoint); + double index = -1; + + double minimumDistance = double.MaxValue; + + for (int i = 0; i + 1 < points.Count; i++) + { + var p1 = points[i]; + var p2 = points[i + 1]; + if (!this.IsValidPoint(p1, this.XAxis, this.YAxis) || !this.IsValidPoint(p2, this.XAxis, this.YAxis)) + { + continue; + } + + var sp1 = this.Transform(p1); + var sp2 = this.Transform(p2); + + // Find the nearest point on the line segment. + var spl = ScreenPointHelper.FindPointOnLine(point, sp1, sp2); + + if (ScreenPoint.IsUndefined(spl)) + { + // P1 && P2 coincident + continue; + } + + double l2 = (point - spl).LengthSquared; + + if (l2 < minimumDistance) + { + double u = (spl - sp1).Length / (sp2 - sp1).Length; + dpn = new DataPoint(p1.X + (u * (p2.X - p1.X)), p1.Y + (u * (p2.Y - p1.Y))); + spn = spl; + minimumDistance = l2; + index = i + u; + } + } + + if (minimumDistance < double.MaxValue) + { + object item = this.GetItem((int)index); + return new TrackerHitResult(this, dpn, spn, item) { Index = index }; + } + + return null; + } + + /// + /// Gets the nearest point. + /// + /// + /// The points (data coordinates). + /// + /// + /// The point (screen coordinates). + /// + /// + /// A if a point was found, null otherwise. + /// + protected TrackerHitResult GetNearestPointInternal(IEnumerable points, ScreenPoint point) + { + var spn = default(ScreenPoint); + IDataPoint dpn = default(DataPoint); + double index = -1; + + double minimumDistance = double.MaxValue; + int i = 0; + foreach (var p in points) + { + if (!this.IsValidPoint(p, this.XAxis, this.YAxis)) + { + continue; + } + + var sp = Axis.Transform(p, this.XAxis, this.YAxis); + double d2 = (sp - point).LengthSquared; + + if (d2 < minimumDistance) + { + dpn = p; + spn = sp; + minimumDistance = d2; + index = i; + } + + i++; + } + + if (minimumDistance < double.MaxValue) + { + object item = this.GetItem((int)index); + return new TrackerHitResult(this, dpn, spn, item) { Index = index }; + } + + return null; + } + + /// + /// Determines whether the specified point is valid. + /// + /// + /// The point. + /// + /// + /// The x axis. + /// + /// + /// The y axis. + /// + /// + /// true if the point is valid; otherwise, false . + /// + protected virtual bool IsValidPoint(IDataPoint pt, Axis xaxis, Axis yaxis) + { + return !double.IsNaN(pt.X) && !double.IsInfinity(pt.X) && !double.IsNaN(pt.Y) && !double.IsInfinity(pt.Y) + && (xaxis != null && xaxis.IsValidValue(pt.X)) && (yaxis != null && yaxis.IsValidValue(pt.Y)); + } + + /// + /// Converts the value of the specified object to a double precision floating point number. DateTime objects are converted using DateTimeAxis.ToDouble and TimeSpan objects are converted using TimeSpanAxis.ToDouble + /// + /// + /// The value. + /// + /// + /// The floating point number value. + /// + protected virtual double ToDouble(object value) + { + if (value is DateTime) + { + return DateTimeAxis.ToDouble((DateTime)value); + } + + if (value is TimeSpan) + { + return ((TimeSpan)value).TotalSeconds; + } + + return Convert.ToDouble(value); + } + + /// + /// Verifies that both axes are defined. + /// + protected void VerifyAxes() + { + if (this.XAxis == null) + { + throw new InvalidOperationException("XAxis not defined."); + } + + if (this.YAxis == null) + { + throw new InvalidOperationException("YAxis not defined."); + } + } + } +} \ No newline at end of file diff -r 88d699a65cc2 -r 5be8f2773237 External/OxyPlot/OxyPlot/Svg/NativeMethods.cs --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/External/OxyPlot/OxyPlot/Svg/NativeMethods.cs Sat Jun 08 16:53:22 2013 +0000 @@ -0,0 +1,246 @@ +// -------------------------------------------------------------------------------------------------------------------- +// +// The MIT License (MIT) +// +// Copyright (c) 2012 Oystein Bjorke +// +// Permission is hereby granted, free of charge, to any person obtaining a +// copy of this software and associated documentation files (the +// "Software"), to deal in the Software without restriction, including +// without limitation the rights to use, copy, modify, merge, publish, +// distribute, sublicense, and/or sell copies of the Software, and to +// permit persons to whom the Software is furnished to do so, subject to +// the following conditions: +// +// The above copyright notice and this permission notice shall be included +// in all copies or substantial portions of the Software. +// +// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS +// OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF +// MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. +// IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY +// CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, +// TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE +// SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. +// +// +// Interface to GDI32 native methods. +// +// -------------------------------------------------------------------------------------------------------------------- +namespace OxyPlot +{ + using System; + using System.Runtime.InteropServices; + using System.Text.RegularExpressions; + + /// + /// Provides access to native graphics methods. + /// + public class NativeMethods + { + /// + /// The delete dc. + /// + /// + /// The hdc. + /// + /// + /// The delete dc. + /// + [DllImport("gdi32.dll")] + internal static extern bool DeleteDC(IntPtr hdc); + + /// + /// The delete object. + /// + /// + /// The hgdiobj. + /// + /// + /// The delete object. + /// + [DllImport("gdi32.dll")] + internal static extern int DeleteObject(IntPtr hgdiobj); + + /// + /// The get dc. + /// + /// + /// The h wnd. + /// + /// + /// + [DllImport("user32.dll")] + internal static extern IntPtr GetDC(IntPtr hWnd); + + /// + /// The get text extent point 32. + /// + /// + /// The hdc. + /// + /// + /// The str. + /// + /// + /// The len. + /// + /// + /// The siz. + /// + /// + /// The get text extent point 32. + /// + [DllImport("gdi32.dll", CharSet = CharSet.Unicode)] + internal static extern int GetTextExtentPoint32(IntPtr hdc, string str, int len, ref Size siz); + + /// + /// The measure string. + /// + /// + /// The font face name. + /// + /// + /// The height. + /// + /// + /// The weight. + /// + /// + /// The string. + /// + /// + /// The size of the rendered string. + /// + public static OxySize MeasureString(string faceName, int height, int weight, string str) + { + var lines = Regex.Split(str, "\r\n"); + OxySize result = new OxySize(0, 0); + foreach (var line in lines) + { + var hfont = CreateFont(height, 0, 0, 0, weight, 0, 0, 0, 0, 0, 0, 0, 0, faceName); + var hdc = GetDC(IntPtr.Zero); + var oldobj = SelectObject(hdc, hfont); + var temp = GetTextExtent(hdc, line); + SelectObject(hdc, oldobj); + DeleteObject(hfont); + DeleteDC(hdc); + var lineSpacing = temp.Height / 3.0; + result.Height += temp.Height + lineSpacing; + result.Width = Math.Max(temp.Width * 1.28, result.Width); + } + + return result; + } + + /// + /// The select object. + /// + /// + /// The hdc. + /// + /// + /// The hgdi obj. + /// + /// + /// + [DllImport("gdi32.dll")] + internal static extern IntPtr SelectObject(IntPtr hdc, IntPtr hgdiObj); + + /// + /// The create font. + /// + /// + /// The n height. + /// + /// + /// The n width. + /// + /// + /// The n escapement. + /// + /// + /// The n orientation. + /// + /// + /// The fn weight. + /// + /// + /// The fdw italic. + /// + /// + /// The fdw underline. + /// + /// + /// The fdw strike out. + /// + /// + /// The fdw char set. + /// + /// + /// The fdw output precision. + /// + /// + /// The fdw clip precision. + /// + /// + /// The fdw quality. + /// + /// + /// The fdw pitch and family. + /// + /// + /// The lpsz face. + /// + /// + /// + [DllImport("gdi32.dll", CharSet = CharSet.Unicode)] + private static extern IntPtr CreateFont( + int nHeight, + int nWidth, + int nEscapement, + int nOrientation, + int fnWeight, + uint fdwItalic, + uint fdwUnderline, + uint fdwStrikeOut, + uint fdwCharSet, + uint fdwOutputPrecision, + uint fdwClipPrecision, + uint fdwQuality, + uint fdwPitchAndFamily, + string lpszFace); + + /// + /// Gets the text extent. + /// + /// The HDC. + /// The STR. + /// + private static OxySize GetTextExtent(IntPtr hdc, string str) + { + Size sz = default(Size); + sz.cx = 0; + sz.cy = 0; + GetTextExtentPoint32(hdc, str, str.Length, ref sz); + return new OxySize(sz.cx, sz.cy); + } + + /// + /// The size. + /// + [StructLayout(LayoutKind.Sequential)] + public struct Size + { + /// + /// The cx. + /// + public int cx; + + /// + /// The cy. + /// + public int cy; + } + } +} \ No newline at end of file diff -r 88d699a65cc2 -r 5be8f2773237 External/OxyPlot/OxyPlot/Svg/SvgExporter.cs --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/External/OxyPlot/OxyPlot/Svg/SvgExporter.cs Sat Jun 08 16:53:22 2013 +0000 @@ -0,0 +1,85 @@ +// -------------------------------------------------------------------------------------------------------------------- +// +// The MIT License (MIT) +// +// Copyright (c) 2012 Oystein Bjorke +// +// Permission is hereby granted, free of charge, to any person obtaining a +// copy of this software and associated documentation files (the +// "Software"), to deal in the Software without restriction, including +// without limitation the rights to use, copy, modify, merge, publish, +// distribute, sublicense, and/or sell copies of the Software, and to +// permit persons to whom the Software is furnished to do so, subject to +// the following conditions: +// +// The above copyright notice and this permission notice shall be included +// in all copies or substantial portions of the Software. +// +// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS +// OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF +// MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. +// IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY +// CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, +// TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE +// SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. +// +// +// Exports plot models to svg. +// +// -------------------------------------------------------------------------------------------------------------------- +namespace OxyPlot +{ + using System.IO; + + /// + /// Exports plots to scalable vector graphics. + /// + public static class SvgExporter + { + /// + /// Exports the specified model to a stream. + /// + /// The model. + /// The output stream. + /// The width (points). + /// The height (points). + /// if set to true, the xml headers will be included (?xml and !DOCTYPE). + /// The text measurer. + public static void Export(PlotModel model, Stream stream, double width, double height, bool isDocument, IRenderContext textMeasurer) + { + using (var rc = new SvgRenderContext(stream, width, height, true, textMeasurer, model.Background)) + { + model.Update(); + model.Render(rc, width, height); + rc.Complete(); + rc.Flush(); + } + } + + /// + /// Exports to string. + /// + /// The model. + /// The width (points). + /// The height (points). + /// if set to true, the xml headers will be included (?xml and !DOCTYPE). + /// The text measurer. + /// + /// The plot as a svg string. + /// + public static string ExportToString(PlotModel model, double width, double height, bool isDocument, IRenderContext textMeasurer) + { + string svg; + using (var ms = new MemoryStream()) + { + Export(model, ms, width, height, isDocument, textMeasurer); + ms.Flush(); + ms.Position = 0; + var sr = new StreamReader(ms); + svg = sr.ReadToEnd(); + } + + return svg; + } + } +} \ No newline at end of file diff -r 88d699a65cc2 -r 5be8f2773237 External/OxyPlot/OxyPlot/Svg/SvgRenderContext.cs --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/External/OxyPlot/OxyPlot/Svg/SvgRenderContext.cs Sat Jun 08 16:53:22 2013 +0000 @@ -0,0 +1,278 @@ +// -------------------------------------------------------------------------------------------------------------------- +// +// The MIT License (MIT) +// +// Copyright (c) 2012 Oystein Bjorke +// +// Permission is hereby granted, free of charge, to any person obtaining a +// copy of this software and associated documentation files (the +// "Software"), to deal in the Software without restriction, including +// without limitation the rights to use, copy, modify, merge, publish, +// distribute, sublicense, and/or sell copies of the Software, and to +// permit persons to whom the Software is furnished to do so, subject to +// the following conditions: +// +// The above copyright notice and this permission notice shall be included +// in all copies or substantial portions of the Software. +// +// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS +// OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF +// MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. +// IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY +// CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, +// TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE +// SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. +// +// +// The svg render context. +// +// -------------------------------------------------------------------------------------------------------------------- +namespace OxyPlot +{ + using System; + using System.Collections.Generic; + using System.IO; + using System.Text.RegularExpressions; + + /// + /// Provides a render context for scalable vector graphics output. + /// + public class SvgRenderContext : RenderContextBase, IDisposable + { + /// + /// The writer. + /// + private readonly SvgWriter w; + + /// + /// The disposed flag. + /// + private bool disposed; + + /// + /// Initializes a new instance of the class. + /// + /// The s. + /// The width. + /// The height. + /// Create an SVG document if set to true. + /// The text measurer. + /// The background. + public SvgRenderContext(Stream s, double width, double height, bool isDocument, IRenderContext textMeasurer, OxyColor background) + { + if (textMeasurer == null) + { + throw new ArgumentNullException("textMeasurer", "A text measuring render context must be provided."); + } + + this.w = new SvgWriter(s, width, height, isDocument); + this.TextMeasurer = textMeasurer; + if (background != null) + { + this.w.WriteRectangle(0, 0, width, height, this.w.CreateStyle(background, null, 0)); + } + } + + /// + /// Gets or sets the text measurer. + /// + /// + /// The text measurer. + /// + public IRenderContext TextMeasurer { get; set; } + + /// + /// Closes the svg writer. + /// + public void Close() + { + this.w.Close(); + } + + /// + /// Completes the svg element. + /// + public void Complete() + { + this.w.Complete(); + } + + /// + /// Performs application-defined tasks associated with freeing, releasing, or resetting unmanaged resources. + /// + public void Dispose() + { + this.Dispose(true); + GC.SuppressFinalize(this); + } + + /// + /// Draws an ellipse. + /// + /// The rectangle. + /// The fill color. + /// The stroke color. + /// The thickness. + public override void DrawEllipse(OxyRect rect, OxyColor fill, OxyColor stroke, double thickness) + { + this.w.WriteEllipse( + rect.Left, rect.Top, rect.Width, rect.Height, this.w.CreateStyle(fill, stroke, thickness)); + } + + /// + /// Draws the polyline from the specified points. + /// + /// The points. + /// The stroke color. + /// The stroke thickness. + /// The dash array. + /// The line join type. + /// if set to true the shape will be aliased. + public override void DrawLine( + IList points, + OxyColor stroke, + double thickness, + double[] dashArray, + OxyPenLineJoin lineJoin, + bool aliased) + { + this.w.WritePolyline(points, this.w.CreateStyle(null, stroke, thickness, dashArray, lineJoin)); + } + + /// + /// Draws the polygon from the specified points. The polygon can have stroke and/or fill. + /// + /// The points. + /// The fill color. + /// The stroke color. + /// The stroke thickness. + /// The dash array. + /// The line join type. + /// if set to true the shape will be aliased. + public override void DrawPolygon( + IList points, + OxyColor fill, + OxyColor stroke, + double thickness, + double[] dashArray, + OxyPenLineJoin lineJoin, + bool aliased) + { + this.w.WritePolygon(points, this.w.CreateStyle(fill, stroke, thickness, dashArray, lineJoin)); + } + + /// + /// Draws the rectangle. + /// + /// The rectangle. + /// The fill color. + /// The stroke color. + /// The stroke thickness. + public override void DrawRectangle(OxyRect rect, OxyColor fill, OxyColor stroke, double thickness) + { + this.w.WriteRectangle( + rect.Left, rect.Top, rect.Width, rect.Height, this.w.CreateStyle(fill, stroke, thickness)); + } + + /// + /// Draws the text. + /// + /// The p. + /// The text. + /// The c. + /// The font family. + /// Size of the font. + /// The font weight. + /// The rotate. + /// The horizontal alignment. + /// The vertical alignment. + /// Size of the max. + public override void DrawText( + ScreenPoint p, + string text, + OxyColor c, + string fontFamily, + double fontSize, + double fontWeight, + double rotate, + HorizontalAlignment halign, + VerticalAlignment valign, + OxySize? maxSize) + { + if (string.IsNullOrEmpty(text)) + { + return; + } + + var lines = Regex.Split(text, "\r\n"); + if (valign == VerticalAlignment.Bottom) + { + for (var i = lines.Length - 1; i >= 0; i--) + { + var line = lines[i]; + var size = this.MeasureText(line, fontFamily, fontSize, fontWeight); + this.w.WriteText(p, line, c, fontFamily, fontSize, fontWeight, rotate, halign, valign); + + p.X += Math.Sin(rotate / 180.0 * Math.PI) * size.Height; + p.Y -= Math.Cos(rotate / 180.0 * Math.PI) * size.Height; + } + } + else + { + foreach (var line in lines) + { + var size = this.MeasureText(line, fontFamily, fontSize, fontWeight); + this.w.WriteText(p, line, c, fontFamily, fontSize, fontWeight, rotate, halign, valign); + + p.X -= Math.Sin(rotate / 180.0 * Math.PI) * size.Height; + p.Y += Math.Cos(rotate / 180.0 * Math.PI) * size.Height; + } + } + } + + /// + /// Flushes this instance. + /// + public void Flush() + { + this.w.Flush(); + } + + /// + /// Measures the text. + /// + /// The text. + /// The font family. + /// Size of the font. + /// The font weight. + /// + /// The text size. + /// + public override OxySize MeasureText(string text, string fontFamily, double fontSize, double fontWeight) + { + if (string.IsNullOrEmpty(text)) + { + return OxySize.Empty; + } + + return this.TextMeasurer.MeasureText(text, fontFamily, fontSize, fontWeight); + } + + /// + /// Releases unmanaged and - optionally - managed resources + /// + /// true to release both managed and unmanaged resources; false to release only unmanaged resources. + private void Dispose(bool disposing) + { + if (!this.disposed) + { + if (disposing) + { + this.w.Dispose(); + } + } + + this.disposed = true; + } + } +} \ No newline at end of file diff -r 88d699a65cc2 -r 5be8f2773237 External/OxyPlot/OxyPlot/Svg/SvgWriter.cs --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/External/OxyPlot/OxyPlot/Svg/SvgWriter.cs Sat Jun 08 16:53:22 2013 +0000 @@ -0,0 +1,502 @@ +// -------------------------------------------------------------------------------------------------------------------- +// +// The MIT License (MIT) +// +// Copyright (c) 2012 Oystein Bjorke +// +// Permission is hereby granted, free of charge, to any person obtaining a +// copy of this software and associated documentation files (the +// "Software"), to deal in the Software without restriction, including +// without limitation the rights to use, copy, modify, merge, publish, +// distribute, sublicense, and/or sell copies of the Software, and to +// permit persons to whom the Software is furnished to do so, subject to +// the following conditions: +// +// The above copyright notice and this permission notice shall be included +// in all copies or substantial portions of the Software. +// +// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS +// OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF +// MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. +// IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY +// CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, +// TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE +// SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. +// +// +// Scalable Vector Graphics writer. +// +// -------------------------------------------------------------------------------------------------------------------- +namespace OxyPlot +{ + using System; + using System.Collections.Generic; + using System.Globalization; + using System.IO; + using System.Text; + + /// + /// Represents a writer that provides easy generation of Scalable Vector Graphics files. + /// + public class SvgWriter : XmlWriterBase + { + /// + /// The end is written. + /// + private bool endIsWritten; + + /// + /// Initializes a new instance of the class. + /// + /// + /// The stream. + /// + /// + /// The width. + /// + /// + /// The height. + /// + /// + /// if set to true, the writer will write the xml headers (?xml and !DOCTYPE). + /// + public SvgWriter(Stream stream, double width, double height, bool isDocument = true) + : base(stream) + { + this.IsDocument = isDocument; + this.NumberFormat = "0.####"; + this.WriteHeader(width, height); + } + + /// + /// Gets or sets a value indicating whether this writer should produce a stand-alone document. + /// + public bool IsDocument { get; set; } + + /// + /// Gets or sets the number format. + /// + /// The number format. + public string NumberFormat { get; set; } + + /// + /// Closes the svg document. + /// + public override void Close() + { + if (!this.endIsWritten) + { + this.Complete(); + } + + base.Close(); + } + + /// + /// Writes the end of the document. + /// + public void Complete() + { + this.WriteEndElement(); + if (this.IsDocument) + { + this.WriteEndDocument(); + } + + this.endIsWritten = true; + } + + /// + /// Creates a style. + /// + /// + /// The fill color. + /// + /// + /// The stroke color. + /// + /// + /// The stroke thickness. + /// + /// + /// The line dash array. + /// + /// + /// The line join type. + /// + /// + /// A style string. + /// + public string CreateStyle( + OxyColor fill, + OxyColor stroke, + double thickness, + double[] dashArray = null, + OxyPenLineJoin lineJoin = OxyPenLineJoin.Miter) + { + // http://oreilly.com/catalog/svgess/chapter/ch03.html + var style = new StringBuilder(); + if (fill == null) + { + style.AppendFormat("fill:none;"); + } + else + { + style.AppendFormat("fill:{0};", this.ColorToString(fill)); + if (fill.A != 0xFF) + { + style.AppendFormat(CultureInfo.InvariantCulture, "fill-opacity:{0};", fill.A / 255.0); + } + } + + if (stroke == null) + { + style.AppendFormat("stroke:none;"); + } + else + { + string formatString = "stroke:{0};stroke-width:{1:" + this.NumberFormat + "}"; + style.AppendFormat(formatString, this.ColorToString(stroke), thickness); + switch (lineJoin) + { + case OxyPenLineJoin.Round: + style.AppendFormat(";stroke-linejoin:round"); + break; + case OxyPenLineJoin.Bevel: + style.AppendFormat(";stroke-linejoin:bevel"); + break; + } + + if (stroke.A != 0xFF) + { + style.AppendFormat(CultureInfo.InvariantCulture, ";stroke-opacity:{0}", stroke.A / 255.0); + } + + if (dashArray != null && dashArray.Length > 0) + { + style.Append(";stroke-dasharray:"); + for (int i = 0; i < dashArray.Length; i++) + { + style.AppendFormat( + CultureInfo.InvariantCulture, "{0}{1}", i > 0 ? "," : string.Empty, dashArray[i]); + } + } + } + + return style.ToString(); + } + + /// + /// Writes an ellipse. + /// + /// + /// The x coordinate of the center. + /// + /// + /// The y coordinate of the center. + /// + /// + /// The width. + /// + /// + /// The height. + /// + /// + /// The style. + /// + public void WriteEllipse(double x, double y, double width, double height, string style) + { + // http://www.w3.org/TR/SVG/shapes.html#EllipseElement + this.WriteStartElement("ellipse"); + this.WriteAttributeString("cx", x + (width / 2)); + this.WriteAttributeString("cy", y + (height / 2)); + this.WriteAttributeString("rx", width / 2); + this.WriteAttributeString("ry", height / 2); + this.WriteAttributeString("style", style); + this.WriteEndElement(); + } + + /// + /// Writes a line. + /// + /// + /// The first point. + /// + /// + /// The second point. + /// + /// + /// The style. + /// + public void WriteLine(ScreenPoint p1, ScreenPoint p2, string style) + { + // http://www.w3.org/TR/SVG/shapes.html#LineElement + // http://www.w3schools.com/svg/svg_line.asp + this.WriteStartElement("line"); + this.WriteAttributeString("x1", p1.X); + this.WriteAttributeString("y1", p1.Y); + this.WriteAttributeString("x2", p2.X); + this.WriteAttributeString("y2", p2.Y); + this.WriteAttributeString("style", style); + this.WriteEndElement(); + } + + /// + /// Writes a polygon. + /// + /// + /// The points. + /// + /// + /// The style. + /// + public void WritePolygon(IEnumerable points, string style) + { + // http://www.w3.org/TR/SVG/shapes.html#PolygonElement + this.WriteStartElement("polygon"); + this.WriteAttributeString("points", this.PointsToString(points)); + this.WriteAttributeString("style", style); + this.WriteEndElement(); + } + + /// + /// Writes a polyline. + /// + /// + /// The points. + /// + /// + /// The style. + /// + public void WritePolyline(IEnumerable pts, string style) + { + // http://www.w3.org/TR/SVG/shapes.html#PolylineElement + this.WriteStartElement("polyline"); + this.WriteAttributeString("points", this.PointsToString(pts)); + this.WriteAttributeString("style", style); + this.WriteEndElement(); + } + + /// + /// Writes a rectangle. + /// + /// + /// The x coordinate. + /// + /// + /// The y coordinate. + /// + /// + /// The width. + /// + /// + /// The height. + /// + /// + /// The style. + /// + public void WriteRectangle(double x, double y, double width, double height, string style) + { + // http://www.w3.org/TR/SVG/shapes.html#RectangleElement + this.WriteStartElement("rect"); + this.WriteAttributeString("x", x); + this.WriteAttributeString("y", y); + this.WriteAttributeString("width", width); + this.WriteAttributeString("height", height); + this.WriteAttributeString("style", style); + this.WriteEndElement(); + } + + /// + /// Writes text. + /// + /// + /// The position. + /// + /// + /// The text. + /// + /// + /// The text color. + /// + /// + /// The font family. + /// + /// + /// The font size. + /// + /// + /// The font weight. + /// + /// + /// The rotation angle. + /// + /// + /// The horizontal alignment. + /// + /// + /// The vertical alignment. + /// + public void WriteText( + ScreenPoint position, + string text, + OxyColor fill, + string fontFamily = null, + double fontSize = 10, + double fontWeight = FontWeights.Normal, + double rotate = 0, + HorizontalAlignment halign = HorizontalAlignment.Left, + VerticalAlignment valign = VerticalAlignment.Top) + { + // http://www.w3.org/TR/SVG/text.html + this.WriteStartElement("text"); + + // WriteAttributeString("x", position.X); + // WriteAttributeString("y", position.Y); + string baselineAlignment = "hanging"; + if (valign == VerticalAlignment.Middle) + { + baselineAlignment = "middle"; + } + + if (valign == VerticalAlignment.Bottom) + { + baselineAlignment = "baseline"; + } + + this.WriteAttributeString("dominant-baseline", baselineAlignment); + + string textAnchor = "start"; + if (halign == HorizontalAlignment.Center) + { + textAnchor = "middle"; + } + + if (halign == HorizontalAlignment.Right) + { + textAnchor = "end"; + } + + this.WriteAttributeString("text-anchor", textAnchor); + + string fmt = "translate({0:" + this.NumberFormat + "},{1:" + this.NumberFormat + "})"; + string transform = string.Format(CultureInfo.InvariantCulture, fmt, position.X, position.Y); + if (Math.Abs(rotate) > 0) + { + transform += string.Format(CultureInfo.InvariantCulture, " rotate({0})", rotate); + } + + this.WriteAttributeString("transform", transform); + + if (fontFamily != null) + { + this.WriteAttributeString("font-family", fontFamily); + } + + if (fontSize > 0) + { + this.WriteAttributeString("font-size", fontSize); + } + + if (fontWeight > 0) + { + this.WriteAttributeString("font-weight", fontWeight); + } + + this.WriteAttributeString("fill", this.ColorToString(fill)); + + // WriteAttributeString("style", style); + this.WriteString(text); + this.WriteEndElement(); + } + + /// + /// Converts a color to a svg color string. + /// + /// The color. + /// The color string. + protected string ColorToString(OxyColor color) + { + if (color == OxyColors.Black) + { + return "black"; + } + + var formatString = "rgb({0:" + this.NumberFormat + "},{1:" + this.NumberFormat + "},{2:" + this.NumberFormat + "})"; + return string.Format(formatString, color.R, color.G, color.B); + } + + /// + /// The write attribute string. + /// + /// + /// The name. + /// + /// + /// The value. + /// + protected void WriteAttributeString(string name, double value) + { + this.WriteAttributeString(name, value.ToString(this.NumberFormat, CultureInfo.InvariantCulture)); + } + + /// + /// Converts a value to a string or to the specified "auto" string if the value is NaN. + /// + /// The value. + /// The string to return if value is NaN. + /// A string. + private string GetAutoValue(double value, string auto) + { + if (double.IsNaN(value)) + { + return auto; + } + + return value.ToString(this.NumberFormat, CultureInfo.InvariantCulture); + } + + /// + /// Converts a list of points to a string. + /// + /// The points. + /// A string. + private string PointsToString(IEnumerable points) + { + var sb = new StringBuilder(); + string fmt = "{0:" + this.NumberFormat + "},{1:" + this.NumberFormat + "} "; + foreach (var p in points) + { + sb.AppendFormat(CultureInfo.InvariantCulture, fmt, p.X, p.Y); + } + + return sb.ToString().Trim(); + } + + /// + /// The write header. + /// + /// + /// The width. + /// + /// + /// The height. + /// + private void WriteHeader(double width, double height) + { + // http://www.w3.org/TR/SVG/struct.html#SVGElement + if (this.IsDocument) + { + this.WriteStartDocument(false); + this.WriteDocType( + "svg", "-//W3C//DTD SVG 1.1//EN", "http://www.w3.org/Graphics/SVG/1.1/DTD/svg11.dtd", null); + } + + this.WriteStartElement("svg", "http://www.w3.org/2000/svg"); + this.WriteAttributeString("width", this.GetAutoValue(width, "100%")); + this.WriteAttributeString("height", this.GetAutoValue(height, "100%")); + this.WriteAttributeString("version", "1.1"); + } + + } +} \ No newline at end of file