[longomatch] Import oxyplot library (d190d7748a73)



commit 0a66aa6dca79a358fb81ae2fc3d0a00e3638f742
Author: Andoni Morales Alastruey <ylatuya gmail com>
Date:   Sat Jun 1 12:57:47 2013 +0200

    Import oxyplot library (d190d7748a73)

 oxyplot/GlobalAssemblyInfo.cs                      |   38 +
 oxyplot/OxyPlot.sln                                |  779 +++++++++
 oxyplot/OxyPlot/Annotations/Annotation.cs          |  181 ++
 oxyplot/OxyPlot/Annotations/AnnotationLayer.cs     |   52 +
 oxyplot/OxyPlot/Annotations/ArrowAnnotation.cs     |  228 +++
 oxyplot/OxyPlot/Annotations/EllipseAnnotation.cs   |  152 ++
 oxyplot/OxyPlot/Annotations/ImageAnnotation.cs     |  451 +++++
 oxyplot/OxyPlot/Annotations/LineAnnotation.cs      |  528 ++++++
 oxyplot/OxyPlot/Annotations/LineAnnotationType.cs  |   62 +
 oxyplot/OxyPlot/Annotations/PolygonAnnotation.cs   |  166 ++
 oxyplot/OxyPlot/Annotations/RectangleAnnotation.cs |  174 ++
 oxyplot/OxyPlot/Annotations/TextAnnotation.cs      |  254 +++
 oxyplot/OxyPlot/Annotations/TextualAnnotation.cs   |   46 +
 oxyplot/OxyPlot/Annotations/TileMapAnnotation.cs   |  457 +++++
 oxyplot/OxyPlot/Axes/AngleAxis.cs                  |  184 ++
 oxyplot/OxyPlot/Axes/Axis.cs                       | 1753 ++++++++++++++++++++
 oxyplot/OxyPlot/Axes/AxisChangeTypes.cs            |   52 +
 oxyplot/OxyPlot/Axes/AxisChangedEventArgs.cs       |   57 +
 oxyplot/OxyPlot/Axes/AxisLayer.cs                  |   47 +
 oxyplot/OxyPlot/Axes/AxisPosition.cs               |   62 +
 oxyplot/OxyPlot/Axes/CategoryAxis.cs               |  501 ++++++
 oxyplot/OxyPlot/Axes/ColorAxis.cs                  |  283 ++++
 oxyplot/OxyPlot/Axes/DateTimeAxis.cs               |  679 ++++++++
 oxyplot/OxyPlot/Axes/DateTimeIntervalType.cs       |   87 +
 oxyplot/OxyPlot/Axes/LinearAxis.cs                 |  164 ++
 oxyplot/OxyPlot/Axes/LogarithmicAxis.cs            |  406 +++++
 oxyplot/OxyPlot/Axes/MagnitudeAxis.cs              |  205 +++
 oxyplot/OxyPlot/Axes/RangeAxis.cs                  |  469 ++++++
 oxyplot/OxyPlot/Axes/TickStyle.cs                  |   57 +
 oxyplot/OxyPlot/Axes/TimeAxis.cs                   |  120 ++
 oxyplot/OxyPlot/Axes/TimeSpanAxis.cs               |  197 +++
 oxyplot/OxyPlot/ClassDiagrams/PlotModel.cd         |  276 +++
 oxyplot/OxyPlot/ClassDiagrams/Reporting.cd         |  204 +++
 oxyplot/OxyPlot/ClassDiagrams/Series.cd            |  161 ++
 oxyplot/OxyPlot/Foundation/ArrayHelper.cs          |  124 ++
 .../OxyPlot/Foundation/CanonicalSplineHelper.cs    |  252 +++
 .../CodeGenerator/CodeGenerationAttribute.cs       |   57 +
 .../Foundation/CodeGenerator/CodeGenerator.cs      |  448 +++++
 .../CodeGenerator/CodeGeneratorStringExtensions.cs |  188 +++
 .../Foundation/CodeGenerator/ICodeGenerating.cs    |   45 +
 .../OxyPlot/Foundation/CohenSutherlandClipping.cs  |  298 ++++
 oxyplot/OxyPlot/Foundation/Color.cs                |   55 +
 oxyplot/OxyPlot/Foundation/Colors.cs               |   45 +
 oxyplot/OxyPlot/Foundation/Conrec.cs               |  294 ++++
 oxyplot/OxyPlot/Foundation/DataPoint.cs            |  136 ++
 oxyplot/OxyPlot/Foundation/DataPointConverter.cs   |   82 +
 oxyplot/OxyPlot/Foundation/DoubleExtensions.cs     |  236 +++
 oxyplot/OxyPlot/Foundation/FontWeights.cs          |   48 +
 oxyplot/OxyPlot/Foundation/FractionHelper.cs       |  155 ++
 oxyplot/OxyPlot/Foundation/HorizontalAlignment.cs  |   52 +
 oxyplot/OxyPlot/Foundation/IDataPoint.cs           |   49 +
 oxyplot/OxyPlot/Foundation/IDataPointProvider.cs   |   45 +
 oxyplot/OxyPlot/Foundation/LineStyle.cs            |   97 ++
 oxyplot/OxyPlot/Foundation/LineStyleHelper.cs      |   76 +
 oxyplot/OxyPlot/Foundation/ListFiller.cs           |  145 ++
 oxyplot/OxyPlot/Foundation/MarkerType.cs           |   91 +
 oxyplot/OxyPlot/Foundation/OxyColor.cs             |  626 +++++++
 oxyplot/OxyPlot/Foundation/OxyColorConverter.cs    |  135 ++
 oxyplot/OxyPlot/Foundation/OxyColors.cs            |  743 +++++++++
 oxyplot/OxyPlot/Foundation/OxyImage.cs             |  444 +++++
 oxyplot/OxyPlot/Foundation/OxyPalette.cs           |  102 ++
 oxyplot/OxyPlot/Foundation/OxyPalettes.cs          |  208 +++
 oxyplot/OxyPlot/Foundation/OxyPen.cs               |  138 ++
 oxyplot/OxyPlot/Foundation/OxyPenLineJoin.cs       |   52 +
 oxyplot/OxyPlot/Foundation/OxyRect.cs              |  287 ++++
 oxyplot/OxyPlot/Foundation/OxySize.cs              |   87 +
 oxyplot/OxyPlot/Foundation/OxyThickness.cs         |  220 +++
 oxyplot/OxyPlot/Foundation/Pen.cs                  |   42 +
 oxyplot/OxyPlot/Foundation/PlotLength.cs           |   91 +
 oxyplot/OxyPlot/Foundation/PlotLengthUnit.cs       |   58 +
 oxyplot/OxyPlot/Foundation/PngEncoder.cs           |  323 ++++
 oxyplot/OxyPlot/Foundation/Point.cs                |   58 +
 oxyplot/OxyPlot/Foundation/Rectangle.cs            |   36 +
 oxyplot/OxyPlot/Foundation/ReflectionHelper.cs     |   81 +
 oxyplot/OxyPlot/Foundation/ScreenPoint.cs          |  198 +++
 oxyplot/OxyPlot/Foundation/ScreenPointHelper.cs    |  255 +++
 oxyplot/OxyPlot/Foundation/ScreenVector.cs         |  155 ++
 oxyplot/OxyPlot/Foundation/Size.cs                 |   43 +
 oxyplot/OxyPlot/Foundation/StreamExtensions.cs     |   25 +
 oxyplot/OxyPlot/Foundation/StringHelper.cs         |  169 ++
 .../Foundation/SutherlandHodgmanClipping.cs        |  233 +++
 oxyplot/OxyPlot/Foundation/VerticalAlignment.cs    |   52 +
 oxyplot/OxyPlot/Foundation/XmlWriterBase.cs        |  233 +++
 oxyplot/OxyPlot/LibraryDoc.cs                      |   37 +
 oxyplot/OxyPlot/Manipulators/CursorType.cs         |   62 +
 oxyplot/OxyPlot/Manipulators/IPlotControl.cs       |  176 ++
 .../OxyPlot/Manipulators/ManipulationEventArgs.cs  |   67 +
 oxyplot/OxyPlot/Manipulators/ManipulatorBase.cs    |  151 ++
 oxyplot/OxyPlot/Manipulators/PanManipulator.cs     |  100 ++
 oxyplot/OxyPlot/Manipulators/ResetManipulator.cs   |   71 +
 oxyplot/OxyPlot/Manipulators/TrackerHitResult.cs   |  162 ++
 oxyplot/OxyPlot/Manipulators/TrackerManipulator.cs |  186 +++
 oxyplot/OxyPlot/Manipulators/ZoomManipulator.cs    |   72 +
 .../Manipulators/ZoomRectangleManipulator.cs       |  154 ++
 .../OxyPlot/Manipulators/ZoomStepManipulator.cs    |  106 ++
 oxyplot/OxyPlot/MouseActions/MouseAction.cs        |   54 +
 oxyplot/OxyPlot/MouseActions/SliderAction.cs       |  106 ++
 oxyplot/OxyPlot/NamespaceDoc.cs                    |   37 +
 oxyplot/OxyPlot/OxyPlot.csproj                     |  230 +++
 oxyplot/OxyPlot/OxyPlot.csproj.DotSettings         |   15 +
 oxyplot/OxyPlot/OxyPlot.csproj.ReSharper           |   16 +
 oxyplot/OxyPlot/OxyPlot.snk                        |  Bin 0 -> 596 bytes
 oxyplot/OxyPlot/OxyPlotMT.csproj                   |  229 +++
 oxyplot/OxyPlot/OxyPlotMfA.csproj                  |  238 +++
 oxyplot/OxyPlot/OxyPlot_NET40x.csproj              |  237 +++
 oxyplot/OxyPlot/PlotModel/HitTestResult.cs         |   79 +
 oxyplot/OxyPlot/PlotModel/OxyMouseButton.cs        |   67 +
 oxyplot/OxyPlot/PlotModel/OxyMouseEventArgs.cs     |   87 +
 oxyplot/OxyPlot/PlotModel/PlotElement.cs           |  142 ++
 oxyplot/OxyPlot/PlotModel/PlotModel.Legends.cs     |  507 ++++++
 oxyplot/OxyPlot/PlotModel/PlotModel.MouseEvents.cs |  202 +++
 oxyplot/OxyPlot/PlotModel/PlotModel.Rendering.cs   |  481 ++++++
 oxyplot/OxyPlot/PlotModel/PlotModel.cs             | 1485 +++++++++++++++++
 oxyplot/OxyPlot/PlotModel/SelectablePlotElement.cs |  159 ++
 oxyplot/OxyPlot/PlotModel/UIPlotElement.cs         |  116 ++
 oxyplot/OxyPlot/Properties/AssemblyInfo.cs         |   10 +
 oxyplot/OxyPlot/Render/AngleAxisRenderer.cs        |  166 ++
 oxyplot/OxyPlot/Render/AxisRenderer.cs             |  532 ++++++
 oxyplot/OxyPlot/Render/AxisRendererBase.cs         |  217 +++
 .../Render/HorizontalAndVerticalAxisRenderer.cs    |  642 +++++++
 oxyplot/OxyPlot/Render/IRenderContext.cs           |  400 +++++
 oxyplot/OxyPlot/Render/MagnitudeAxisRenderer.cs    |  145 ++
 oxyplot/OxyPlot/Render/MathRenderingExtensions.cs  |  347 ++++
 oxyplot/OxyPlot/Render/PlotRenderer.cs             |  159 ++
 oxyplot/OxyPlot/Render/RenderContextBase.cs        |  423 +++++
 oxyplot/OxyPlot/Render/RenderingExtensions.cs      | 1109 +++++++++++++
 oxyplot/OxyPlot/Render/VerticalAxisRenderer.cs     |  318 ++++
 oxyplot/OxyPlot/Reporting/NamespaceDoc.cs          |   39 +
 oxyplot/OxyPlot/Reporting/Report/Content.cs        |   75 +
 oxyplot/OxyPlot/Reporting/Report/Drawing.cs        |   46 +
 oxyplot/OxyPlot/Reporting/Report/DrawingFigure.cs  |   73 +
 oxyplot/OxyPlot/Reporting/Report/Equation.cs       |   59 +
 oxyplot/OxyPlot/Reporting/Report/Figure.cs         |   62 +
 oxyplot/OxyPlot/Reporting/Report/Header.cs         |   82 +
 oxyplot/OxyPlot/Reporting/Report/HeaderHelper.cs   |   82 +
 oxyplot/OxyPlot/Reporting/Report/Image.cs          |   54 +
 oxyplot/OxyPlot/Reporting/Report/ItemsTable.cs     |  243 +++
 .../OxyPlot/Reporting/Report/ItemsTableField.cs    |  136 ++
 oxyplot/OxyPlot/Reporting/Report/Paragraph.cs      |   54 +
 oxyplot/OxyPlot/Reporting/Report/ParagraphStyle.cs |  397 +++++
 oxyplot/OxyPlot/Reporting/Report/Plot.cs           |   40 +
 oxyplot/OxyPlot/Reporting/Report/PlotFigure.cs     |   64 +
 oxyplot/OxyPlot/Reporting/Report/PropertyTable.cs  |  114 ++
 oxyplot/OxyPlot/Reporting/Report/Report.cs         |   87 +
 oxyplot/OxyPlot/Reporting/Report/ReportItem.cs     |  311 ++++
 oxyplot/OxyPlot/Reporting/Report/ReportSection.cs  |   38 +
 oxyplot/OxyPlot/Reporting/Report/ReportStyle.cs    |  156 ++
 oxyplot/OxyPlot/Reporting/Report/Table.cs          |  252 +++
 oxyplot/OxyPlot/Reporting/Report/TableColumn.cs    |   63 +
 .../OxyPlot/Reporting/Report/TableOfContents.cs    |  115 ++
 .../Reporting/ReportWriters/HtmlReportWriter.cs    |  501 ++++++
 .../Reporting/ReportWriters/IReportWriter.cs       |   87 +
 .../Reporting/ReportWriters/StringExtensions.cs    |  130 ++
 .../Reporting/ReportWriters/TextReportWriter.cs    |  289 ++++
 .../Reporting/ReportWriters/WikiReportWriter.cs    |  308 ++++
 oxyplot/OxyPlot/Series/AreaSeries.cs               |  295 ++++
 oxyplot/OxyPlot/Series/BarSeries/BarItem.cs        |   64 +
 oxyplot/OxyPlot/Series/BarSeries/BarItemBase.cs    |   83 +
 oxyplot/OxyPlot/Series/BarSeries/BarSeries.cs      |  198 +++
 oxyplot/OxyPlot/Series/BarSeries/BarSeriesBase.cs  |  603 +++++++
 .../OxyPlot/Series/BarSeries/BarSeriesBase{T}.cs   |  113 ++
 .../OxyPlot/Series/BarSeries/CategorizedItem.cs    |   73 +
 .../OxyPlot/Series/BarSeries/CategorizedSeries.cs  |   83 +
 oxyplot/OxyPlot/Series/BarSeries/ColumnItem.cs     |   64 +
 oxyplot/OxyPlot/Series/BarSeries/ColumnSeries.cs   |  198 +++
 .../OxyPlot/Series/BarSeries/ErrorColumnItem.cs    |   96 ++
 .../OxyPlot/Series/BarSeries/ErrorColumnSeries.cs  |  240 +++
 .../OxyPlot/Series/BarSeries/IStackableSeries.cs   |   50 +
 .../OxyPlot/Series/BarSeries/IntervalBarItem.cs    |  110 ++
 .../OxyPlot/Series/BarSeries/IntervalBarSeries.cs  |  515 ++++++
 oxyplot/OxyPlot/Series/BarSeries/LabelPlacement.cs |   57 +
 .../OxyPlot/Series/BarSeries/RectangleBarItem.cs   |  137 ++
 .../OxyPlot/Series/BarSeries/RectangleBarSeries.cs |  337 ++++
 oxyplot/OxyPlot/Series/BarSeries/TornadoBarItem.cs |  147 ++
 .../OxyPlot/Series/BarSeries/TornadoBarSeries.cs   |  590 +++++++
 oxyplot/OxyPlot/Series/BoxPlotItem.cs              |  167 ++
 oxyplot/OxyPlot/Series/BoxPlotSeries.cs            |  615 +++++++
 oxyplot/OxyPlot/Series/CandleStickSeries.cs        |  201 +++
 oxyplot/OxyPlot/Series/ContourSeries.cs            |  770 +++++++++
 oxyplot/OxyPlot/Series/DataPointSeries.cs          |  325 ++++
 oxyplot/OxyPlot/Series/DataSeries.cs               |  391 +++++
 oxyplot/OxyPlot/Series/FunctionSeries.cs           |  157 ++
 oxyplot/OxyPlot/Series/HeatMapSeries.cs            |  238 +++
 oxyplot/OxyPlot/Series/HighLowItem.cs              |  187 +++
 oxyplot/OxyPlot/Series/HighLowSeries.cs            |  502 ++++++
 oxyplot/OxyPlot/Series/ITrackableSeries.cs         |   67 +
 oxyplot/OxyPlot/Series/ItemsSeries.cs              |   96 ++
 oxyplot/OxyPlot/Series/LineLegendPosition.cs       |   52 +
 oxyplot/OxyPlot/Series/LineSeries.cs               |  644 +++++++
 oxyplot/OxyPlot/Series/PieSeries.cs                |  481 ++++++
 oxyplot/OxyPlot/Series/PieSlice.cs                 |   99 ++
 oxyplot/OxyPlot/Series/PlotSeriesBase.cs           |  302 ++++
 oxyplot/OxyPlot/Series/ScatterPoint.cs             |  232 +++
 oxyplot/OxyPlot/Series/ScatterSeries.cs            |  621 +++++++
 oxyplot/OxyPlot/Series/Series.cs                   |  204 +++
 oxyplot/OxyPlot/Series/StairStepSeries.cs          |  291 ++++
 oxyplot/OxyPlot/Series/StemSeries.cs               |  212 +++
 oxyplot/OxyPlot/Series/TwoColorLineSeries.cs       |  163 ++
 oxyplot/OxyPlot/Series/XYAxisSeries.cs             |  424 +++++
 oxyplot/OxyPlot/Svg/NativeMethods.cs               |  246 +++
 oxyplot/OxyPlot/Svg/SvgExporter.cs                 |   85 +
 oxyplot/OxyPlot/Svg/SvgRenderContext.cs            |  278 ++++
 oxyplot/OxyPlot/Svg/SvgWriter.cs                   |  502 ++++++
 oxyplot/OxyPlotMono.sln                            |   20 +
 oxyplot/OxyPlotMono/OxyPlotMono.csproj             |  562 +++++++
 oxyplot/OxyPlotMono/OxyPlotMono.userprefs          |   12 +
 oxyplot/OxyPlotMono/bin/Debug/OxyPlotMono.dll      |  Bin 0 -> 329216 bytes
 oxyplot/OxyPlotMono/bin/Debug/OxyPlotMono.dll.mdb  |  Bin 0 -> 183277 bytes
 208 files changed, 45099 insertions(+), 0 deletions(-)
---
diff --git a/oxyplot/GlobalAssemblyInfo.cs b/oxyplot/GlobalAssemblyInfo.cs
new file mode 100644
index 0000000..3d3f2cf
--- /dev/null
+++ b/oxyplot/GlobalAssemblyInfo.cs
@@ -0,0 +1,38 @@
+//-----------------------------------------------------------------------
+// <copyright file="GlobalAssemblyInfo.cs" company="OxyPlot">
+//   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.
+// </copyright>
+//-----------------------------------------------------------------------
+
+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 --git a/oxyplot/OxyPlot.sln b/oxyplot/OxyPlot.sln
new file mode 100644
index 0000000..0094f3c
--- /dev/null
+++ b/oxyplot/OxyPlot.sln
@@ -0,0 +1,779 @@
+
+Microsoft Visual Studio Solution File, Format Version 12.00
+# Visual Studio 2012
+Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "OxyPlot.Wpf", "OxyPlot.Wpf\OxyPlot.Wpf.csproj", 
"{698CCD8E-ADCC-4565-8517-5EDD36F07155}"
+EndProject
+Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "OxyPlot.Tests", "OxyPlot.Tests\OxyPlot.Tests.csproj", 
"{E6218B88-69F5-4E3F-9ABC-93AB82FD77AD}"
+EndProject
+Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = "Examples.WPF", "Examples.WPF", 
"{B630CA82-A785-49CA-8FA0-3D3AF4D6626A}"
+EndProject
+Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "SimpleDemo", 
"Examples\WPF\SimpleDemo\SimpleDemo.csproj", "{F97B3093-EBDD-46C9-890E-0501922B9168}"
+EndProject
+Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "OxyPlot", "OxyPlot\OxyPlot.csproj", 
"{7A0B35C0-DD17-4964-8E9A-44D6CECDC692}"
+EndProject
+Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "OxyPlot.Pdf", "OxyPlot.Pdf\OxyPlot.Pdf.csproj", 
"{12737C3F-5770-403F-90A1-BC12EBD1BB31}"
+EndProject
+Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "ExportDemo", 
"Examples\WPF\ExportDemo\ExportDemo.csproj", "{11B45D63-8D63-4527-A537-41F6E8B4F9C0}"
+EndProject
+Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "OxyPlot.Xps", "OxyPlot.Xps\OxyPlot.Xps.csproj", 
"{639E0B40-A307-4D4A-BB78-BE0019D8D7C1}"
+EndProject
+Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "OxyPlot.OpenXml", 
"OxyPlot.OpenXml\OxyPlot.OpenXml.csproj", "{BB4FA452-A96A-4C47-AA65-7E88F6FAE873}"
+EndProject
+Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "ExampleLibrary", 
"Examples\ExampleLibrary\ExampleLibrary.csproj", "{FACB89E5-53A5-4748-9F5B-E0714EBB37B2}"
+EndProject
+Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "ExampleBrowser", 
"Examples\WPF\ExampleBrowser\ExampleBrowser.csproj", "{4BB6F831-E215-488E-8ED8-F73C98C4B23F}"
+EndProject
+Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "WorldStatisticsDemo", 
"Examples\WPF\WorldStatisticsDemo\WorldStatisticsDemo.csproj", "{6B677A5B-BF20-48C2-8435-5594BB3BC65F}"
+EndProject
+Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "OxyPlot.Wpf.Tests", 
"OxyPlot.Wpf.Tests\OxyPlot.Wpf.Tests.csproj", "{4ED9A511-669D-47B1-97F5-4FCAFE8EB178}"
+EndProject
+Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = "DemoApplications", "DemoApplications", 
"{831970F4-9390-4214-848B-70E6250443DC}"
+EndProject
+Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "MemoryTest", 
"Examples\WPF\MemoryTest\MemoryTest.csproj", "{2F190086-3322-4407-A052-845E0DA24392}"
+EndProject
+Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "WpfExamples", 
"Examples\WPF\WpfExamples\WpfExamples.csproj", "{B86739B8-5DE9-406F-9418-0751BF7C166F}"
+EndProject
+Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "OxyPlot.Wpf_NET40", 
"OxyPlot.Wpf\OxyPlot.Wpf_NET40.csproj", "{0D7C7710-C58B-4713-BA18-8231A2F35A12}"
+EndProject
+Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "OxyPlot.Xps_NET40", 
"OxyPlot.Xps\OxyPlot.Xps_NET40.csproj", "{87B7C658-12D9-4BD2-8FBB-9E4F2A670FB3}"
+EndProject
+Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "OxyPlot.WindowsForms", 
"OxyPlot.WindowsForms\OxyPlot.WindowsForms.csproj", "{8BC521AD-81CF-4E6C-8898-BE67527E7064}"
+EndProject
+Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "OxyPlot.WindowsForms_NET40", 
"OxyPlot.WindowsForms\OxyPlot.WindowsForms_NET40.csproj", "{D4554296-094E-4CAC-8EAE-44EB250666C6}"
+EndProject
+Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "OxyPlot.Silverlight", 
"OxyPlot.Silverlight\OxyPlot.Silverlight.csproj", "{2EB36333-58C3-47FD-B01F-C1C3FAF1888A}"
+EndProject
+Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "OxyPlot.Silverlight_SL4", 
"OxyPlot.Silverlight\OxyPlot.Silverlight_SL4.csproj", "{388DB184-B394-4F9D-8937-AAE920CAAD70}"
+EndProject
+Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "OxyPlot.Pdf_NET40", 
"OxyPlot.Pdf\OxyPlot.Pdf_NET40.csproj", "{AD0C93A1-7E0A-4311-8088-143FCC13CA3E}"
+EndProject
+Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "OxyPlot.Pdf_SL4", "OxyPlot.Pdf\OxyPlot.Pdf_SL4.csproj", 
"{C84CAEBA-3326-41C8-81DA-B1EB680D7FA1}"
+EndProject
+Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "OxyPlot.Pdf_SL5", "OxyPlot.Pdf\OxyPlot.Pdf_SL5.csproj", 
"{10A30E0C-D902-4803-9CCD-8902C41CA244}"
+EndProject
+Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "OxyPlot.OpenXml_NET40", 
"OxyPlot.OpenXml\OxyPlot.OpenXml_NET40.csproj", "{AF4DF6F4-FD99-4236-B0F1-CE8F5AD0D8A2}"
+EndProject
+Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "OxyPlot.Metro", "OxyPlot.Metro\OxyPlot.Metro.csproj", 
"{2FA3C4D5-1B43-4191-863C-F940DAA6A1EE}"
+EndProject
+Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "OxyPlot.MonoForAndroid", 
"OxyPlot.MonoForAndroid\OxyPlot.MonoForAndroid.csproj", "{E965BA32-9561-4E2A-ADB0-19487B25A939}"
+EndProject
+Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = "Examples.Metro", "Examples.Metro", 
"{02741A76-6D1D-424B-9C04-8CC7B4033571}"
+EndProject
+Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "BasicSample", 
"Examples\Metro\BasicSample\BasicSample.csproj", "{4238CB37-AD71-4E7B-84DB-C97DBBD94082}"
+EndProject
+Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "ExampleBrowser", 
"Examples\Metro\ExampleBrowser\ExampleBrowser.csproj", "{F18CD317-7774-4AFF-8866-E5B42BF71D1E}"
+EndProject
+Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = "Examples.WindowsForms", "Examples.WindowsForms", 
"{B23E6DC9-4786-4BC0-BA8D-74AC6F961FC0}"
+EndProject
+Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = "Examples.Silverlight", "Examples.Silverlight", 
"{8619D594-5980-47B0-BB8D-1C15AC8F2357}"
+EndProject
+Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = "Examples.MonoForAndroid", "Examples.MonoForAndroid", 
"{61666B87-CAC9-4F22-BD25-E0C6568EA1D5}"
+EndProject
+Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "ExampleBrowser", 
"Examples\WindowsForms\ExampleBrowser\ExampleBrowser.csproj", "{138BFD13-0ED1-49F5-B902-78770CB3D66B}"
+EndProject
+Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "ExampleBrowser_NET40", 
"Examples\WindowsForms\ExampleBrowser\ExampleBrowser_NET40.csproj", "{44DC1E63-C7D0-4068-9FAE-1F18A4CEA918}"
+EndProject
+Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "WindowsFormsDemo", 
"Examples\WindowsForms\WindowsFormsDemo\WindowsFormsDemo.csproj", "{BBAECBB8-149A-42EE-A4F4-6207D7954F8B}"
+EndProject
+Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "ExampleBrowser_NET40", 
"Examples\WPF\ExampleBrowser\ExampleBrowser_NET40.csproj", "{9B8816E0-026F-4255-9EA9-9997E33AE377}"
+EndProject
+Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "SparklineDemo", 
"Examples\Silverlight\SparklineDemo\SparklineDemo.csproj", "{BD75B688-D4A3-405F-BC08-E371993A6273}"
+EndProject
+Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "ExampleBrowser", 
"Examples\Silverlight\ExampleBrowser\ExampleBrowser.csproj", "{15B1DC32-92C8-4301-A16D-9C47EE8356A2}"
+EndProject
+Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "ExampleBrowser_SL4", 
"Examples\Silverlight\ExampleBrowser\ExampleBrowser_SL4.csproj", "{564E1DBA-3B0C-441D-9ACA-73B0A54D07AB}"
+EndProject
+Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "ExampleBrowser.Web", 
"Examples\Silverlight\ExampleBrowser.Web\ExampleBrowser.Web.csproj", "{BB639CDB-36F9-4DCB-A075-B713CC5A9A3F}"
+EndProject
+Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "ExportDemo", 
"Examples\Silverlight\ExportDemo\ExportDemo.csproj", "{5C307156-E173-425B-8FC7-4B5CB63C7980}"
+EndProject
+Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "ExportDemo_SL4", 
"Examples\Silverlight\ExportDemo\ExportDemo_SL4.csproj", "{66F2A02F-EF7B-4EBF-AD1B-6506BF7BD983}"
+EndProject
+Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "SilverlightDemo", 
"Examples\Silverlight\SilverlightDemo\SilverlightDemo.csproj", "{ECAEB12F-7177-41FF-98D4-2EA7F5F110F0}"
+EndProject
+Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "ExampleBrowser", 
"Examples\MonoForAndroid\ExampleBrowser\ExampleBrowser.csproj", "{47BDB77E-C1AD-4784-ACA7-FC2D70C3A2BC}"
+EndProject
+Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "ExampleLibraryMfA", 
"Examples\ExampleLibrary\ExampleLibraryMfA.csproj", "{F4C226B3-0DAB-474C-9466-5EACAFA9B64A}"
+EndProject
+Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "OxyPlotMfA", "OxyPlot\OxyPlotMfA.csproj", 
"{08A91765-2C9D-4D2B-B56D-FAE62AB204CC}"
+EndProject
+Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "OxyPlot.Pdf.Tests", 
"OxyPlot.Pdf.Tests\OxyPlot.Pdf.Tests.csproj", "{FF600107-3DEB-404F-8A37-F63473BDFCB8}"
+EndProject
+Global
+       GlobalSection(SolutionConfigurationPlatforms) = preSolution
+               Debug|Any CPU = Debug|Any CPU
+               Debug|ARM = Debug|ARM
+               Debug|Mixed Platforms = Debug|Mixed Platforms
+               Debug|x64 = Debug|x64
+               Debug|x86 = Debug|x86
+               Release|Any CPU = Release|Any CPU
+               Release|ARM = Release|ARM
+               Release|Mixed Platforms = Release|Mixed Platforms
+               Release|x64 = Release|x64
+               Release|x86 = Release|x86
+       EndGlobalSection
+       GlobalSection(ProjectConfigurationPlatforms) = postSolution
+               {698CCD8E-ADCC-4565-8517-5EDD36F07155}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
+               {698CCD8E-ADCC-4565-8517-5EDD36F07155}.Debug|Any CPU.Build.0 = Debug|Any CPU
+               {698CCD8E-ADCC-4565-8517-5EDD36F07155}.Debug|ARM.ActiveCfg = Debug|Any CPU
+               {698CCD8E-ADCC-4565-8517-5EDD36F07155}.Debug|Mixed Platforms.ActiveCfg = Debug|Any CPU
+               {698CCD8E-ADCC-4565-8517-5EDD36F07155}.Debug|Mixed Platforms.Build.0 = Debug|Any CPU
+               {698CCD8E-ADCC-4565-8517-5EDD36F07155}.Debug|x64.ActiveCfg = Debug|Any CPU
+               {698CCD8E-ADCC-4565-8517-5EDD36F07155}.Debug|x86.ActiveCfg = Debug|Any CPU
+               {698CCD8E-ADCC-4565-8517-5EDD36F07155}.Release|Any CPU.ActiveCfg = Release|Any CPU
+               {698CCD8E-ADCC-4565-8517-5EDD36F07155}.Release|Any CPU.Build.0 = Release|Any CPU
+               {698CCD8E-ADCC-4565-8517-5EDD36F07155}.Release|ARM.ActiveCfg = Release|Any CPU
+               {698CCD8E-ADCC-4565-8517-5EDD36F07155}.Release|Mixed Platforms.ActiveCfg = Release|Any CPU
+               {698CCD8E-ADCC-4565-8517-5EDD36F07155}.Release|Mixed Platforms.Build.0 = Release|Any CPU
+               {698CCD8E-ADCC-4565-8517-5EDD36F07155}.Release|x64.ActiveCfg = Release|Any CPU
+               {698CCD8E-ADCC-4565-8517-5EDD36F07155}.Release|x86.ActiveCfg = Release|Any CPU
+               {E6218B88-69F5-4E3F-9ABC-93AB82FD77AD}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
+               {E6218B88-69F5-4E3F-9ABC-93AB82FD77AD}.Debug|Any CPU.Build.0 = Debug|Any CPU
+               {E6218B88-69F5-4E3F-9ABC-93AB82FD77AD}.Debug|ARM.ActiveCfg = Debug|Any CPU
+               {E6218B88-69F5-4E3F-9ABC-93AB82FD77AD}.Debug|Mixed Platforms.ActiveCfg = Debug|Any CPU
+               {E6218B88-69F5-4E3F-9ABC-93AB82FD77AD}.Debug|Mixed Platforms.Build.0 = Debug|Any CPU
+               {E6218B88-69F5-4E3F-9ABC-93AB82FD77AD}.Debug|x64.ActiveCfg = Debug|Any CPU
+               {E6218B88-69F5-4E3F-9ABC-93AB82FD77AD}.Debug|x86.ActiveCfg = Debug|Any CPU
+               {E6218B88-69F5-4E3F-9ABC-93AB82FD77AD}.Release|Any CPU.ActiveCfg = Release|Any CPU
+               {E6218B88-69F5-4E3F-9ABC-93AB82FD77AD}.Release|Any CPU.Build.0 = Release|Any CPU
+               {E6218B88-69F5-4E3F-9ABC-93AB82FD77AD}.Release|ARM.ActiveCfg = Release|Any CPU
+               {E6218B88-69F5-4E3F-9ABC-93AB82FD77AD}.Release|Mixed Platforms.ActiveCfg = Release|Any CPU
+               {E6218B88-69F5-4E3F-9ABC-93AB82FD77AD}.Release|Mixed Platforms.Build.0 = Release|Any CPU
+               {E6218B88-69F5-4E3F-9ABC-93AB82FD77AD}.Release|x64.ActiveCfg = Release|Any CPU
+               {E6218B88-69F5-4E3F-9ABC-93AB82FD77AD}.Release|x86.ActiveCfg = Release|Any CPU
+               {F97B3093-EBDD-46C9-890E-0501922B9168}.Debug|Any CPU.ActiveCfg = Debug|x86
+               {F97B3093-EBDD-46C9-890E-0501922B9168}.Debug|ARM.ActiveCfg = Debug|x86
+               {F97B3093-EBDD-46C9-890E-0501922B9168}.Debug|Mixed Platforms.ActiveCfg = Debug|x86
+               {F97B3093-EBDD-46C9-890E-0501922B9168}.Debug|Mixed Platforms.Build.0 = Debug|x86
+               {F97B3093-EBDD-46C9-890E-0501922B9168}.Debug|x64.ActiveCfg = Debug|x86
+               {F97B3093-EBDD-46C9-890E-0501922B9168}.Debug|x86.ActiveCfg = Debug|x86
+               {F97B3093-EBDD-46C9-890E-0501922B9168}.Debug|x86.Build.0 = Debug|x86
+               {F97B3093-EBDD-46C9-890E-0501922B9168}.Release|Any CPU.ActiveCfg = Release|x86
+               {F97B3093-EBDD-46C9-890E-0501922B9168}.Release|ARM.ActiveCfg = Release|x86
+               {F97B3093-EBDD-46C9-890E-0501922B9168}.Release|Mixed Platforms.ActiveCfg = Release|x86
+               {F97B3093-EBDD-46C9-890E-0501922B9168}.Release|Mixed Platforms.Build.0 = Release|x86
+               {F97B3093-EBDD-46C9-890E-0501922B9168}.Release|x64.ActiveCfg = Release|x86
+               {F97B3093-EBDD-46C9-890E-0501922B9168}.Release|x86.ActiveCfg = Release|x86
+               {F97B3093-EBDD-46C9-890E-0501922B9168}.Release|x86.Build.0 = Release|x86
+               {7A0B35C0-DD17-4964-8E9A-44D6CECDC692}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
+               {7A0B35C0-DD17-4964-8E9A-44D6CECDC692}.Debug|Any CPU.Build.0 = Debug|Any CPU
+               {7A0B35C0-DD17-4964-8E9A-44D6CECDC692}.Debug|ARM.ActiveCfg = Debug|Any CPU
+               {7A0B35C0-DD17-4964-8E9A-44D6CECDC692}.Debug|Mixed Platforms.ActiveCfg = Debug|Any CPU
+               {7A0B35C0-DD17-4964-8E9A-44D6CECDC692}.Debug|Mixed Platforms.Build.0 = Debug|Any CPU
+               {7A0B35C0-DD17-4964-8E9A-44D6CECDC692}.Debug|x64.ActiveCfg = Debug|Any CPU
+               {7A0B35C0-DD17-4964-8E9A-44D6CECDC692}.Debug|x86.ActiveCfg = Debug|Any CPU
+               {7A0B35C0-DD17-4964-8E9A-44D6CECDC692}.Release|Any CPU.ActiveCfg = Release|Any CPU
+               {7A0B35C0-DD17-4964-8E9A-44D6CECDC692}.Release|Any CPU.Build.0 = Release|Any CPU
+               {7A0B35C0-DD17-4964-8E9A-44D6CECDC692}.Release|ARM.ActiveCfg = Release|Any CPU
+               {7A0B35C0-DD17-4964-8E9A-44D6CECDC692}.Release|Mixed Platforms.ActiveCfg = Release|Any CPU
+               {7A0B35C0-DD17-4964-8E9A-44D6CECDC692}.Release|Mixed Platforms.Build.0 = Release|Any CPU
+               {7A0B35C0-DD17-4964-8E9A-44D6CECDC692}.Release|x64.ActiveCfg = Release|Any CPU
+               {7A0B35C0-DD17-4964-8E9A-44D6CECDC692}.Release|x86.ActiveCfg = Release|Any CPU
+               {12737C3F-5770-403F-90A1-BC12EBD1BB31}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
+               {12737C3F-5770-403F-90A1-BC12EBD1BB31}.Debug|Any CPU.Build.0 = Debug|Any CPU
+               {12737C3F-5770-403F-90A1-BC12EBD1BB31}.Debug|ARM.ActiveCfg = Debug|Any CPU
+               {12737C3F-5770-403F-90A1-BC12EBD1BB31}.Debug|Mixed Platforms.ActiveCfg = Debug|Any CPU
+               {12737C3F-5770-403F-90A1-BC12EBD1BB31}.Debug|Mixed Platforms.Build.0 = Debug|Any CPU
+               {12737C3F-5770-403F-90A1-BC12EBD1BB31}.Debug|x64.ActiveCfg = Debug|Any CPU
+               {12737C3F-5770-403F-90A1-BC12EBD1BB31}.Debug|x86.ActiveCfg = Debug|Any CPU
+               {12737C3F-5770-403F-90A1-BC12EBD1BB31}.Release|Any CPU.ActiveCfg = Release|Any CPU
+               {12737C3F-5770-403F-90A1-BC12EBD1BB31}.Release|Any CPU.Build.0 = Release|Any CPU
+               {12737C3F-5770-403F-90A1-BC12EBD1BB31}.Release|ARM.ActiveCfg = Release|Any CPU
+               {12737C3F-5770-403F-90A1-BC12EBD1BB31}.Release|Mixed Platforms.ActiveCfg = Release|Any CPU
+               {12737C3F-5770-403F-90A1-BC12EBD1BB31}.Release|Mixed Platforms.Build.0 = Release|Any CPU
+               {12737C3F-5770-403F-90A1-BC12EBD1BB31}.Release|x64.ActiveCfg = Release|Any CPU
+               {12737C3F-5770-403F-90A1-BC12EBD1BB31}.Release|x86.ActiveCfg = Release|Any CPU
+               {11B45D63-8D63-4527-A537-41F6E8B4F9C0}.Debug|Any CPU.ActiveCfg = Debug|x86
+               {11B45D63-8D63-4527-A537-41F6E8B4F9C0}.Debug|ARM.ActiveCfg = Debug|x86
+               {11B45D63-8D63-4527-A537-41F6E8B4F9C0}.Debug|Mixed Platforms.ActiveCfg = Debug|x86
+               {11B45D63-8D63-4527-A537-41F6E8B4F9C0}.Debug|Mixed Platforms.Build.0 = Debug|x86
+               {11B45D63-8D63-4527-A537-41F6E8B4F9C0}.Debug|x64.ActiveCfg = Debug|x86
+               {11B45D63-8D63-4527-A537-41F6E8B4F9C0}.Debug|x86.ActiveCfg = Debug|x86
+               {11B45D63-8D63-4527-A537-41F6E8B4F9C0}.Debug|x86.Build.0 = Debug|x86
+               {11B45D63-8D63-4527-A537-41F6E8B4F9C0}.Release|Any CPU.ActiveCfg = Release|x86
+               {11B45D63-8D63-4527-A537-41F6E8B4F9C0}.Release|ARM.ActiveCfg = Release|x86
+               {11B45D63-8D63-4527-A537-41F6E8B4F9C0}.Release|Mixed Platforms.ActiveCfg = Release|x86
+               {11B45D63-8D63-4527-A537-41F6E8B4F9C0}.Release|Mixed Platforms.Build.0 = Release|x86
+               {11B45D63-8D63-4527-A537-41F6E8B4F9C0}.Release|x64.ActiveCfg = Release|x86
+               {11B45D63-8D63-4527-A537-41F6E8B4F9C0}.Release|x86.ActiveCfg = Release|x86
+               {11B45D63-8D63-4527-A537-41F6E8B4F9C0}.Release|x86.Build.0 = Release|x86
+               {639E0B40-A307-4D4A-BB78-BE0019D8D7C1}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
+               {639E0B40-A307-4D4A-BB78-BE0019D8D7C1}.Debug|Any CPU.Build.0 = Debug|Any CPU
+               {639E0B40-A307-4D4A-BB78-BE0019D8D7C1}.Debug|ARM.ActiveCfg = Debug|Any CPU
+               {639E0B40-A307-4D4A-BB78-BE0019D8D7C1}.Debug|Mixed Platforms.ActiveCfg = Debug|Any CPU
+               {639E0B40-A307-4D4A-BB78-BE0019D8D7C1}.Debug|Mixed Platforms.Build.0 = Debug|Any CPU
+               {639E0B40-A307-4D4A-BB78-BE0019D8D7C1}.Debug|x64.ActiveCfg = Debug|Any CPU
+               {639E0B40-A307-4D4A-BB78-BE0019D8D7C1}.Debug|x86.ActiveCfg = Debug|Any CPU
+               {639E0B40-A307-4D4A-BB78-BE0019D8D7C1}.Release|Any CPU.ActiveCfg = Release|Any CPU
+               {639E0B40-A307-4D4A-BB78-BE0019D8D7C1}.Release|Any CPU.Build.0 = Release|Any CPU
+               {639E0B40-A307-4D4A-BB78-BE0019D8D7C1}.Release|ARM.ActiveCfg = Release|Any CPU
+               {639E0B40-A307-4D4A-BB78-BE0019D8D7C1}.Release|Mixed Platforms.ActiveCfg = Release|Any CPU
+               {639E0B40-A307-4D4A-BB78-BE0019D8D7C1}.Release|Mixed Platforms.Build.0 = Release|Any CPU
+               {639E0B40-A307-4D4A-BB78-BE0019D8D7C1}.Release|x64.ActiveCfg = Release|Any CPU
+               {639E0B40-A307-4D4A-BB78-BE0019D8D7C1}.Release|x86.ActiveCfg = Release|Any CPU
+               {BB4FA452-A96A-4C47-AA65-7E88F6FAE873}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
+               {BB4FA452-A96A-4C47-AA65-7E88F6FAE873}.Debug|Any CPU.Build.0 = Debug|Any CPU
+               {BB4FA452-A96A-4C47-AA65-7E88F6FAE873}.Debug|ARM.ActiveCfg = Debug|Any CPU
+               {BB4FA452-A96A-4C47-AA65-7E88F6FAE873}.Debug|Mixed Platforms.ActiveCfg = Debug|Any CPU
+               {BB4FA452-A96A-4C47-AA65-7E88F6FAE873}.Debug|Mixed Platforms.Build.0 = Debug|Any CPU
+               {BB4FA452-A96A-4C47-AA65-7E88F6FAE873}.Debug|x64.ActiveCfg = Debug|Any CPU
+               {BB4FA452-A96A-4C47-AA65-7E88F6FAE873}.Debug|x86.ActiveCfg = Debug|Any CPU
+               {BB4FA452-A96A-4C47-AA65-7E88F6FAE873}.Release|Any CPU.ActiveCfg = Release|Any CPU
+               {BB4FA452-A96A-4C47-AA65-7E88F6FAE873}.Release|Any CPU.Build.0 = Release|Any CPU
+               {BB4FA452-A96A-4C47-AA65-7E88F6FAE873}.Release|ARM.ActiveCfg = Release|Any CPU
+               {BB4FA452-A96A-4C47-AA65-7E88F6FAE873}.Release|Mixed Platforms.ActiveCfg = Release|Any CPU
+               {BB4FA452-A96A-4C47-AA65-7E88F6FAE873}.Release|Mixed Platforms.Build.0 = Release|Any CPU
+               {BB4FA452-A96A-4C47-AA65-7E88F6FAE873}.Release|x64.ActiveCfg = Release|Any CPU
+               {BB4FA452-A96A-4C47-AA65-7E88F6FAE873}.Release|x86.ActiveCfg = Release|Any CPU
+               {FACB89E5-53A5-4748-9F5B-E0714EBB37B2}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
+               {FACB89E5-53A5-4748-9F5B-E0714EBB37B2}.Debug|Any CPU.Build.0 = Debug|Any CPU
+               {FACB89E5-53A5-4748-9F5B-E0714EBB37B2}.Debug|ARM.ActiveCfg = Debug|Any CPU
+               {FACB89E5-53A5-4748-9F5B-E0714EBB37B2}.Debug|Mixed Platforms.ActiveCfg = Debug|Any CPU
+               {FACB89E5-53A5-4748-9F5B-E0714EBB37B2}.Debug|Mixed Platforms.Build.0 = Debug|Any CPU
+               {FACB89E5-53A5-4748-9F5B-E0714EBB37B2}.Debug|x64.ActiveCfg = Debug|Any CPU
+               {FACB89E5-53A5-4748-9F5B-E0714EBB37B2}.Debug|x86.ActiveCfg = Debug|Any CPU
+               {FACB89E5-53A5-4748-9F5B-E0714EBB37B2}.Release|Any CPU.ActiveCfg = Release|Any CPU
+               {FACB89E5-53A5-4748-9F5B-E0714EBB37B2}.Release|Any CPU.Build.0 = Release|Any CPU
+               {FACB89E5-53A5-4748-9F5B-E0714EBB37B2}.Release|ARM.ActiveCfg = Release|Any CPU
+               {FACB89E5-53A5-4748-9F5B-E0714EBB37B2}.Release|Mixed Platforms.ActiveCfg = Release|Any CPU
+               {FACB89E5-53A5-4748-9F5B-E0714EBB37B2}.Release|Mixed Platforms.Build.0 = Release|Any CPU
+               {FACB89E5-53A5-4748-9F5B-E0714EBB37B2}.Release|x64.ActiveCfg = Release|Any CPU
+               {FACB89E5-53A5-4748-9F5B-E0714EBB37B2}.Release|x86.ActiveCfg = Release|Any CPU
+               {4BB6F831-E215-488E-8ED8-F73C98C4B23F}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
+               {4BB6F831-E215-488E-8ED8-F73C98C4B23F}.Debug|Any CPU.Build.0 = Debug|Any CPU
+               {4BB6F831-E215-488E-8ED8-F73C98C4B23F}.Debug|ARM.ActiveCfg = Debug|Any CPU
+               {4BB6F831-E215-488E-8ED8-F73C98C4B23F}.Debug|Mixed Platforms.ActiveCfg = Debug|Any CPU
+               {4BB6F831-E215-488E-8ED8-F73C98C4B23F}.Debug|Mixed Platforms.Build.0 = Debug|Any CPU
+               {4BB6F831-E215-488E-8ED8-F73C98C4B23F}.Debug|x64.ActiveCfg = Debug|Any CPU
+               {4BB6F831-E215-488E-8ED8-F73C98C4B23F}.Debug|x86.ActiveCfg = Debug|Any CPU
+               {4BB6F831-E215-488E-8ED8-F73C98C4B23F}.Release|Any CPU.ActiveCfg = Release|Any CPU
+               {4BB6F831-E215-488E-8ED8-F73C98C4B23F}.Release|Any CPU.Build.0 = Release|Any CPU
+               {4BB6F831-E215-488E-8ED8-F73C98C4B23F}.Release|ARM.ActiveCfg = Release|Any CPU
+               {4BB6F831-E215-488E-8ED8-F73C98C4B23F}.Release|Mixed Platforms.ActiveCfg = Release|Any CPU
+               {4BB6F831-E215-488E-8ED8-F73C98C4B23F}.Release|Mixed Platforms.Build.0 = Release|Any CPU
+               {4BB6F831-E215-488E-8ED8-F73C98C4B23F}.Release|x64.ActiveCfg = Release|Any CPU
+               {4BB6F831-E215-488E-8ED8-F73C98C4B23F}.Release|x86.ActiveCfg = Release|Any CPU
+               {6B677A5B-BF20-48C2-8435-5594BB3BC65F}.Debug|Any CPU.ActiveCfg = Debug|x86
+               {6B677A5B-BF20-48C2-8435-5594BB3BC65F}.Debug|ARM.ActiveCfg = Debug|x86
+               {6B677A5B-BF20-48C2-8435-5594BB3BC65F}.Debug|Mixed Platforms.ActiveCfg = Debug|x86
+               {6B677A5B-BF20-48C2-8435-5594BB3BC65F}.Debug|Mixed Platforms.Build.0 = Debug|x86
+               {6B677A5B-BF20-48C2-8435-5594BB3BC65F}.Debug|x64.ActiveCfg = Debug|x86
+               {6B677A5B-BF20-48C2-8435-5594BB3BC65F}.Debug|x86.ActiveCfg = Debug|x86
+               {6B677A5B-BF20-48C2-8435-5594BB3BC65F}.Debug|x86.Build.0 = Debug|x86
+               {6B677A5B-BF20-48C2-8435-5594BB3BC65F}.Release|Any CPU.ActiveCfg = Release|x86
+               {6B677A5B-BF20-48C2-8435-5594BB3BC65F}.Release|ARM.ActiveCfg = Release|x86
+               {6B677A5B-BF20-48C2-8435-5594BB3BC65F}.Release|Mixed Platforms.ActiveCfg = Release|x86
+               {6B677A5B-BF20-48C2-8435-5594BB3BC65F}.Release|Mixed Platforms.Build.0 = Release|x86
+               {6B677A5B-BF20-48C2-8435-5594BB3BC65F}.Release|x64.ActiveCfg = Release|x86
+               {6B677A5B-BF20-48C2-8435-5594BB3BC65F}.Release|x86.ActiveCfg = Release|x86
+               {6B677A5B-BF20-48C2-8435-5594BB3BC65F}.Release|x86.Build.0 = Release|x86
+               {4ED9A511-669D-47B1-97F5-4FCAFE8EB178}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
+               {4ED9A511-669D-47B1-97F5-4FCAFE8EB178}.Debug|Any CPU.Build.0 = Debug|Any CPU
+               {4ED9A511-669D-47B1-97F5-4FCAFE8EB178}.Debug|ARM.ActiveCfg = Debug|Any CPU
+               {4ED9A511-669D-47B1-97F5-4FCAFE8EB178}.Debug|Mixed Platforms.ActiveCfg = Debug|Any CPU
+               {4ED9A511-669D-47B1-97F5-4FCAFE8EB178}.Debug|Mixed Platforms.Build.0 = Debug|Any CPU
+               {4ED9A511-669D-47B1-97F5-4FCAFE8EB178}.Debug|x64.ActiveCfg = Debug|Any CPU
+               {4ED9A511-669D-47B1-97F5-4FCAFE8EB178}.Debug|x86.ActiveCfg = Debug|Any CPU
+               {4ED9A511-669D-47B1-97F5-4FCAFE8EB178}.Release|Any CPU.ActiveCfg = Release|Any CPU
+               {4ED9A511-669D-47B1-97F5-4FCAFE8EB178}.Release|Any CPU.Build.0 = Release|Any CPU
+               {4ED9A511-669D-47B1-97F5-4FCAFE8EB178}.Release|ARM.ActiveCfg = Release|Any CPU
+               {4ED9A511-669D-47B1-97F5-4FCAFE8EB178}.Release|Mixed Platforms.ActiveCfg = Release|Any CPU
+               {4ED9A511-669D-47B1-97F5-4FCAFE8EB178}.Release|Mixed Platforms.Build.0 = Release|Any CPU
+               {4ED9A511-669D-47B1-97F5-4FCAFE8EB178}.Release|x64.ActiveCfg = Release|Any CPU
+               {4ED9A511-669D-47B1-97F5-4FCAFE8EB178}.Release|x86.ActiveCfg = Release|Any CPU
+               {2F190086-3322-4407-A052-845E0DA24392}.Debug|Any CPU.ActiveCfg = Debug|x86
+               {2F190086-3322-4407-A052-845E0DA24392}.Debug|ARM.ActiveCfg = Debug|x86
+               {2F190086-3322-4407-A052-845E0DA24392}.Debug|Mixed Platforms.ActiveCfg = Debug|x86
+               {2F190086-3322-4407-A052-845E0DA24392}.Debug|Mixed Platforms.Build.0 = Debug|x86
+               {2F190086-3322-4407-A052-845E0DA24392}.Debug|x64.ActiveCfg = Debug|x86
+               {2F190086-3322-4407-A052-845E0DA24392}.Debug|x86.ActiveCfg = Debug|x86
+               {2F190086-3322-4407-A052-845E0DA24392}.Debug|x86.Build.0 = Debug|x86
+               {2F190086-3322-4407-A052-845E0DA24392}.Release|Any CPU.ActiveCfg = Release|x86
+               {2F190086-3322-4407-A052-845E0DA24392}.Release|ARM.ActiveCfg = Release|x86
+               {2F190086-3322-4407-A052-845E0DA24392}.Release|Mixed Platforms.ActiveCfg = Release|x86
+               {2F190086-3322-4407-A052-845E0DA24392}.Release|Mixed Platforms.Build.0 = Release|x86
+               {2F190086-3322-4407-A052-845E0DA24392}.Release|x64.ActiveCfg = Release|x86
+               {2F190086-3322-4407-A052-845E0DA24392}.Release|x86.ActiveCfg = Release|x86
+               {2F190086-3322-4407-A052-845E0DA24392}.Release|x86.Build.0 = Release|x86
+               {B86739B8-5DE9-406F-9418-0751BF7C166F}.Debug|Any CPU.ActiveCfg = Debug|x86
+               {B86739B8-5DE9-406F-9418-0751BF7C166F}.Debug|ARM.ActiveCfg = Debug|x86
+               {B86739B8-5DE9-406F-9418-0751BF7C166F}.Debug|Mixed Platforms.ActiveCfg = Debug|x86
+               {B86739B8-5DE9-406F-9418-0751BF7C166F}.Debug|Mixed Platforms.Build.0 = Debug|x86
+               {B86739B8-5DE9-406F-9418-0751BF7C166F}.Debug|x64.ActiveCfg = Debug|x86
+               {B86739B8-5DE9-406F-9418-0751BF7C166F}.Debug|x86.ActiveCfg = Debug|x86
+               {B86739B8-5DE9-406F-9418-0751BF7C166F}.Debug|x86.Build.0 = Debug|x86
+               {B86739B8-5DE9-406F-9418-0751BF7C166F}.Release|Any CPU.ActiveCfg = Release|x86
+               {B86739B8-5DE9-406F-9418-0751BF7C166F}.Release|ARM.ActiveCfg = Release|x86
+               {B86739B8-5DE9-406F-9418-0751BF7C166F}.Release|Mixed Platforms.ActiveCfg = Release|x86
+               {B86739B8-5DE9-406F-9418-0751BF7C166F}.Release|Mixed Platforms.Build.0 = Release|x86
+               {B86739B8-5DE9-406F-9418-0751BF7C166F}.Release|x64.ActiveCfg = Release|x86
+               {B86739B8-5DE9-406F-9418-0751BF7C166F}.Release|x86.ActiveCfg = Release|x86
+               {B86739B8-5DE9-406F-9418-0751BF7C166F}.Release|x86.Build.0 = Release|x86
+               {0D7C7710-C58B-4713-BA18-8231A2F35A12}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
+               {0D7C7710-C58B-4713-BA18-8231A2F35A12}.Debug|Any CPU.Build.0 = Debug|Any CPU
+               {0D7C7710-C58B-4713-BA18-8231A2F35A12}.Debug|ARM.ActiveCfg = Debug|Any CPU
+               {0D7C7710-C58B-4713-BA18-8231A2F35A12}.Debug|Mixed Platforms.ActiveCfg = Debug|Any CPU
+               {0D7C7710-C58B-4713-BA18-8231A2F35A12}.Debug|Mixed Platforms.Build.0 = Debug|Any CPU
+               {0D7C7710-C58B-4713-BA18-8231A2F35A12}.Debug|x64.ActiveCfg = Debug|Any CPU
+               {0D7C7710-C58B-4713-BA18-8231A2F35A12}.Debug|x86.ActiveCfg = Debug|Any CPU
+               {0D7C7710-C58B-4713-BA18-8231A2F35A12}.Release|Any CPU.ActiveCfg = Release|Any CPU
+               {0D7C7710-C58B-4713-BA18-8231A2F35A12}.Release|Any CPU.Build.0 = Release|Any CPU
+               {0D7C7710-C58B-4713-BA18-8231A2F35A12}.Release|ARM.ActiveCfg = Release|Any CPU
+               {0D7C7710-C58B-4713-BA18-8231A2F35A12}.Release|Mixed Platforms.ActiveCfg = Release|Any CPU
+               {0D7C7710-C58B-4713-BA18-8231A2F35A12}.Release|Mixed Platforms.Build.0 = Release|Any CPU
+               {0D7C7710-C58B-4713-BA18-8231A2F35A12}.Release|x64.ActiveCfg = Release|Any CPU
+               {0D7C7710-C58B-4713-BA18-8231A2F35A12}.Release|x86.ActiveCfg = Release|Any CPU
+               {87B7C658-12D9-4BD2-8FBB-9E4F2A670FB3}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
+               {87B7C658-12D9-4BD2-8FBB-9E4F2A670FB3}.Debug|Any CPU.Build.0 = Debug|Any CPU
+               {87B7C658-12D9-4BD2-8FBB-9E4F2A670FB3}.Debug|ARM.ActiveCfg = Debug|Any CPU
+               {87B7C658-12D9-4BD2-8FBB-9E4F2A670FB3}.Debug|Mixed Platforms.ActiveCfg = Debug|Any CPU
+               {87B7C658-12D9-4BD2-8FBB-9E4F2A670FB3}.Debug|Mixed Platforms.Build.0 = Debug|Any CPU
+               {87B7C658-12D9-4BD2-8FBB-9E4F2A670FB3}.Debug|x64.ActiveCfg = Debug|Any CPU
+               {87B7C658-12D9-4BD2-8FBB-9E4F2A670FB3}.Debug|x86.ActiveCfg = Debug|Any CPU
+               {87B7C658-12D9-4BD2-8FBB-9E4F2A670FB3}.Release|Any CPU.ActiveCfg = Release|Any CPU
+               {87B7C658-12D9-4BD2-8FBB-9E4F2A670FB3}.Release|Any CPU.Build.0 = Release|Any CPU
+               {87B7C658-12D9-4BD2-8FBB-9E4F2A670FB3}.Release|ARM.ActiveCfg = Release|Any CPU
+               {87B7C658-12D9-4BD2-8FBB-9E4F2A670FB3}.Release|Mixed Platforms.ActiveCfg = Release|Any CPU
+               {87B7C658-12D9-4BD2-8FBB-9E4F2A670FB3}.Release|Mixed Platforms.Build.0 = Release|Any CPU
+               {87B7C658-12D9-4BD2-8FBB-9E4F2A670FB3}.Release|x64.ActiveCfg = Release|Any CPU
+               {87B7C658-12D9-4BD2-8FBB-9E4F2A670FB3}.Release|x86.ActiveCfg = Release|Any CPU
+               {8BC521AD-81CF-4E6C-8898-BE67527E7064}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
+               {8BC521AD-81CF-4E6C-8898-BE67527E7064}.Debug|Any CPU.Build.0 = Debug|Any CPU
+               {8BC521AD-81CF-4E6C-8898-BE67527E7064}.Debug|ARM.ActiveCfg = Debug|Any CPU
+               {8BC521AD-81CF-4E6C-8898-BE67527E7064}.Debug|Mixed Platforms.ActiveCfg = Debug|Any CPU
+               {8BC521AD-81CF-4E6C-8898-BE67527E7064}.Debug|Mixed Platforms.Build.0 = Debug|Any CPU
+               {8BC521AD-81CF-4E6C-8898-BE67527E7064}.Debug|x64.ActiveCfg = Debug|Any CPU
+               {8BC521AD-81CF-4E6C-8898-BE67527E7064}.Debug|x86.ActiveCfg = Debug|Any CPU
+               {8BC521AD-81CF-4E6C-8898-BE67527E7064}.Release|Any CPU.ActiveCfg = Release|Any CPU
+               {8BC521AD-81CF-4E6C-8898-BE67527E7064}.Release|Any CPU.Build.0 = Release|Any CPU
+               {8BC521AD-81CF-4E6C-8898-BE67527E7064}.Release|ARM.ActiveCfg = Release|Any CPU
+               {8BC521AD-81CF-4E6C-8898-BE67527E7064}.Release|Mixed Platforms.ActiveCfg = Release|Any CPU
+               {8BC521AD-81CF-4E6C-8898-BE67527E7064}.Release|Mixed Platforms.Build.0 = Release|Any CPU
+               {8BC521AD-81CF-4E6C-8898-BE67527E7064}.Release|x64.ActiveCfg = Release|Any CPU
+               {8BC521AD-81CF-4E6C-8898-BE67527E7064}.Release|x86.ActiveCfg = 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}.Debug|ARM.ActiveCfg = Debug|Any CPU
+               {D4554296-094E-4CAC-8EAE-44EB250666C6}.Debug|Mixed Platforms.ActiveCfg = Debug|Any CPU
+               {D4554296-094E-4CAC-8EAE-44EB250666C6}.Debug|Mixed Platforms.Build.0 = Debug|Any CPU
+               {D4554296-094E-4CAC-8EAE-44EB250666C6}.Debug|x64.ActiveCfg = Debug|Any CPU
+               {D4554296-094E-4CAC-8EAE-44EB250666C6}.Debug|x86.ActiveCfg = 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
+               {D4554296-094E-4CAC-8EAE-44EB250666C6}.Release|ARM.ActiveCfg = Release|Any CPU
+               {D4554296-094E-4CAC-8EAE-44EB250666C6}.Release|Mixed Platforms.ActiveCfg = Release|Any CPU
+               {D4554296-094E-4CAC-8EAE-44EB250666C6}.Release|Mixed Platforms.Build.0 = Release|Any CPU
+               {D4554296-094E-4CAC-8EAE-44EB250666C6}.Release|x64.ActiveCfg = Release|Any CPU
+               {D4554296-094E-4CAC-8EAE-44EB250666C6}.Release|x86.ActiveCfg = Release|Any CPU
+               {2EB36333-58C3-47FD-B01F-C1C3FAF1888A}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
+               {2EB36333-58C3-47FD-B01F-C1C3FAF1888A}.Debug|Any CPU.Build.0 = Debug|Any CPU
+               {2EB36333-58C3-47FD-B01F-C1C3FAF1888A}.Debug|ARM.ActiveCfg = Debug|Any CPU
+               {2EB36333-58C3-47FD-B01F-C1C3FAF1888A}.Debug|Mixed Platforms.ActiveCfg = Debug|Any CPU
+               {2EB36333-58C3-47FD-B01F-C1C3FAF1888A}.Debug|Mixed Platforms.Build.0 = Debug|Any CPU
+               {2EB36333-58C3-47FD-B01F-C1C3FAF1888A}.Debug|x64.ActiveCfg = Debug|Any CPU
+               {2EB36333-58C3-47FD-B01F-C1C3FAF1888A}.Debug|x86.ActiveCfg = Debug|Any CPU
+               {2EB36333-58C3-47FD-B01F-C1C3FAF1888A}.Release|Any CPU.ActiveCfg = Release|Any CPU
+               {2EB36333-58C3-47FD-B01F-C1C3FAF1888A}.Release|Any CPU.Build.0 = Release|Any CPU
+               {2EB36333-58C3-47FD-B01F-C1C3FAF1888A}.Release|ARM.ActiveCfg = Release|Any CPU
+               {2EB36333-58C3-47FD-B01F-C1C3FAF1888A}.Release|Mixed Platforms.ActiveCfg = Release|Any CPU
+               {2EB36333-58C3-47FD-B01F-C1C3FAF1888A}.Release|Mixed Platforms.Build.0 = Release|Any CPU
+               {2EB36333-58C3-47FD-B01F-C1C3FAF1888A}.Release|x64.ActiveCfg = Release|Any CPU
+               {2EB36333-58C3-47FD-B01F-C1C3FAF1888A}.Release|x86.ActiveCfg = Release|Any CPU
+               {388DB184-B394-4F9D-8937-AAE920CAAD70}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
+               {388DB184-B394-4F9D-8937-AAE920CAAD70}.Debug|Any CPU.Build.0 = Debug|Any CPU
+               {388DB184-B394-4F9D-8937-AAE920CAAD70}.Debug|ARM.ActiveCfg = Debug|Any CPU
+               {388DB184-B394-4F9D-8937-AAE920CAAD70}.Debug|Mixed Platforms.ActiveCfg = Debug|Any CPU
+               {388DB184-B394-4F9D-8937-AAE920CAAD70}.Debug|Mixed Platforms.Build.0 = Debug|Any CPU
+               {388DB184-B394-4F9D-8937-AAE920CAAD70}.Debug|x64.ActiveCfg = Debug|Any CPU
+               {388DB184-B394-4F9D-8937-AAE920CAAD70}.Debug|x86.ActiveCfg = Debug|Any CPU
+               {388DB184-B394-4F9D-8937-AAE920CAAD70}.Release|Any CPU.ActiveCfg = Release|Any CPU
+               {388DB184-B394-4F9D-8937-AAE920CAAD70}.Release|Any CPU.Build.0 = Release|Any CPU
+               {388DB184-B394-4F9D-8937-AAE920CAAD70}.Release|ARM.ActiveCfg = Release|Any CPU
+               {388DB184-B394-4F9D-8937-AAE920CAAD70}.Release|Mixed Platforms.ActiveCfg = Release|Any CPU
+               {388DB184-B394-4F9D-8937-AAE920CAAD70}.Release|Mixed Platforms.Build.0 = Release|Any CPU
+               {388DB184-B394-4F9D-8937-AAE920CAAD70}.Release|x64.ActiveCfg = Release|Any CPU
+               {388DB184-B394-4F9D-8937-AAE920CAAD70}.Release|x86.ActiveCfg = Release|Any CPU
+               {AD0C93A1-7E0A-4311-8088-143FCC13CA3E}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
+               {AD0C93A1-7E0A-4311-8088-143FCC13CA3E}.Debug|Any CPU.Build.0 = Debug|Any CPU
+               {AD0C93A1-7E0A-4311-8088-143FCC13CA3E}.Debug|ARM.ActiveCfg = Debug|Any CPU
+               {AD0C93A1-7E0A-4311-8088-143FCC13CA3E}.Debug|Mixed Platforms.ActiveCfg = Debug|Any CPU
+               {AD0C93A1-7E0A-4311-8088-143FCC13CA3E}.Debug|Mixed Platforms.Build.0 = Debug|Any CPU
+               {AD0C93A1-7E0A-4311-8088-143FCC13CA3E}.Debug|x64.ActiveCfg = Debug|Any CPU
+               {AD0C93A1-7E0A-4311-8088-143FCC13CA3E}.Debug|x86.ActiveCfg = Debug|Any CPU
+               {AD0C93A1-7E0A-4311-8088-143FCC13CA3E}.Release|Any CPU.ActiveCfg = Release|Any CPU
+               {AD0C93A1-7E0A-4311-8088-143FCC13CA3E}.Release|Any CPU.Build.0 = Release|Any CPU
+               {AD0C93A1-7E0A-4311-8088-143FCC13CA3E}.Release|ARM.ActiveCfg = Release|Any CPU
+               {AD0C93A1-7E0A-4311-8088-143FCC13CA3E}.Release|Mixed Platforms.ActiveCfg = Release|Any CPU
+               {AD0C93A1-7E0A-4311-8088-143FCC13CA3E}.Release|Mixed Platforms.Build.0 = Release|Any CPU
+               {AD0C93A1-7E0A-4311-8088-143FCC13CA3E}.Release|x64.ActiveCfg = Release|Any CPU
+               {AD0C93A1-7E0A-4311-8088-143FCC13CA3E}.Release|x86.ActiveCfg = Release|Any CPU
+               {C84CAEBA-3326-41C8-81DA-B1EB680D7FA1}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
+               {C84CAEBA-3326-41C8-81DA-B1EB680D7FA1}.Debug|Any CPU.Build.0 = Debug|Any CPU
+               {C84CAEBA-3326-41C8-81DA-B1EB680D7FA1}.Debug|ARM.ActiveCfg = Debug|Any CPU
+               {C84CAEBA-3326-41C8-81DA-B1EB680D7FA1}.Debug|Mixed Platforms.ActiveCfg = Debug|Any CPU
+               {C84CAEBA-3326-41C8-81DA-B1EB680D7FA1}.Debug|Mixed Platforms.Build.0 = Debug|Any CPU
+               {C84CAEBA-3326-41C8-81DA-B1EB680D7FA1}.Debug|x64.ActiveCfg = Debug|Any CPU
+               {C84CAEBA-3326-41C8-81DA-B1EB680D7FA1}.Debug|x86.ActiveCfg = Debug|Any CPU
+               {C84CAEBA-3326-41C8-81DA-B1EB680D7FA1}.Release|Any CPU.ActiveCfg = Release|Any CPU
+               {C84CAEBA-3326-41C8-81DA-B1EB680D7FA1}.Release|Any CPU.Build.0 = Release|Any CPU
+               {C84CAEBA-3326-41C8-81DA-B1EB680D7FA1}.Release|ARM.ActiveCfg = Release|Any CPU
+               {C84CAEBA-3326-41C8-81DA-B1EB680D7FA1}.Release|Mixed Platforms.ActiveCfg = Release|Any CPU
+               {C84CAEBA-3326-41C8-81DA-B1EB680D7FA1}.Release|Mixed Platforms.Build.0 = Release|Any CPU
+               {C84CAEBA-3326-41C8-81DA-B1EB680D7FA1}.Release|x64.ActiveCfg = Release|Any CPU
+               {C84CAEBA-3326-41C8-81DA-B1EB680D7FA1}.Release|x86.ActiveCfg = Release|Any CPU
+               {10A30E0C-D902-4803-9CCD-8902C41CA244}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
+               {10A30E0C-D902-4803-9CCD-8902C41CA244}.Debug|Any CPU.Build.0 = Debug|Any CPU
+               {10A30E0C-D902-4803-9CCD-8902C41CA244}.Debug|ARM.ActiveCfg = Debug|Any CPU
+               {10A30E0C-D902-4803-9CCD-8902C41CA244}.Debug|Mixed Platforms.ActiveCfg = Debug|Any CPU
+               {10A30E0C-D902-4803-9CCD-8902C41CA244}.Debug|Mixed Platforms.Build.0 = Debug|Any CPU
+               {10A30E0C-D902-4803-9CCD-8902C41CA244}.Debug|x64.ActiveCfg = Debug|Any CPU
+               {10A30E0C-D902-4803-9CCD-8902C41CA244}.Debug|x86.ActiveCfg = Debug|Any CPU
+               {10A30E0C-D902-4803-9CCD-8902C41CA244}.Release|Any CPU.ActiveCfg = Release|Any CPU
+               {10A30E0C-D902-4803-9CCD-8902C41CA244}.Release|Any CPU.Build.0 = Release|Any CPU
+               {10A30E0C-D902-4803-9CCD-8902C41CA244}.Release|ARM.ActiveCfg = Release|Any CPU
+               {10A30E0C-D902-4803-9CCD-8902C41CA244}.Release|Mixed Platforms.ActiveCfg = Release|Any CPU
+               {10A30E0C-D902-4803-9CCD-8902C41CA244}.Release|Mixed Platforms.Build.0 = Release|Any CPU
+               {10A30E0C-D902-4803-9CCD-8902C41CA244}.Release|x64.ActiveCfg = Release|Any CPU
+               {10A30E0C-D902-4803-9CCD-8902C41CA244}.Release|x86.ActiveCfg = Release|Any CPU
+               {AF4DF6F4-FD99-4236-B0F1-CE8F5AD0D8A2}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
+               {AF4DF6F4-FD99-4236-B0F1-CE8F5AD0D8A2}.Debug|Any CPU.Build.0 = Debug|Any CPU
+               {AF4DF6F4-FD99-4236-B0F1-CE8F5AD0D8A2}.Debug|ARM.ActiveCfg = Debug|Any CPU
+               {AF4DF6F4-FD99-4236-B0F1-CE8F5AD0D8A2}.Debug|Mixed Platforms.ActiveCfg = Debug|Any CPU
+               {AF4DF6F4-FD99-4236-B0F1-CE8F5AD0D8A2}.Debug|Mixed Platforms.Build.0 = Debug|Any CPU
+               {AF4DF6F4-FD99-4236-B0F1-CE8F5AD0D8A2}.Debug|x64.ActiveCfg = Debug|Any CPU
+               {AF4DF6F4-FD99-4236-B0F1-CE8F5AD0D8A2}.Debug|x86.ActiveCfg = Debug|Any CPU
+               {AF4DF6F4-FD99-4236-B0F1-CE8F5AD0D8A2}.Release|Any CPU.ActiveCfg = Release|Any CPU
+               {AF4DF6F4-FD99-4236-B0F1-CE8F5AD0D8A2}.Release|Any CPU.Build.0 = Release|Any CPU
+               {AF4DF6F4-FD99-4236-B0F1-CE8F5AD0D8A2}.Release|ARM.ActiveCfg = Release|Any CPU
+               {AF4DF6F4-FD99-4236-B0F1-CE8F5AD0D8A2}.Release|Mixed Platforms.ActiveCfg = Release|Any CPU
+               {AF4DF6F4-FD99-4236-B0F1-CE8F5AD0D8A2}.Release|Mixed Platforms.Build.0 = Release|Any CPU
+               {AF4DF6F4-FD99-4236-B0F1-CE8F5AD0D8A2}.Release|x64.ActiveCfg = Release|Any CPU
+               {AF4DF6F4-FD99-4236-B0F1-CE8F5AD0D8A2}.Release|x86.ActiveCfg = Release|Any CPU
+               {2FA3C4D5-1B43-4191-863C-F940DAA6A1EE}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
+               {2FA3C4D5-1B43-4191-863C-F940DAA6A1EE}.Debug|Any CPU.Build.0 = Debug|Any CPU
+               {2FA3C4D5-1B43-4191-863C-F940DAA6A1EE}.Debug|ARM.ActiveCfg = Debug|Any CPU
+               {2FA3C4D5-1B43-4191-863C-F940DAA6A1EE}.Debug|Mixed Platforms.ActiveCfg = Debug|Any CPU
+               {2FA3C4D5-1B43-4191-863C-F940DAA6A1EE}.Debug|Mixed Platforms.Build.0 = Debug|Any CPU
+               {2FA3C4D5-1B43-4191-863C-F940DAA6A1EE}.Debug|x64.ActiveCfg = Debug|Any CPU
+               {2FA3C4D5-1B43-4191-863C-F940DAA6A1EE}.Debug|x86.ActiveCfg = Debug|Any CPU
+               {2FA3C4D5-1B43-4191-863C-F940DAA6A1EE}.Release|Any CPU.ActiveCfg = Release|Any CPU
+               {2FA3C4D5-1B43-4191-863C-F940DAA6A1EE}.Release|Any CPU.Build.0 = Release|Any CPU
+               {2FA3C4D5-1B43-4191-863C-F940DAA6A1EE}.Release|ARM.ActiveCfg = Release|Any CPU
+               {2FA3C4D5-1B43-4191-863C-F940DAA6A1EE}.Release|Mixed Platforms.ActiveCfg = Release|Any CPU
+               {2FA3C4D5-1B43-4191-863C-F940DAA6A1EE}.Release|Mixed Platforms.Build.0 = Release|Any CPU
+               {2FA3C4D5-1B43-4191-863C-F940DAA6A1EE}.Release|x64.ActiveCfg = Release|Any CPU
+               {2FA3C4D5-1B43-4191-863C-F940DAA6A1EE}.Release|x86.ActiveCfg = Release|Any CPU
+               {E965BA32-9561-4E2A-ADB0-19487B25A939}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
+               {E965BA32-9561-4E2A-ADB0-19487B25A939}.Debug|Any CPU.Build.0 = Debug|Any CPU
+               {E965BA32-9561-4E2A-ADB0-19487B25A939}.Debug|ARM.ActiveCfg = Debug|Any CPU
+               {E965BA32-9561-4E2A-ADB0-19487B25A939}.Debug|Mixed Platforms.ActiveCfg = Debug|Any CPU
+               {E965BA32-9561-4E2A-ADB0-19487B25A939}.Debug|Mixed Platforms.Build.0 = Debug|Any CPU
+               {E965BA32-9561-4E2A-ADB0-19487B25A939}.Debug|x64.ActiveCfg = Debug|Any CPU
+               {E965BA32-9561-4E2A-ADB0-19487B25A939}.Debug|x86.ActiveCfg = Debug|Any CPU
+               {E965BA32-9561-4E2A-ADB0-19487B25A939}.Release|Any CPU.ActiveCfg = Release|Any CPU
+               {E965BA32-9561-4E2A-ADB0-19487B25A939}.Release|Any CPU.Build.0 = Release|Any CPU
+               {E965BA32-9561-4E2A-ADB0-19487B25A939}.Release|ARM.ActiveCfg = Release|Any CPU
+               {E965BA32-9561-4E2A-ADB0-19487B25A939}.Release|Mixed Platforms.ActiveCfg = Release|Any CPU
+               {E965BA32-9561-4E2A-ADB0-19487B25A939}.Release|Mixed Platforms.Build.0 = Release|Any CPU
+               {E965BA32-9561-4E2A-ADB0-19487B25A939}.Release|x64.ActiveCfg = Release|Any CPU
+               {E965BA32-9561-4E2A-ADB0-19487B25A939}.Release|x86.ActiveCfg = Release|Any CPU
+               {4238CB37-AD71-4E7B-84DB-C97DBBD94082}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
+               {4238CB37-AD71-4E7B-84DB-C97DBBD94082}.Debug|Any CPU.Build.0 = Debug|Any CPU
+               {4238CB37-AD71-4E7B-84DB-C97DBBD94082}.Debug|Any CPU.Deploy.0 = Debug|Any CPU
+               {4238CB37-AD71-4E7B-84DB-C97DBBD94082}.Debug|ARM.ActiveCfg = Debug|ARM
+               {4238CB37-AD71-4E7B-84DB-C97DBBD94082}.Debug|ARM.Build.0 = Debug|ARM
+               {4238CB37-AD71-4E7B-84DB-C97DBBD94082}.Debug|ARM.Deploy.0 = Debug|ARM
+               {4238CB37-AD71-4E7B-84DB-C97DBBD94082}.Debug|Mixed Platforms.ActiveCfg = Debug|x86
+               {4238CB37-AD71-4E7B-84DB-C97DBBD94082}.Debug|Mixed Platforms.Build.0 = Debug|x86
+               {4238CB37-AD71-4E7B-84DB-C97DBBD94082}.Debug|Mixed Platforms.Deploy.0 = Debug|x86
+               {4238CB37-AD71-4E7B-84DB-C97DBBD94082}.Debug|x64.ActiveCfg = Debug|x64
+               {4238CB37-AD71-4E7B-84DB-C97DBBD94082}.Debug|x64.Build.0 = Debug|x64
+               {4238CB37-AD71-4E7B-84DB-C97DBBD94082}.Debug|x64.Deploy.0 = Debug|x64
+               {4238CB37-AD71-4E7B-84DB-C97DBBD94082}.Debug|x86.ActiveCfg = Debug|x86
+               {4238CB37-AD71-4E7B-84DB-C97DBBD94082}.Debug|x86.Build.0 = Debug|x86
+               {4238CB37-AD71-4E7B-84DB-C97DBBD94082}.Debug|x86.Deploy.0 = Debug|x86
+               {4238CB37-AD71-4E7B-84DB-C97DBBD94082}.Release|Any CPU.ActiveCfg = Release|Any CPU
+               {4238CB37-AD71-4E7B-84DB-C97DBBD94082}.Release|Any CPU.Build.0 = Release|Any CPU
+               {4238CB37-AD71-4E7B-84DB-C97DBBD94082}.Release|Any CPU.Deploy.0 = Release|Any CPU
+               {4238CB37-AD71-4E7B-84DB-C97DBBD94082}.Release|ARM.ActiveCfg = Release|ARM
+               {4238CB37-AD71-4E7B-84DB-C97DBBD94082}.Release|ARM.Build.0 = Release|ARM
+               {4238CB37-AD71-4E7B-84DB-C97DBBD94082}.Release|ARM.Deploy.0 = Release|ARM
+               {4238CB37-AD71-4E7B-84DB-C97DBBD94082}.Release|Mixed Platforms.ActiveCfg = Release|x86
+               {4238CB37-AD71-4E7B-84DB-C97DBBD94082}.Release|Mixed Platforms.Build.0 = Release|x86
+               {4238CB37-AD71-4E7B-84DB-C97DBBD94082}.Release|Mixed Platforms.Deploy.0 = Release|x86
+               {4238CB37-AD71-4E7B-84DB-C97DBBD94082}.Release|x64.ActiveCfg = Release|x64
+               {4238CB37-AD71-4E7B-84DB-C97DBBD94082}.Release|x64.Build.0 = Release|x64
+               {4238CB37-AD71-4E7B-84DB-C97DBBD94082}.Release|x64.Deploy.0 = Release|x64
+               {4238CB37-AD71-4E7B-84DB-C97DBBD94082}.Release|x86.ActiveCfg = Release|x86
+               {4238CB37-AD71-4E7B-84DB-C97DBBD94082}.Release|x86.Build.0 = Release|x86
+               {4238CB37-AD71-4E7B-84DB-C97DBBD94082}.Release|x86.Deploy.0 = Release|x86
+               {F18CD317-7774-4AFF-8866-E5B42BF71D1E}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
+               {F18CD317-7774-4AFF-8866-E5B42BF71D1E}.Debug|Any CPU.Build.0 = Debug|Any CPU
+               {F18CD317-7774-4AFF-8866-E5B42BF71D1E}.Debug|Any CPU.Deploy.0 = Debug|Any CPU
+               {F18CD317-7774-4AFF-8866-E5B42BF71D1E}.Debug|ARM.ActiveCfg = Debug|ARM
+               {F18CD317-7774-4AFF-8866-E5B42BF71D1E}.Debug|ARM.Build.0 = Debug|ARM
+               {F18CD317-7774-4AFF-8866-E5B42BF71D1E}.Debug|ARM.Deploy.0 = Debug|ARM
+               {F18CD317-7774-4AFF-8866-E5B42BF71D1E}.Debug|Mixed Platforms.ActiveCfg = Debug|x86
+               {F18CD317-7774-4AFF-8866-E5B42BF71D1E}.Debug|Mixed Platforms.Build.0 = Debug|x86
+               {F18CD317-7774-4AFF-8866-E5B42BF71D1E}.Debug|Mixed Platforms.Deploy.0 = Debug|x86
+               {F18CD317-7774-4AFF-8866-E5B42BF71D1E}.Debug|x64.ActiveCfg = Debug|x64
+               {F18CD317-7774-4AFF-8866-E5B42BF71D1E}.Debug|x64.Build.0 = Debug|x64
+               {F18CD317-7774-4AFF-8866-E5B42BF71D1E}.Debug|x64.Deploy.0 = Debug|x64
+               {F18CD317-7774-4AFF-8866-E5B42BF71D1E}.Debug|x86.ActiveCfg = Debug|x86
+               {F18CD317-7774-4AFF-8866-E5B42BF71D1E}.Debug|x86.Build.0 = Debug|x86
+               {F18CD317-7774-4AFF-8866-E5B42BF71D1E}.Debug|x86.Deploy.0 = Debug|x86
+               {F18CD317-7774-4AFF-8866-E5B42BF71D1E}.Release|Any CPU.ActiveCfg = Release|Any CPU
+               {F18CD317-7774-4AFF-8866-E5B42BF71D1E}.Release|Any CPU.Build.0 = Release|Any CPU
+               {F18CD317-7774-4AFF-8866-E5B42BF71D1E}.Release|Any CPU.Deploy.0 = Release|Any CPU
+               {F18CD317-7774-4AFF-8866-E5B42BF71D1E}.Release|ARM.ActiveCfg = Release|ARM
+               {F18CD317-7774-4AFF-8866-E5B42BF71D1E}.Release|ARM.Build.0 = Release|ARM
+               {F18CD317-7774-4AFF-8866-E5B42BF71D1E}.Release|ARM.Deploy.0 = Release|ARM
+               {F18CD317-7774-4AFF-8866-E5B42BF71D1E}.Release|Mixed Platforms.ActiveCfg = Release|x86
+               {F18CD317-7774-4AFF-8866-E5B42BF71D1E}.Release|Mixed Platforms.Build.0 = Release|x86
+               {F18CD317-7774-4AFF-8866-E5B42BF71D1E}.Release|Mixed Platforms.Deploy.0 = Release|x86
+               {F18CD317-7774-4AFF-8866-E5B42BF71D1E}.Release|x64.ActiveCfg = Release|x64
+               {F18CD317-7774-4AFF-8866-E5B42BF71D1E}.Release|x64.Build.0 = Release|x64
+               {F18CD317-7774-4AFF-8866-E5B42BF71D1E}.Release|x64.Deploy.0 = Release|x64
+               {F18CD317-7774-4AFF-8866-E5B42BF71D1E}.Release|x86.ActiveCfg = Release|x86
+               {F18CD317-7774-4AFF-8866-E5B42BF71D1E}.Release|x86.Build.0 = Release|x86
+               {F18CD317-7774-4AFF-8866-E5B42BF71D1E}.Release|x86.Deploy.0 = Release|x86
+               {138BFD13-0ED1-49F5-B902-78770CB3D66B}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
+               {138BFD13-0ED1-49F5-B902-78770CB3D66B}.Debug|Any CPU.Build.0 = Debug|Any CPU
+               {138BFD13-0ED1-49F5-B902-78770CB3D66B}.Debug|ARM.ActiveCfg = Debug|Any CPU
+               {138BFD13-0ED1-49F5-B902-78770CB3D66B}.Debug|Mixed Platforms.ActiveCfg = Debug|Any CPU
+               {138BFD13-0ED1-49F5-B902-78770CB3D66B}.Debug|Mixed Platforms.Build.0 = Debug|Any CPU
+               {138BFD13-0ED1-49F5-B902-78770CB3D66B}.Debug|x64.ActiveCfg = Debug|Any CPU
+               {138BFD13-0ED1-49F5-B902-78770CB3D66B}.Debug|x86.ActiveCfg = Debug|Any CPU
+               {138BFD13-0ED1-49F5-B902-78770CB3D66B}.Release|Any CPU.ActiveCfg = Release|Any CPU
+               {138BFD13-0ED1-49F5-B902-78770CB3D66B}.Release|Any CPU.Build.0 = Release|Any CPU
+               {138BFD13-0ED1-49F5-B902-78770CB3D66B}.Release|ARM.ActiveCfg = Release|Any CPU
+               {138BFD13-0ED1-49F5-B902-78770CB3D66B}.Release|Mixed Platforms.ActiveCfg = Release|Any CPU
+               {138BFD13-0ED1-49F5-B902-78770CB3D66B}.Release|Mixed Platforms.Build.0 = Release|Any CPU
+               {138BFD13-0ED1-49F5-B902-78770CB3D66B}.Release|x64.ActiveCfg = Release|Any CPU
+               {138BFD13-0ED1-49F5-B902-78770CB3D66B}.Release|x86.ActiveCfg = Release|Any CPU
+               {44DC1E63-C7D0-4068-9FAE-1F18A4CEA918}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
+               {44DC1E63-C7D0-4068-9FAE-1F18A4CEA918}.Debug|Any CPU.Build.0 = Debug|Any CPU
+               {44DC1E63-C7D0-4068-9FAE-1F18A4CEA918}.Debug|ARM.ActiveCfg = Debug|Any CPU
+               {44DC1E63-C7D0-4068-9FAE-1F18A4CEA918}.Debug|Mixed Platforms.ActiveCfg = Debug|Any CPU
+               {44DC1E63-C7D0-4068-9FAE-1F18A4CEA918}.Debug|Mixed Platforms.Build.0 = Debug|Any CPU
+               {44DC1E63-C7D0-4068-9FAE-1F18A4CEA918}.Debug|x64.ActiveCfg = Debug|Any CPU
+               {44DC1E63-C7D0-4068-9FAE-1F18A4CEA918}.Debug|x86.ActiveCfg = Debug|Any CPU
+               {44DC1E63-C7D0-4068-9FAE-1F18A4CEA918}.Release|Any CPU.ActiveCfg = Release|Any CPU
+               {44DC1E63-C7D0-4068-9FAE-1F18A4CEA918}.Release|Any CPU.Build.0 = Release|Any CPU
+               {44DC1E63-C7D0-4068-9FAE-1F18A4CEA918}.Release|ARM.ActiveCfg = Release|Any CPU
+               {44DC1E63-C7D0-4068-9FAE-1F18A4CEA918}.Release|Mixed Platforms.ActiveCfg = Release|Any CPU
+               {44DC1E63-C7D0-4068-9FAE-1F18A4CEA918}.Release|Mixed Platforms.Build.0 = Release|Any CPU
+               {44DC1E63-C7D0-4068-9FAE-1F18A4CEA918}.Release|x64.ActiveCfg = Release|Any CPU
+               {44DC1E63-C7D0-4068-9FAE-1F18A4CEA918}.Release|x86.ActiveCfg = Release|Any CPU
+               {BBAECBB8-149A-42EE-A4F4-6207D7954F8B}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
+               {BBAECBB8-149A-42EE-A4F4-6207D7954F8B}.Debug|Any CPU.Build.0 = Debug|Any CPU
+               {BBAECBB8-149A-42EE-A4F4-6207D7954F8B}.Debug|ARM.ActiveCfg = Debug|Any CPU
+               {BBAECBB8-149A-42EE-A4F4-6207D7954F8B}.Debug|Mixed Platforms.ActiveCfg = Debug|Any CPU
+               {BBAECBB8-149A-42EE-A4F4-6207D7954F8B}.Debug|Mixed Platforms.Build.0 = Debug|Any CPU
+               {BBAECBB8-149A-42EE-A4F4-6207D7954F8B}.Debug|x64.ActiveCfg = Debug|Any CPU
+               {BBAECBB8-149A-42EE-A4F4-6207D7954F8B}.Debug|x86.ActiveCfg = Debug|Any CPU
+               {BBAECBB8-149A-42EE-A4F4-6207D7954F8B}.Release|Any CPU.ActiveCfg = Release|Any CPU
+               {BBAECBB8-149A-42EE-A4F4-6207D7954F8B}.Release|Any CPU.Build.0 = Release|Any CPU
+               {BBAECBB8-149A-42EE-A4F4-6207D7954F8B}.Release|ARM.ActiveCfg = Release|Any CPU
+               {BBAECBB8-149A-42EE-A4F4-6207D7954F8B}.Release|Mixed Platforms.ActiveCfg = Release|Any CPU
+               {BBAECBB8-149A-42EE-A4F4-6207D7954F8B}.Release|Mixed Platforms.Build.0 = Release|Any CPU
+               {BBAECBB8-149A-42EE-A4F4-6207D7954F8B}.Release|x64.ActiveCfg = Release|Any CPU
+               {BBAECBB8-149A-42EE-A4F4-6207D7954F8B}.Release|x86.ActiveCfg = Release|Any CPU
+               {9B8816E0-026F-4255-9EA9-9997E33AE377}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
+               {9B8816E0-026F-4255-9EA9-9997E33AE377}.Debug|Any CPU.Build.0 = Debug|Any CPU
+               {9B8816E0-026F-4255-9EA9-9997E33AE377}.Debug|ARM.ActiveCfg = Debug|Any CPU
+               {9B8816E0-026F-4255-9EA9-9997E33AE377}.Debug|Mixed Platforms.ActiveCfg = Debug|Any CPU
+               {9B8816E0-026F-4255-9EA9-9997E33AE377}.Debug|Mixed Platforms.Build.0 = Debug|Any CPU
+               {9B8816E0-026F-4255-9EA9-9997E33AE377}.Debug|x64.ActiveCfg = Debug|Any CPU
+               {9B8816E0-026F-4255-9EA9-9997E33AE377}.Debug|x86.ActiveCfg = Debug|Any CPU
+               {9B8816E0-026F-4255-9EA9-9997E33AE377}.Release|Any CPU.ActiveCfg = Release|Any CPU
+               {9B8816E0-026F-4255-9EA9-9997E33AE377}.Release|Any CPU.Build.0 = Release|Any CPU
+               {9B8816E0-026F-4255-9EA9-9997E33AE377}.Release|ARM.ActiveCfg = Release|Any CPU
+               {9B8816E0-026F-4255-9EA9-9997E33AE377}.Release|Mixed Platforms.ActiveCfg = Release|Any CPU
+               {9B8816E0-026F-4255-9EA9-9997E33AE377}.Release|Mixed Platforms.Build.0 = Release|Any CPU
+               {9B8816E0-026F-4255-9EA9-9997E33AE377}.Release|x64.ActiveCfg = Release|Any CPU
+               {9B8816E0-026F-4255-9EA9-9997E33AE377}.Release|x86.ActiveCfg = Release|Any CPU
+               {BD75B688-D4A3-405F-BC08-E371993A6273}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
+               {BD75B688-D4A3-405F-BC08-E371993A6273}.Debug|Any CPU.Build.0 = Debug|Any CPU
+               {BD75B688-D4A3-405F-BC08-E371993A6273}.Debug|ARM.ActiveCfg = Debug|Any CPU
+               {BD75B688-D4A3-405F-BC08-E371993A6273}.Debug|Mixed Platforms.ActiveCfg = Debug|Any CPU
+               {BD75B688-D4A3-405F-BC08-E371993A6273}.Debug|Mixed Platforms.Build.0 = Debug|Any CPU
+               {BD75B688-D4A3-405F-BC08-E371993A6273}.Debug|x64.ActiveCfg = Debug|Any CPU
+               {BD75B688-D4A3-405F-BC08-E371993A6273}.Debug|x86.ActiveCfg = Debug|Any CPU
+               {BD75B688-D4A3-405F-BC08-E371993A6273}.Release|Any CPU.ActiveCfg = Release|Any CPU
+               {BD75B688-D4A3-405F-BC08-E371993A6273}.Release|Any CPU.Build.0 = Release|Any CPU
+               {BD75B688-D4A3-405F-BC08-E371993A6273}.Release|ARM.ActiveCfg = Release|Any CPU
+               {BD75B688-D4A3-405F-BC08-E371993A6273}.Release|Mixed Platforms.ActiveCfg = Release|Any CPU
+               {BD75B688-D4A3-405F-BC08-E371993A6273}.Release|Mixed Platforms.Build.0 = Release|Any CPU
+               {BD75B688-D4A3-405F-BC08-E371993A6273}.Release|x64.ActiveCfg = Release|Any CPU
+               {BD75B688-D4A3-405F-BC08-E371993A6273}.Release|x86.ActiveCfg = Release|Any CPU
+               {15B1DC32-92C8-4301-A16D-9C47EE8356A2}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
+               {15B1DC32-92C8-4301-A16D-9C47EE8356A2}.Debug|Any CPU.Build.0 = Debug|Any CPU
+               {15B1DC32-92C8-4301-A16D-9C47EE8356A2}.Debug|ARM.ActiveCfg = Debug|Any CPU
+               {15B1DC32-92C8-4301-A16D-9C47EE8356A2}.Debug|Mixed Platforms.ActiveCfg = Debug|Any CPU
+               {15B1DC32-92C8-4301-A16D-9C47EE8356A2}.Debug|Mixed Platforms.Build.0 = Debug|Any CPU
+               {15B1DC32-92C8-4301-A16D-9C47EE8356A2}.Debug|x64.ActiveCfg = Debug|Any CPU
+               {15B1DC32-92C8-4301-A16D-9C47EE8356A2}.Debug|x86.ActiveCfg = Debug|Any CPU
+               {15B1DC32-92C8-4301-A16D-9C47EE8356A2}.Release|Any CPU.ActiveCfg = Release|Any CPU
+               {15B1DC32-92C8-4301-A16D-9C47EE8356A2}.Release|Any CPU.Build.0 = Release|Any CPU
+               {15B1DC32-92C8-4301-A16D-9C47EE8356A2}.Release|ARM.ActiveCfg = Release|Any CPU
+               {15B1DC32-92C8-4301-A16D-9C47EE8356A2}.Release|Mixed Platforms.ActiveCfg = Release|Any CPU
+               {15B1DC32-92C8-4301-A16D-9C47EE8356A2}.Release|Mixed Platforms.Build.0 = Release|Any CPU
+               {15B1DC32-92C8-4301-A16D-9C47EE8356A2}.Release|x64.ActiveCfg = Release|Any CPU
+               {15B1DC32-92C8-4301-A16D-9C47EE8356A2}.Release|x86.ActiveCfg = Release|Any CPU
+               {564E1DBA-3B0C-441D-9ACA-73B0A54D07AB}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
+               {564E1DBA-3B0C-441D-9ACA-73B0A54D07AB}.Debug|Any CPU.Build.0 = Debug|Any CPU
+               {564E1DBA-3B0C-441D-9ACA-73B0A54D07AB}.Debug|ARM.ActiveCfg = Debug|Any CPU
+               {564E1DBA-3B0C-441D-9ACA-73B0A54D07AB}.Debug|Mixed Platforms.ActiveCfg = Debug|Any CPU
+               {564E1DBA-3B0C-441D-9ACA-73B0A54D07AB}.Debug|Mixed Platforms.Build.0 = Debug|Any CPU
+               {564E1DBA-3B0C-441D-9ACA-73B0A54D07AB}.Debug|x64.ActiveCfg = Debug|Any CPU
+               {564E1DBA-3B0C-441D-9ACA-73B0A54D07AB}.Debug|x86.ActiveCfg = Debug|Any CPU
+               {564E1DBA-3B0C-441D-9ACA-73B0A54D07AB}.Release|Any CPU.ActiveCfg = Release|Any CPU
+               {564E1DBA-3B0C-441D-9ACA-73B0A54D07AB}.Release|Any CPU.Build.0 = Release|Any CPU
+               {564E1DBA-3B0C-441D-9ACA-73B0A54D07AB}.Release|ARM.ActiveCfg = Release|Any CPU
+               {564E1DBA-3B0C-441D-9ACA-73B0A54D07AB}.Release|Mixed Platforms.ActiveCfg = Release|Any CPU
+               {564E1DBA-3B0C-441D-9ACA-73B0A54D07AB}.Release|Mixed Platforms.Build.0 = Release|Any CPU
+               {564E1DBA-3B0C-441D-9ACA-73B0A54D07AB}.Release|x64.ActiveCfg = Release|Any CPU
+               {564E1DBA-3B0C-441D-9ACA-73B0A54D07AB}.Release|x86.ActiveCfg = Release|Any CPU
+               {BB639CDB-36F9-4DCB-A075-B713CC5A9A3F}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
+               {BB639CDB-36F9-4DCB-A075-B713CC5A9A3F}.Debug|Any CPU.Build.0 = Debug|Any CPU
+               {BB639CDB-36F9-4DCB-A075-B713CC5A9A3F}.Debug|ARM.ActiveCfg = Debug|Any CPU
+               {BB639CDB-36F9-4DCB-A075-B713CC5A9A3F}.Debug|Mixed Platforms.ActiveCfg = Debug|Any CPU
+               {BB639CDB-36F9-4DCB-A075-B713CC5A9A3F}.Debug|Mixed Platforms.Build.0 = Debug|Any CPU
+               {BB639CDB-36F9-4DCB-A075-B713CC5A9A3F}.Debug|x64.ActiveCfg = Debug|Any CPU
+               {BB639CDB-36F9-4DCB-A075-B713CC5A9A3F}.Debug|x86.ActiveCfg = Debug|Any CPU
+               {BB639CDB-36F9-4DCB-A075-B713CC5A9A3F}.Release|Any CPU.ActiveCfg = Release|Any CPU
+               {BB639CDB-36F9-4DCB-A075-B713CC5A9A3F}.Release|Any CPU.Build.0 = Release|Any CPU
+               {BB639CDB-36F9-4DCB-A075-B713CC5A9A3F}.Release|ARM.ActiveCfg = Release|Any CPU
+               {BB639CDB-36F9-4DCB-A075-B713CC5A9A3F}.Release|Mixed Platforms.ActiveCfg = Release|Any CPU
+               {BB639CDB-36F9-4DCB-A075-B713CC5A9A3F}.Release|Mixed Platforms.Build.0 = Release|Any CPU
+               {BB639CDB-36F9-4DCB-A075-B713CC5A9A3F}.Release|x64.ActiveCfg = Release|Any CPU
+               {BB639CDB-36F9-4DCB-A075-B713CC5A9A3F}.Release|x86.ActiveCfg = Release|Any CPU
+               {5C307156-E173-425B-8FC7-4B5CB63C7980}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
+               {5C307156-E173-425B-8FC7-4B5CB63C7980}.Debug|Any CPU.Build.0 = Debug|Any CPU
+               {5C307156-E173-425B-8FC7-4B5CB63C7980}.Debug|ARM.ActiveCfg = Debug|Any CPU
+               {5C307156-E173-425B-8FC7-4B5CB63C7980}.Debug|Mixed Platforms.ActiveCfg = Debug|Any CPU
+               {5C307156-E173-425B-8FC7-4B5CB63C7980}.Debug|Mixed Platforms.Build.0 = Debug|Any CPU
+               {5C307156-E173-425B-8FC7-4B5CB63C7980}.Debug|x64.ActiveCfg = Debug|Any CPU
+               {5C307156-E173-425B-8FC7-4B5CB63C7980}.Debug|x86.ActiveCfg = Debug|Any CPU
+               {5C307156-E173-425B-8FC7-4B5CB63C7980}.Release|Any CPU.ActiveCfg = Release|Any CPU
+               {5C307156-E173-425B-8FC7-4B5CB63C7980}.Release|Any CPU.Build.0 = Release|Any CPU
+               {5C307156-E173-425B-8FC7-4B5CB63C7980}.Release|ARM.ActiveCfg = Release|Any CPU
+               {5C307156-E173-425B-8FC7-4B5CB63C7980}.Release|Mixed Platforms.ActiveCfg = Release|Any CPU
+               {5C307156-E173-425B-8FC7-4B5CB63C7980}.Release|Mixed Platforms.Build.0 = Release|Any CPU
+               {5C307156-E173-425B-8FC7-4B5CB63C7980}.Release|x64.ActiveCfg = Release|Any CPU
+               {5C307156-E173-425B-8FC7-4B5CB63C7980}.Release|x86.ActiveCfg = Release|Any CPU
+               {66F2A02F-EF7B-4EBF-AD1B-6506BF7BD983}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
+               {66F2A02F-EF7B-4EBF-AD1B-6506BF7BD983}.Debug|Any CPU.Build.0 = Debug|Any CPU
+               {66F2A02F-EF7B-4EBF-AD1B-6506BF7BD983}.Debug|ARM.ActiveCfg = Debug|Any CPU
+               {66F2A02F-EF7B-4EBF-AD1B-6506BF7BD983}.Debug|Mixed Platforms.ActiveCfg = Debug|Any CPU
+               {66F2A02F-EF7B-4EBF-AD1B-6506BF7BD983}.Debug|Mixed Platforms.Build.0 = Debug|Any CPU
+               {66F2A02F-EF7B-4EBF-AD1B-6506BF7BD983}.Debug|x64.ActiveCfg = Debug|Any CPU
+               {66F2A02F-EF7B-4EBF-AD1B-6506BF7BD983}.Debug|x86.ActiveCfg = Debug|Any CPU
+               {66F2A02F-EF7B-4EBF-AD1B-6506BF7BD983}.Release|Any CPU.ActiveCfg = Release|Any CPU
+               {66F2A02F-EF7B-4EBF-AD1B-6506BF7BD983}.Release|Any CPU.Build.0 = Release|Any CPU
+               {66F2A02F-EF7B-4EBF-AD1B-6506BF7BD983}.Release|ARM.ActiveCfg = Release|Any CPU
+               {66F2A02F-EF7B-4EBF-AD1B-6506BF7BD983}.Release|Mixed Platforms.ActiveCfg = Release|Any CPU
+               {66F2A02F-EF7B-4EBF-AD1B-6506BF7BD983}.Release|Mixed Platforms.Build.0 = Release|Any CPU
+               {66F2A02F-EF7B-4EBF-AD1B-6506BF7BD983}.Release|x64.ActiveCfg = Release|Any CPU
+               {66F2A02F-EF7B-4EBF-AD1B-6506BF7BD983}.Release|x86.ActiveCfg = Release|Any CPU
+               {ECAEB12F-7177-41FF-98D4-2EA7F5F110F0}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
+               {ECAEB12F-7177-41FF-98D4-2EA7F5F110F0}.Debug|Any CPU.Build.0 = Debug|Any CPU
+               {ECAEB12F-7177-41FF-98D4-2EA7F5F110F0}.Debug|ARM.ActiveCfg = Debug|Any CPU
+               {ECAEB12F-7177-41FF-98D4-2EA7F5F110F0}.Debug|Mixed Platforms.ActiveCfg = Debug|Any CPU
+               {ECAEB12F-7177-41FF-98D4-2EA7F5F110F0}.Debug|Mixed Platforms.Build.0 = Debug|Any CPU
+               {ECAEB12F-7177-41FF-98D4-2EA7F5F110F0}.Debug|x64.ActiveCfg = Debug|Any CPU
+               {ECAEB12F-7177-41FF-98D4-2EA7F5F110F0}.Debug|x86.ActiveCfg = Debug|Any CPU
+               {ECAEB12F-7177-41FF-98D4-2EA7F5F110F0}.Release|Any CPU.ActiveCfg = Release|Any CPU
+               {ECAEB12F-7177-41FF-98D4-2EA7F5F110F0}.Release|Any CPU.Build.0 = Release|Any CPU
+               {ECAEB12F-7177-41FF-98D4-2EA7F5F110F0}.Release|ARM.ActiveCfg = Release|Any CPU
+               {ECAEB12F-7177-41FF-98D4-2EA7F5F110F0}.Release|Mixed Platforms.ActiveCfg = Release|Any CPU
+               {ECAEB12F-7177-41FF-98D4-2EA7F5F110F0}.Release|Mixed Platforms.Build.0 = Release|Any CPU
+               {ECAEB12F-7177-41FF-98D4-2EA7F5F110F0}.Release|x64.ActiveCfg = Release|Any CPU
+               {ECAEB12F-7177-41FF-98D4-2EA7F5F110F0}.Release|x86.ActiveCfg = Release|Any CPU
+               {47BDB77E-C1AD-4784-ACA7-FC2D70C3A2BC}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
+               {47BDB77E-C1AD-4784-ACA7-FC2D70C3A2BC}.Debug|Any CPU.Build.0 = Debug|Any CPU
+               {47BDB77E-C1AD-4784-ACA7-FC2D70C3A2BC}.Debug|ARM.ActiveCfg = Debug|Any CPU
+               {47BDB77E-C1AD-4784-ACA7-FC2D70C3A2BC}.Debug|Mixed Platforms.ActiveCfg = Debug|Any CPU
+               {47BDB77E-C1AD-4784-ACA7-FC2D70C3A2BC}.Debug|Mixed Platforms.Build.0 = Debug|Any CPU
+               {47BDB77E-C1AD-4784-ACA7-FC2D70C3A2BC}.Debug|x64.ActiveCfg = Debug|Any CPU
+               {47BDB77E-C1AD-4784-ACA7-FC2D70C3A2BC}.Debug|x86.ActiveCfg = Debug|Any CPU
+               {47BDB77E-C1AD-4784-ACA7-FC2D70C3A2BC}.Release|Any CPU.ActiveCfg = Release|Any CPU
+               {47BDB77E-C1AD-4784-ACA7-FC2D70C3A2BC}.Release|Any CPU.Build.0 = Release|Any CPU
+               {47BDB77E-C1AD-4784-ACA7-FC2D70C3A2BC}.Release|ARM.ActiveCfg = Release|Any CPU
+               {47BDB77E-C1AD-4784-ACA7-FC2D70C3A2BC}.Release|Mixed Platforms.ActiveCfg = Release|Any CPU
+               {47BDB77E-C1AD-4784-ACA7-FC2D70C3A2BC}.Release|Mixed Platforms.Build.0 = Release|Any CPU
+               {47BDB77E-C1AD-4784-ACA7-FC2D70C3A2BC}.Release|x64.ActiveCfg = Release|Any CPU
+               {47BDB77E-C1AD-4784-ACA7-FC2D70C3A2BC}.Release|x86.ActiveCfg = Release|Any CPU
+               {F4C226B3-0DAB-474C-9466-5EACAFA9B64A}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
+               {F4C226B3-0DAB-474C-9466-5EACAFA9B64A}.Debug|Any CPU.Build.0 = Debug|Any CPU
+               {F4C226B3-0DAB-474C-9466-5EACAFA9B64A}.Debug|ARM.ActiveCfg = Debug|Any CPU
+               {F4C226B3-0DAB-474C-9466-5EACAFA9B64A}.Debug|Mixed Platforms.ActiveCfg = Debug|Any CPU
+               {F4C226B3-0DAB-474C-9466-5EACAFA9B64A}.Debug|Mixed Platforms.Build.0 = Debug|Any CPU
+               {F4C226B3-0DAB-474C-9466-5EACAFA9B64A}.Debug|x64.ActiveCfg = Debug|Any CPU
+               {F4C226B3-0DAB-474C-9466-5EACAFA9B64A}.Debug|x86.ActiveCfg = Debug|Any CPU
+               {F4C226B3-0DAB-474C-9466-5EACAFA9B64A}.Release|Any CPU.ActiveCfg = Release|Any CPU
+               {F4C226B3-0DAB-474C-9466-5EACAFA9B64A}.Release|Any CPU.Build.0 = Release|Any CPU
+               {F4C226B3-0DAB-474C-9466-5EACAFA9B64A}.Release|ARM.ActiveCfg = Release|Any CPU
+               {F4C226B3-0DAB-474C-9466-5EACAFA9B64A}.Release|Mixed Platforms.ActiveCfg = Release|Any CPU
+               {F4C226B3-0DAB-474C-9466-5EACAFA9B64A}.Release|Mixed Platforms.Build.0 = Release|Any CPU
+               {F4C226B3-0DAB-474C-9466-5EACAFA9B64A}.Release|x64.ActiveCfg = Release|Any CPU
+               {F4C226B3-0DAB-474C-9466-5EACAFA9B64A}.Release|x86.ActiveCfg = Release|Any CPU
+               {08A91765-2C9D-4D2B-B56D-FAE62AB204CC}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
+               {08A91765-2C9D-4D2B-B56D-FAE62AB204CC}.Debug|Any CPU.Build.0 = Debug|Any CPU
+               {08A91765-2C9D-4D2B-B56D-FAE62AB204CC}.Debug|ARM.ActiveCfg = Debug|Any CPU
+               {08A91765-2C9D-4D2B-B56D-FAE62AB204CC}.Debug|Mixed Platforms.ActiveCfg = Debug|Any CPU
+               {08A91765-2C9D-4D2B-B56D-FAE62AB204CC}.Debug|Mixed Platforms.Build.0 = Debug|Any CPU
+               {08A91765-2C9D-4D2B-B56D-FAE62AB204CC}.Debug|x64.ActiveCfg = Debug|Any CPU
+               {08A91765-2C9D-4D2B-B56D-FAE62AB204CC}.Debug|x86.ActiveCfg = Debug|Any CPU
+               {08A91765-2C9D-4D2B-B56D-FAE62AB204CC}.Release|Any CPU.ActiveCfg = Release|Any CPU
+               {08A91765-2C9D-4D2B-B56D-FAE62AB204CC}.Release|Any CPU.Build.0 = Release|Any CPU
+               {08A91765-2C9D-4D2B-B56D-FAE62AB204CC}.Release|ARM.ActiveCfg = Release|Any CPU
+               {08A91765-2C9D-4D2B-B56D-FAE62AB204CC}.Release|Mixed Platforms.ActiveCfg = Release|Any CPU
+               {08A91765-2C9D-4D2B-B56D-FAE62AB204CC}.Release|Mixed Platforms.Build.0 = Release|Any CPU
+               {08A91765-2C9D-4D2B-B56D-FAE62AB204CC}.Release|x64.ActiveCfg = Release|Any CPU
+               {08A91765-2C9D-4D2B-B56D-FAE62AB204CC}.Release|x86.ActiveCfg = Release|Any CPU
+               {FF600107-3DEB-404F-8A37-F63473BDFCB8}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
+               {FF600107-3DEB-404F-8A37-F63473BDFCB8}.Debug|Any CPU.Build.0 = Debug|Any CPU
+               {FF600107-3DEB-404F-8A37-F63473BDFCB8}.Debug|ARM.ActiveCfg = Debug|Any CPU
+               {FF600107-3DEB-404F-8A37-F63473BDFCB8}.Debug|Mixed Platforms.ActiveCfg = Debug|Any CPU
+               {FF600107-3DEB-404F-8A37-F63473BDFCB8}.Debug|Mixed Platforms.Build.0 = Debug|Any CPU
+               {FF600107-3DEB-404F-8A37-F63473BDFCB8}.Debug|x64.ActiveCfg = Debug|Any CPU
+               {FF600107-3DEB-404F-8A37-F63473BDFCB8}.Debug|x86.ActiveCfg = Debug|Any CPU
+               {FF600107-3DEB-404F-8A37-F63473BDFCB8}.Release|Any CPU.ActiveCfg = Release|Any CPU
+               {FF600107-3DEB-404F-8A37-F63473BDFCB8}.Release|Any CPU.Build.0 = Release|Any CPU
+               {FF600107-3DEB-404F-8A37-F63473BDFCB8}.Release|ARM.ActiveCfg = Release|Any CPU
+               {FF600107-3DEB-404F-8A37-F63473BDFCB8}.Release|Mixed Platforms.ActiveCfg = Release|Any CPU
+               {FF600107-3DEB-404F-8A37-F63473BDFCB8}.Release|Mixed Platforms.Build.0 = Release|Any CPU
+               {FF600107-3DEB-404F-8A37-F63473BDFCB8}.Release|x64.ActiveCfg = Release|Any CPU
+               {FF600107-3DEB-404F-8A37-F63473BDFCB8}.Release|x86.ActiveCfg = Release|Any CPU
+       EndGlobalSection
+       GlobalSection(SolutionProperties) = preSolution
+               HideSolutionNode = FALSE
+       EndGlobalSection
+       GlobalSection(NestedProjects) = preSolution
+               {831970F4-9390-4214-848B-70E6250443DC} = {B630CA82-A785-49CA-8FA0-3D3AF4D6626A}
+               {FACB89E5-53A5-4748-9F5B-E0714EBB37B2} = {B630CA82-A785-49CA-8FA0-3D3AF4D6626A}
+               {4BB6F831-E215-488E-8ED8-F73C98C4B23F} = {B630CA82-A785-49CA-8FA0-3D3AF4D6626A}
+               {9B8816E0-026F-4255-9EA9-9997E33AE377} = {B630CA82-A785-49CA-8FA0-3D3AF4D6626A}
+               {11B45D63-8D63-4527-A537-41F6E8B4F9C0} = {831970F4-9390-4214-848B-70E6250443DC}
+               {6B677A5B-BF20-48C2-8435-5594BB3BC65F} = {831970F4-9390-4214-848B-70E6250443DC}
+               {F97B3093-EBDD-46C9-890E-0501922B9168} = {831970F4-9390-4214-848B-70E6250443DC}
+               {2F190086-3322-4407-A052-845E0DA24392} = {831970F4-9390-4214-848B-70E6250443DC}
+               {B86739B8-5DE9-406F-9418-0751BF7C166F} = {831970F4-9390-4214-848B-70E6250443DC}
+               {4238CB37-AD71-4E7B-84DB-C97DBBD94082} = {02741A76-6D1D-424B-9C04-8CC7B4033571}
+               {F18CD317-7774-4AFF-8866-E5B42BF71D1E} = {02741A76-6D1D-424B-9C04-8CC7B4033571}
+               {138BFD13-0ED1-49F5-B902-78770CB3D66B} = {B23E6DC9-4786-4BC0-BA8D-74AC6F961FC0}
+               {44DC1E63-C7D0-4068-9FAE-1F18A4CEA918} = {B23E6DC9-4786-4BC0-BA8D-74AC6F961FC0}
+               {BBAECBB8-149A-42EE-A4F4-6207D7954F8B} = {B23E6DC9-4786-4BC0-BA8D-74AC6F961FC0}
+               {BD75B688-D4A3-405F-BC08-E371993A6273} = {8619D594-5980-47B0-BB8D-1C15AC8F2357}
+               {15B1DC32-92C8-4301-A16D-9C47EE8356A2} = {8619D594-5980-47B0-BB8D-1C15AC8F2357}
+               {564E1DBA-3B0C-441D-9ACA-73B0A54D07AB} = {8619D594-5980-47B0-BB8D-1C15AC8F2357}
+               {BB639CDB-36F9-4DCB-A075-B713CC5A9A3F} = {8619D594-5980-47B0-BB8D-1C15AC8F2357}
+               {5C307156-E173-425B-8FC7-4B5CB63C7980} = {8619D594-5980-47B0-BB8D-1C15AC8F2357}
+               {66F2A02F-EF7B-4EBF-AD1B-6506BF7BD983} = {8619D594-5980-47B0-BB8D-1C15AC8F2357}
+               {ECAEB12F-7177-41FF-98D4-2EA7F5F110F0} = {8619D594-5980-47B0-BB8D-1C15AC8F2357}
+               {47BDB77E-C1AD-4784-ACA7-FC2D70C3A2BC} = {61666B87-CAC9-4F22-BD25-E0C6568EA1D5}
+               {F4C226B3-0DAB-474C-9466-5EACAFA9B64A} = {61666B87-CAC9-4F22-BD25-E0C6568EA1D5}
+       EndGlobalSection
+EndGlobal
diff --git a/oxyplot/OxyPlot/Annotations/Annotation.cs b/oxyplot/OxyPlot/Annotations/Annotation.cs
new file mode 100644
index 0000000..24d10e0
--- /dev/null
+++ b/oxyplot/OxyPlot/Annotations/Annotation.cs
@@ -0,0 +1,181 @@
+// 
--------------------------------------------------------------------------------------------------------------------
+// <copyright file="Annotation.cs" company="OxyPlot">
+//   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.
+// </copyright>
+// <summary>
+//   Annotation base class.
+// </summary>
+// 
--------------------------------------------------------------------------------------------------------------------
+namespace OxyPlot.Annotations
+{
+    using System;
+    using System.Globalization;
+
+    using OxyPlot.Axes;
+
+    /// <summary>
+    /// Provides an abstract base class for annotations.
+    /// </summary>
+    public abstract class Annotation : UIPlotElement
+    {
+        /// <summary>
+        /// Gets the actual culture.
+        /// </summary>
+        /// <remarks>
+        /// The culture is defined in the parent PlotModel.
+        /// </remarks>
+        public CultureInfo ActualCulture
+        {
+            get
+            {
+                return this.PlotModel != null ? this.PlotModel.ActualCulture : CultureInfo.CurrentCulture;
+            }
+        }
+
+        /// <summary>
+        /// Gets or sets the layer.
+        /// </summary>
+        public AnnotationLayer Layer { get; set; }
+
+        /// <summary>
+        /// Gets or sets the X axis.
+        /// </summary>
+        /// <value>The X axis.</value>
+        public Axis XAxis { get; set; }
+
+        /// <summary>
+        /// Gets or sets the X axis key.
+        /// </summary>
+        /// <value>The X axis key.</value>
+        public string XAxisKey { get; set; }
+
+        /// <summary>
+        /// Gets or sets the Y axis.
+        /// </summary>
+        /// <value>The Y axis.</value>
+        public Axis YAxis { get; set; }
+
+        /// <summary>
+        /// Gets or sets the Y axis key.
+        /// </summary>
+        /// <value>The Y axis key.</value>
+        public string YAxisKey { get; set; }
+
+        /// <summary>
+        /// Ensures that the annotation axes are set.
+        /// </summary>
+        public void EnsureAxes()
+        {
+            this.XAxis = this.PlotModel.GetAxisOrDefault(this.XAxisKey, this.PlotModel.DefaultXAxis);
+            this.YAxis = this.PlotModel.GetAxisOrDefault(this.YAxisKey, this.PlotModel.DefaultYAxis);
+        }
+
+        /// <summary>
+        /// Renders the annotation on the specified context.
+        /// </summary>
+        /// <param name="rc">
+        /// The render context.
+        /// </param>
+        /// <param name="model">
+        /// The model.
+        /// </param>
+        public virtual void Render(IRenderContext rc, PlotModel model)
+        {
+        }
+
+        /// <summary>
+        /// Tests if the plot element is hit by the specified point.
+        /// </summary>
+        /// <param name="point">The point.</param>
+        /// <param name="tolerance">The tolerance.</param>
+        /// <returns>
+        /// A hit test result.
+        /// </returns>
+        protected internal override HitTestResult HitTest(ScreenPoint point, double tolerance)
+        {
+            return null;
+        }
+
+        /// <summary>
+        /// Transforms the specified coordinates to a screen point.
+        /// </summary>
+        /// <param name="x">
+        /// The x coordinate.
+        /// </param>
+        /// <param name="y">
+        /// The y coordinate.
+        /// </param>
+        /// <returns>
+        /// A screen point.
+        /// </returns>
+        public ScreenPoint Transform(double x, double y)
+        {
+            return this.XAxis.Transform(x, y, this.YAxis);
+        }
+
+        /// <summary>
+        /// Transforms the specified data point to a screen point.
+        /// </summary>
+        /// <param name="p">
+        /// The point.
+        /// </param>
+        /// <returns>
+        /// A screen point.
+        /// </returns>
+        public ScreenPoint Transform(IDataPoint p)
+        {
+            return this.XAxis.Transform(p.X, p.Y, this.YAxis);
+        }
+
+        /// <summary>
+        /// Transforms the specified screen position to a data point.
+        /// </summary>
+        /// <param name="position">
+        /// The position.
+        /// </param>
+        /// <returns>
+        /// A data point
+        /// </returns>
+        public DataPoint InverseTransform(ScreenPoint position)
+        {
+            return Axis.InverseTransform(position, this.XAxis, this.YAxis);
+        }
+
+        /// <summary>
+        /// Gets the clipping rectangle.
+        /// </summary>
+        /// <returns>
+        /// The clipping rectangle.
+        /// </returns>
+        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 --git a/oxyplot/OxyPlot/Annotations/AnnotationLayer.cs b/oxyplot/OxyPlot/Annotations/AnnotationLayer.cs
new file mode 100644
index 0000000..a069863
--- /dev/null
+++ b/oxyplot/OxyPlot/Annotations/AnnotationLayer.cs
@@ -0,0 +1,52 @@
+// 
--------------------------------------------------------------------------------------------------------------------
+// <copyright file="AnnotationLayer.cs" company="OxyPlot">
+//   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.
+// </copyright>
+// <summary>
+//   The annotation layer.
+// </summary>
+// 
--------------------------------------------------------------------------------------------------------------------
+namespace OxyPlot.Annotations
+{
+    /// <summary>
+    /// Specifies the layer for an <see cref="Annotation"/>.
+    /// </summary>
+    public enum AnnotationLayer
+    {
+        /// <summary>
+        /// Render the annotation below the gridlines of the axes.
+        /// </summary>
+        BelowAxes,
+
+        /// <summary>
+        /// Render the annotation below the series.
+        /// </summary>
+        BelowSeries,
+
+        /// <summary>
+        /// Render the annotation above the series.
+        /// </summary>
+        AboveSeries
+    }
+}
\ No newline at end of file
diff --git a/oxyplot/OxyPlot/Annotations/ArrowAnnotation.cs b/oxyplot/OxyPlot/Annotations/ArrowAnnotation.cs
new file mode 100644
index 0000000..d2f690b
--- /dev/null
+++ b/oxyplot/OxyPlot/Annotations/ArrowAnnotation.cs
@@ -0,0 +1,228 @@
+// 
--------------------------------------------------------------------------------------------------------------------
+// <copyright file="ArrowAnnotation.cs" company="OxyPlot">
+//   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.
+// </copyright>
+// <summary>
+//   Represents an arrow annotation.
+// </summary>
+// 
--------------------------------------------------------------------------------------------------------------------
+namespace OxyPlot.Annotations
+{
+    /// <summary>
+    /// Represents an arrow annotation.
+    /// </summary>
+    public class ArrowAnnotation : TextualAnnotation
+    {
+        /// <summary>
+        /// The end point in screen coordinates.
+        /// </summary>
+        private ScreenPoint screenEndPoint;
+
+        /// <summary>
+        /// The start point in screen coordinates.
+        /// </summary>
+        private ScreenPoint screenStartPoint;
+
+        /// <summary>
+        /// Initializes a new instance of the <see cref="ArrowAnnotation"/> class.
+        /// </summary>
+        public ArrowAnnotation()
+        {
+            this.HeadLength = 10;
+            this.HeadWidth = 3;
+            this.Color = OxyColors.Blue;
+            this.StrokeThickness = 2;
+            this.LineStyle = LineStyle.Solid;
+            this.LineJoin = OxyPenLineJoin.Miter;
+        }
+
+        /// <summary>
+        /// Gets or sets the arrow direction.
+        /// </summary>
+        /// <remarks>
+        /// Setting this property overrides the StartPoint property.
+        /// </remarks>
+        public ScreenVector ArrowDirection { get; set; }
+
+        /// <summary>
+        /// Gets or sets the color of the arrow.
+        /// </summary>
+        public OxyColor Color { get; set; }
+
+        /// <summary>
+        /// Gets or sets the end point.
+        /// </summary>
+        public DataPoint EndPoint { get; set; }
+
+        /// <summary>
+        /// Gets or sets the length of the head (relative to the stroke thickness) (the default value is 10).
+        /// </summary>
+        /// <value> The length of the head. </value>
+        public double HeadLength { get; set; }
+
+        /// <summary>
+        /// Gets or sets the width of the head (relative to the stroke thickness) (the default value is 3).
+        /// </summary>
+        /// <value> The width of the head. </value>
+        public double HeadWidth { get; set; }
+
+        /// <summary>
+        /// Gets or sets the line join type.
+        /// </summary>
+        /// <value> The line join type. </value>
+        public OxyPenLineJoin LineJoin { get; set; }
+
+        /// <summary>
+        /// Gets or sets the line style.
+        /// </summary>
+        /// <value> The line style. </value>
+        public LineStyle LineStyle { get; set; }
+
+        /// <summary>
+        /// Gets or sets the start point.
+        /// </summary>
+        /// <remarks>
+        /// This property is overridden by the ArrowDirection property, if set.
+        /// </remarks>
+        public DataPoint StartPoint { get; set; }
+
+        /// <summary>
+        /// Gets or sets the stroke thickness (the default value is 2).
+        /// </summary>
+        /// <value> The stroke thickness. </value>
+        public double StrokeThickness { get; set; }
+
+        /// <summary>
+        /// Gets or sets the 'veeness' of the arrow head (relative to thickness) (the default value is 0).
+        /// </summary>
+        /// <value> The 'veeness'. </value>
+        public double Veeness { get; set; }
+
+        /// <summary>
+        /// Renders the arrow annotation.
+        /// </summary>
+        /// <param name="rc">
+        /// The render context.
+        /// </param>
+        /// <param name="model">
+        /// The plot model.
+        /// </param>
+        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);
+            }
+        }
+
+        /// <summary>
+        /// Tests if the plot element is hit by the specified point.
+        /// </summary>
+        /// <param name="point">
+        /// The point.
+        /// </param>
+        /// <param name="tolerance">
+        /// The tolerance.
+        /// </param>
+        /// <returns>
+        /// A hit test result.
+        /// </returns>
+        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 --git a/oxyplot/OxyPlot/Annotations/EllipseAnnotation.cs 
b/oxyplot/OxyPlot/Annotations/EllipseAnnotation.cs
new file mode 100644
index 0000000..964a20c
--- /dev/null
+++ b/oxyplot/OxyPlot/Annotations/EllipseAnnotation.cs
@@ -0,0 +1,152 @@
+// 
--------------------------------------------------------------------------------------------------------------------
+// <copyright file="RectangleAnnotation.cs" company="OxyPlot">
+//   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.
+// </copyright>
+// <summary>
+//   Represents a rectangle annotation.
+// </summary>
+// 
--------------------------------------------------------------------------------------------------------------------
+namespace OxyPlot.Annotations
+{
+    /// <summary>
+    /// Represents an ellipse annotation.
+    /// </summary>
+    public class EllipseAnnotation : TextualAnnotation
+    {
+        /// <summary>
+        /// The rectangle transformed to screen coordinates.
+        /// </summary>
+        private OxyRect screenRectangle;
+
+        /// <summary>
+        /// Initializes a new instance of the <see cref="EllipseAnnotation"/> class.
+        /// </summary>
+        public EllipseAnnotation()
+        {
+            this.Stroke = OxyColors.Black;
+            this.Fill = OxyColors.LightBlue;
+        }
+
+        /// <summary>
+        /// Gets or sets the fill color.
+        /// </summary>
+        /// <value> The fill. </value>
+        public OxyColor Fill { get; set; }
+
+        /// <summary>
+        /// Gets or sets the stroke color.
+        /// </summary>
+        public OxyColor Stroke { get; set; }
+
+        /// <summary>
+        /// Gets or sets the stroke thickness.
+        /// </summary>
+        public double StrokeThickness { get; set; }
+
+        /// <summary>
+        /// Gets or sets the x-coordinate of the center.
+        /// </summary>
+        public double X { get; set; }
+
+        /// <summary>
+        /// Gets or sets the y-coordinate of the center.
+        /// </summary>
+        public double Y { get; set; }
+
+        /// <summary>
+        /// Gets or sets the width of the ellipse.
+        /// </summary>
+        public double Width { get; set; }
+
+        /// <summary>
+        /// Gets or sets the height of the ellipse.
+        /// </summary>
+        public double Height { get; set; }
+
+        /// <summary>
+        /// Gets or sets the text rotation (degrees).
+        /// </summary>
+        /// <value>The text rotation in degrees.</value>
+        public double TextRotation { get; set; }
+
+        /// <summary>
+        /// Renders the polygon annotation.
+        /// </summary>
+        /// <param name="rc">
+        /// The render context.
+        /// </param>
+        /// <param name="model">
+        /// The plot model.
+        /// </param>
+        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);
+            }
+        }
+
+        /// <summary>
+        /// Tests if the plot element is hit by the specified point.
+        /// </summary>
+        /// <param name="point">
+        /// The point.
+        /// </param>
+        /// <param name="tolerance">
+        /// The tolerance.
+        /// </param>
+        /// <returns>
+        /// A hit test result.
+        /// </returns>
+        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 --git a/oxyplot/OxyPlot/Annotations/ImageAnnotation.cs b/oxyplot/OxyPlot/Annotations/ImageAnnotation.cs
new file mode 100644
index 0000000..9369cb4
--- /dev/null
+++ b/oxyplot/OxyPlot/Annotations/ImageAnnotation.cs
@@ -0,0 +1,451 @@
+// 
--------------------------------------------------------------------------------------------------------------------
+// <copyright file="ImageAnnotation.cs" company="OxyPlot">
+//   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.
+// </copyright>
+// <summary>
+//   Represents a text object annotation.
+// </summary>
+// 
--------------------------------------------------------------------------------------------------------------------
+namespace OxyPlot.Annotations
+{
+    /// <summary>
+    /// Represents a text annotation.
+    /// </summary>
+    public class ImageAnnotation : Annotation
+    {
+        /// <summary>
+        /// The actual bounds of the rendered image.
+        /// </summary>
+        private OxyRect actualBounds;
+
+        /// <summary>
+        /// Initializes a new instance of the <see cref="ImageAnnotation" /> class.
+        /// </summary>
+        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;
+        }
+
+        /// <summary>
+        /// Initializes a new instance of the <see cref="ImageAnnotation"/> class.
+        /// </summary>
+        /// <param name="image">
+        /// The image.
+        /// </param>
+        /// <param name="position">
+        /// The position in screen coordinates.
+        /// </param>
+        /// <param name="horizontalAlignment">
+        /// The horizontal alignment.
+        /// </param>
+        /// <param name="verticalAlignment">
+        /// The vertical alignment.
+        /// </param>
+        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;
+        }
+
+        /// <summary>
+        /// Initializes a new instance of the <see cref="ImageAnnotation"/> class.
+        /// </summary>
+        /// <param name="image">
+        /// The image.
+        /// </param>
+        /// <param name="position">
+        /// The position in data coordinates.
+        /// </param>
+        /// <param name="horizontalAlignment">
+        /// The horizontal alignment.
+        /// </param>
+        /// <param name="verticalAlignment">
+        /// The vertical alignment.
+        /// </param>
+        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;
+        }
+
+        /// <summary>
+        /// Initializes a new instance of the <see cref="ImageAnnotation"/> class.
+        /// </summary>
+        /// <param name="image">
+        /// The image.
+        /// </param>
+        /// <param name="relativeX">
+        /// The x-coordinate relative to the plot area (0-1).
+        /// </param>
+        /// <param name="relativeY">
+        /// The y-coordinate relative to the plot area (0-1).
+        /// </param>
+        /// <param name="horizontalAlignment">
+        /// The horizontal alignment.
+        /// </param>
+        /// <param name="verticalAlignment">
+        /// The vertical alignment.
+        /// </param>
+        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;
+        }
+
+        /// <summary>
+        /// Gets or sets the image source.
+        /// </summary>
+        /// <value>
+        /// The image source.
+        /// </value>
+        public OxyImage ImageSource { get; set; }
+
+        /// <summary>
+        /// Gets or sets the horizontal alignment.
+        /// </summary>
+        /// <value> The horizontal alignment. </value>
+        public HorizontalAlignment HorizontalAlignment { get; set; }
+
+        /// <summary>
+        /// Gets or sets the X position of the image.
+        /// </summary>
+        /// <value>
+        /// The X.
+        /// </value>
+        public PlotLength X { get; set; }
+
+        /// <summary>
+        /// Gets or sets the Y position of the image.
+        /// </summary>
+        /// <value>
+        /// The Y.
+        /// </value>
+        public PlotLength Y { get; set; }
+
+        /// <summary>
+        /// Gets or sets the X offset.
+        /// </summary>
+        /// <value>
+        /// The offset X.
+        /// </value>
+        public PlotLength OffsetX { get; set; }
+
+        /// <summary>
+        /// Gets or sets the Y offset.
+        /// </summary>
+        /// <value>
+        /// The offset Y.
+        /// </value>
+        public PlotLength OffsetY { get; set; }
+
+        /// <summary>
+        /// Gets or sets the width.
+        /// </summary>
+        /// <value>
+        /// The width.
+        /// </value>
+        public PlotLength Width { get; set; }
+
+        /// <summary>
+        /// Gets or sets the height.
+        /// </summary>
+        /// <value>
+        /// The height.
+        /// </value>
+        public PlotLength Height { get; set; }
+
+        /// <summary>
+        /// Gets or sets the opacity (0-1).
+        /// </summary>
+        /// <value>
+        /// The opacity value.
+        /// </value>
+        public double Opacity { get; set; }
+
+        /// <summary>
+        /// Gets or sets a value indicating whether to apply smooth interpolation to the image.
+        /// </summary>
+        /// <value>
+        ///   <c>true</c> if the image should be interpolated (using a high-quality bi-cubic interpolation); 
<c>false</c> if the nearest neighbor should be used.
+        /// </value>
+        public bool Interpolate { get; set; }
+
+        /// <summary>
+        /// Gets or sets the vertical alignment.
+        /// </summary>
+        /// <value> The vertical alignment. </value>
+        public VerticalAlignment VerticalAlignment { get; set; }
+
+        /// <summary>
+        /// Renders the image annotation.
+        /// </summary>
+        /// <param name="rc">
+        /// The render context.
+        /// </param>
+        /// <param name="model">
+        /// The plot model.
+        /// </param>
+        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);
+            }
+        }
+
+        /// <summary>
+        /// Tests if the plot element is hit by the specified point.
+        /// </summary>
+        /// <param name="point">
+        /// The point.
+        /// </param>
+        /// <param name="tolerance">
+        /// The tolerance.
+        /// </param>
+        /// <returns>
+        /// A hit test result.
+        /// </returns>
+        protected internal override HitTestResult HitTest(ScreenPoint point, double tolerance)
+        {
+            if (this.actualBounds.Contains(point))
+            {
+                return new HitTestResult(point);
+            }
+
+            return null;
+        }
+
+        /// <summary>
+        /// Gets the point.
+        /// </summary>
+        /// <param name="x">
+        /// The x.
+        /// </param>
+        /// <param name="y">
+        /// The y.
+        /// </param>
+        /// <param name="rc">
+        /// The render context.
+        /// </param>
+        /// <param name="model">
+        /// The model.
+        /// </param>
+        /// <returns>
+        /// The point in screen coordinates.
+        /// </returns>
+        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);
+        }
+
+        /// <summary>
+        /// Gets the vector.
+        /// </summary>
+        /// <param name="x">
+        /// The x component.
+        /// </param>
+        /// <param name="y">
+        /// The y component.
+        /// </param>
+        /// <param name="rc">
+        /// The render context.
+        /// </param>
+        /// <param name="model">
+        /// The model.
+        /// </param>
+        /// <returns>
+        /// The vector in screen coordinates.
+        /// </returns>
+        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 --git a/oxyplot/OxyPlot/Annotations/LineAnnotation.cs b/oxyplot/OxyPlot/Annotations/LineAnnotation.cs
new file mode 100644
index 0000000..8eb68bb
--- /dev/null
+++ b/oxyplot/OxyPlot/Annotations/LineAnnotation.cs
@@ -0,0 +1,528 @@
+// 
--------------------------------------------------------------------------------------------------------------------
+// <copyright file="LineAnnotation.cs" company="OxyPlot">
+//   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.
+// </copyright>
+// <summary>
+//   Specify the orientation of the annotation text
+// </summary>
+// 
--------------------------------------------------------------------------------------------------------------------
+namespace OxyPlot.Annotations
+{
+    using System;
+    using System.Collections.Generic;
+    using System.Linq;
+
+    using OxyPlot.Axes;
+
+    /// <summary>
+    /// Specifes the orientation of the annotation text
+    /// </summary>
+    public enum AnnotationTextOrientation
+    {
+        /// <summary>
+        /// Horizontal text.
+        /// </summary>
+        Horizontal,
+
+        /// <summary>
+        /// Vertical text.
+        /// </summary>
+        Vertical,
+
+        /// <summary>
+        /// Oriented along the line.
+        /// </summary>
+        AlongLine
+    }
+
+    /// <summary>
+    /// Represents a line annotation.
+    /// </summary>
+    public class LineAnnotation : TextualAnnotation
+    {
+        /// <summary>
+        /// The points of the line, transformed to screen coordinates.
+        /// </summary>
+        private IList<ScreenPoint> screenPoints;
+
+        /// <summary>
+        /// Initializes a new instance of the <see cref = "LineAnnotation" /> class.
+        /// </summary>
+        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;
+        }
+
+        /// <summary>
+        /// Gets or sets the color of the line.
+        /// </summary>
+        public OxyColor Color { get; set; }
+
+        /// <summary>
+        /// Gets or sets the y=f(x) equation when Type is Equation.
+        /// </summary>
+        public Func<double, double> Equation { get; set; }
+
+        /// <summary>
+        /// Gets or sets the y-intercept when Type is LinearEquation.
+        /// </summary>
+        /// <value>The intercept value.</value>
+        /// <remarks>
+        /// Linear equation y-intercept (the b in y=mx+b).
+        /// http://en.wikipedia.org/wiki/Linear_equation
+        /// </remarks>
+        public double Intercept { get; set; }
+
+        /// <summary>
+        /// Gets or sets the line join.
+        /// </summary>
+        /// <value>The line join.</value>
+        public OxyPenLineJoin LineJoin { get; set; }
+
+        /// <summary>
+        /// Gets or sets the line style.
+        /// </summary>
+        /// <value>The line style.</value>
+        public LineStyle LineStyle { get; set; }
+
+        /// <summary>
+        /// Gets or sets the maximum X coordinate for the line.
+        /// </summary>
+        public double MaximumX { get; set; }
+
+        /// <summary>
+        /// Gets or sets the maximum Y coordinate for the line.
+        /// </summary>
+        public double MaximumY { get; set; }
+
+        /// <summary>
+        /// Gets or sets the minimum X coordinate for the line.
+        /// </summary>
+        public double MinimumX { get; set; }
+
+        /// <summary>
+        /// Gets or sets the minimum Y coordinate for the line.
+        /// </summary>
+        public double MinimumY { get; set; }
+
+        /// <summary>
+        /// Gets or sets the slope when Type is LinearEquation.
+        /// </summary>
+        /// <value>The slope value.</value>
+        /// <remarks>
+        /// Linear equation slope (the m in y=mx+b)
+        /// http://en.wikipedia.org/wiki/Linear_equation
+        /// </remarks>
+        public double Slope { get; set; }
+
+        /// <summary>
+        /// Gets or sets the stroke thickness.
+        /// </summary>
+        /// <value>The stroke thickness.</value>
+        public double StrokeThickness { get; set; }
+
+        /// <summary>
+        /// Gets or sets the text horizontal alignment.
+        /// </summary>
+        /// <value>The text horizontal alignment.</value>
+        public HorizontalAlignment TextHorizontalAlignment { get; set; }
+
+        /// <summary>
+        /// Gets or sets the text margin (along the line).
+        /// </summary>
+        /// <value>The text margin.</value>
+        public double TextMargin { get; set; }
+
+        /// <summary>
+        /// Gets or sets the text padding (in the direction of the text).
+        /// </summary>
+        /// <value>The text padding.</value>
+        public double TextPadding { get; set; }
+
+        /// <summary>
+        /// Gets or sets the text orientation.
+        /// </summary>
+        /// <value>The text orientation.</value>
+        public AnnotationTextOrientation TextOrientation { get; set; }
+
+        /// <summary>
+        /// Gets or sets the text position fraction.
+        /// </summary>
+        /// <value>The text position in the interval [0,1].</value>
+        /// <remarks>
+        /// 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
+        /// </remarks>
+        public double TextPosition { get; set; }
+
+        /// <summary>
+        /// Gets or sets the vertical alignment of text (above or below the line).
+        /// </summary>
+        public VerticalAlignment TextVerticalAlignment { get; set; }
+
+        /// <summary>
+        /// Gets or sets the type of line equation.
+        /// </summary>
+        public LineAnnotationType Type { get; set; }
+
+        /// <summary>
+        /// Gets or sets the X position for vertical lines (only for Type==Vertical).
+        /// </summary>
+        public double X { get; set; }
+
+        /// <summary>
+        /// Gets or sets the Y position for horizontal lines (only for Type==Horizontal)
+        /// </summary>
+        public double Y { get; set; }
+
+        /// <summary>
+        /// Gets or sets a value indicating whether to clip the annotation line by the X axis range.
+        /// </summary>
+        /// <value><c>true</c> if clipping by the X axis is enabled; otherwise, <c>false</c>.</value>
+        public bool ClipByXAxis { get; set; }
+
+        /// <summary>
+        /// Gets or sets a value indicating whether to clip the annotation line by the Y axis range.
+        /// </summary>
+        /// <value><c>true</c> if clipping by the Y axis is enabled; otherwise, <c>false</c>.</value>
+        public bool ClipByYAxis { get; set; }
+
+        /// <summary>
+        /// Renders the line annotation.
+        /// </summary>
+        /// <param name="rc">
+        /// The render context.
+        /// </param>
+        /// <param name="model">
+        /// The plot model.
+        /// </param>
+        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<double, double> fx = null;
+
+            // x=f(y)
+            Func<double, double> 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<DataPoint>();
+
+            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<ScreenPoint> 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);
+                }
+            }
+        }
+
+        /// <summary>
+        /// Tests if the plot element is hit by the specified point.
+        /// </summary>
+        /// <param name="point">The point.</param>
+        /// <param name="tolerance">The tolerance.</param>
+        /// <returns>
+        /// A hit test result.
+        /// </returns>
+        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;
+        }
+
+        /// <summary>
+        /// Gets the point on a curve at the specified relative distance along the curve.
+        /// </summary>
+        /// <param name="pts">
+        /// The curve points.
+        /// </param>
+        /// <param name="p">
+        /// The relative distance along the curve.
+        /// </param>
+        /// <param name="margin">
+        /// The margins.
+        /// </param>
+        /// <param name="position">
+        /// The position.
+        /// </param>
+        /// <param name="angle">
+        /// The angle.
+        /// </param>
+        /// <returns>
+        /// True if a position was found.
+        /// </returns>
+        private static bool GetPointAtRelativeDistance(
+            IList<ScreenPoint> 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 --git a/oxyplot/OxyPlot/Annotations/LineAnnotationType.cs 
b/oxyplot/OxyPlot/Annotations/LineAnnotationType.cs
new file mode 100644
index 0000000..f73b7a9
--- /dev/null
+++ b/oxyplot/OxyPlot/Annotations/LineAnnotationType.cs
@@ -0,0 +1,62 @@
+// 
--------------------------------------------------------------------------------------------------------------------
+// <copyright file="LineAnnotationType.cs" company="OxyPlot">
+//   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.
+// </copyright>
+// <summary>
+//   The line annotation type.
+// </summary>
+// 
--------------------------------------------------------------------------------------------------------------------
+namespace OxyPlot.Annotations
+{
+    /// <summary>
+    /// Specifies the definition of the line in a <see cref="LineAnnotation"/>.
+    /// </summary>
+    public enum LineAnnotationType
+    {
+        /// <summary>
+        /// Horizontal line given by the Y property
+        /// </summary>
+        Horizontal,
+
+        /// <summary>
+        /// Vertical line given by the X property
+        /// </summary>
+        Vertical,
+
+        /// <summary>
+        /// Linear equation y=mx+b given by the Slope and Intercept properties
+        /// </summary>
+        LinearEquation,
+
+        /// <summary>
+        /// Curve equation x=f(y) given by the Equation property
+        /// </summary>
+        EquationX,
+
+        /// <summary>
+        /// Curve equation y=f(x) given by the Equation property
+        /// </summary>
+        EquationY
+    }
+}
\ No newline at end of file
diff --git a/oxyplot/OxyPlot/Annotations/PolygonAnnotation.cs 
b/oxyplot/OxyPlot/Annotations/PolygonAnnotation.cs
new file mode 100644
index 0000000..60aa125
--- /dev/null
+++ b/oxyplot/OxyPlot/Annotations/PolygonAnnotation.cs
@@ -0,0 +1,166 @@
+// 
--------------------------------------------------------------------------------------------------------------------
+// <copyright file="PolygonAnnotation.cs" company="OxyPlot">
+//   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.
+// </copyright>
+// <summary>
+//   Represents a polygon annotation.
+// </summary>
+// 
--------------------------------------------------------------------------------------------------------------------
+namespace OxyPlot.Annotations
+{
+    using System.Collections.Generic;
+    using System.Linq;
+
+    /// <summary>
+    /// Represents a polygon annotation.
+    /// </summary>
+    public class PolygonAnnotation : TextualAnnotation
+    {
+        /// <summary>
+        /// The polygon points transformed to screen coordinates.
+        /// </summary>
+        private IList<ScreenPoint> screenPoints;
+
+        /// <summary>
+        /// Initializes a new instance of the <see cref="PolygonAnnotation"/> class.
+        /// </summary>
+        public PolygonAnnotation()
+        {
+            this.Color = OxyColors.Blue;
+            this.Fill = OxyColors.LightBlue;
+            this.StrokeThickness = 1;
+            this.LineStyle = LineStyle.Solid;
+            this.LineJoin = OxyPenLineJoin.Miter;
+        }
+
+        /// <summary>
+        /// Gets or sets the color of the line.
+        /// </summary>
+        public OxyColor Color { get; set; }
+
+        /// <summary>
+        /// Gets or sets the fill color.
+        /// </summary>
+        /// <value> The fill. </value>
+        public OxyColor Fill { get; set; }
+
+        /// <summary>
+        /// Gets or sets the line join.
+        /// </summary>
+        /// <value> The line join. </value>
+        public OxyPenLineJoin LineJoin { get; set; }
+
+        /// <summary>
+        /// Gets or sets the line style.
+        /// </summary>
+        /// <value> The line style. </value>
+        public LineStyle LineStyle { get; set; }
+
+        /// <summary>
+        /// Gets or sets the points.
+        /// </summary>
+        /// <value> The points. </value>
+        public IList<DataPoint> Points { get; set; }
+
+        /// <summary>
+        /// Gets or sets the stroke thickness.
+        /// </summary>
+        /// <value> The stroke thickness. </value>
+        public double StrokeThickness { get; set; }
+
+        /// <summary>
+        /// Renders the polygon annotation.
+        /// </summary>
+        /// <param name="rc">
+        /// The render context.
+        /// </param>
+        /// <param name="model">
+        /// The plot model.
+        /// </param>
+        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);
+            }
+        }
+
+        /// <summary>
+        /// Tests if the plot element is hit by the specified point.
+        /// </summary>
+        /// <param name="point">
+        /// The point.
+        /// </param>
+        /// <param name="tolerance">
+        /// The tolerance.
+        /// </param>
+        /// <returns>
+        /// A hit test result.
+        /// </returns>
+        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 --git a/oxyplot/OxyPlot/Annotations/RectangleAnnotation.cs 
b/oxyplot/OxyPlot/Annotations/RectangleAnnotation.cs
new file mode 100644
index 0000000..45a6f6a
--- /dev/null
+++ b/oxyplot/OxyPlot/Annotations/RectangleAnnotation.cs
@@ -0,0 +1,174 @@
+// 
--------------------------------------------------------------------------------------------------------------------
+// <copyright file="RectangleAnnotation.cs" company="OxyPlot">
+//   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.
+// </copyright>
+// <summary>
+//   Represents a rectangle annotation.
+// </summary>
+// 
--------------------------------------------------------------------------------------------------------------------
+namespace OxyPlot.Annotations
+{
+    /// <summary>
+    /// Represents a rectangle annotation.
+    /// </summary>
+    public class RectangleAnnotation : TextualAnnotation
+    {
+        /// <summary>
+        /// The rectangle transformed to screen coordinates.
+        /// </summary>
+        private OxyRect screenRectangle;
+
+        /// <summary>
+        /// Initializes a new instance of the <see cref="RectangleAnnotation"/> class.
+        /// </summary>
+        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;
+        }
+
+        /// <summary>
+        /// Gets or sets the fill color.
+        /// </summary>
+        /// <value> The fill. </value>
+        public OxyColor Fill { get; set; }
+
+        /// <summary>
+        /// Gets or sets the stroke color.
+        /// </summary>
+        public OxyColor Stroke { get; set; }
+
+        /// <summary>
+        /// Gets or sets the stroke thickness.
+        /// </summary>
+        public double StrokeThickness { get; set; }
+
+        /// <summary>
+        /// Gets or sets the minimum X.
+        /// </summary>
+        /// <value>The minimum X.</value>
+        public double MinimumX { get; set; }
+
+        /// <summary>
+        /// Gets or sets the maximum X.
+        /// </summary>
+        /// <value>The maximum X.</value>
+        public double MaximumX { get; set; }
+
+        /// <summary>
+        /// Gets or sets the minimum Y.
+        /// </summary>
+        /// <value>The minimum Y.</value>
+        public double MinimumY { get; set; }
+
+        /// <summary>
+        /// Gets or sets the maximum Y.
+        /// </summary>
+        /// <value>The maximum Y.</value>
+        public double MaximumY { get; set; }
+
+        /// <summary>
+        /// Gets or sets the text rotation (degrees).
+        /// </summary>
+        /// <value>The text rotation in degrees.</value>
+        public double TextRotation { get; set; }
+
+        /// <summary>
+        /// Renders the polygon annotation.
+        /// </summary>
+        /// <param name="rc">
+        /// The render context.
+        /// </param>
+        /// <param name="model">
+        /// The plot model.
+        /// </param>
+        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);
+            }
+        }
+
+        /// <summary>
+        /// Tests if the plot element is hit by the specified point.
+        /// </summary>
+        /// <param name="point">
+        /// The point.
+        /// </param>
+        /// <param name="tolerance">
+        /// The tolerance.
+        /// </param>
+        /// <returns>
+        /// A hit test result.
+        /// </returns>
+        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 --git a/oxyplot/OxyPlot/Annotations/TextAnnotation.cs b/oxyplot/OxyPlot/Annotations/TextAnnotation.cs
new file mode 100644
index 0000000..1bbe044
--- /dev/null
+++ b/oxyplot/OxyPlot/Annotations/TextAnnotation.cs
@@ -0,0 +1,254 @@
+// 
--------------------------------------------------------------------------------------------------------------------
+// <copyright file="TextAnnotation.cs" company="OxyPlot">
+//   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.
+// </copyright>
+// <summary>
+//   Represents a text object annotation.
+// </summary>
+// 
--------------------------------------------------------------------------------------------------------------------
+namespace OxyPlot.Annotations
+{
+    using System;
+    using System.Collections.Generic;
+
+    /// <summary>
+    /// Represents a text annotation.
+    /// </summary>
+    public class TextAnnotation : TextualAnnotation
+    {
+        /// <summary>
+        /// The actual bounds of the text.
+        /// </summary>
+        private IList<ScreenPoint> actualBounds;
+
+        /// <summary>
+        /// Initializes a new instance of the <see cref="TextAnnotation" /> class.
+        /// </summary>
+        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);
+        }
+
+        /// <summary>
+        /// Gets or sets the fill color of the background rectangle.
+        /// </summary>
+        /// <value> The background. </value>
+        public OxyColor Background { get; set; }
+
+        /// <summary>
+        /// Gets or sets the horizontal alignment.
+        /// </summary>
+        /// <value> The horizontal alignment. </value>
+        public HorizontalAlignment HorizontalAlignment { get; set; }
+
+        /// <summary>
+        /// Gets or sets the position offset (screen coordinates).
+        /// </summary>
+        /// <value> The offset. </value>
+        public ScreenVector Offset { get; set; }
+
+        /// <summary>
+        /// Gets or sets the padding of the background rectangle.
+        /// </summary>
+        /// <value> The padding. </value>
+        public OxyThickness Padding { get; set; }
+
+        /// <summary>
+        /// Gets or sets the position of the text.
+        /// </summary>
+        public DataPoint Position { get; set; }
+
+        /// <summary>
+        /// Gets or sets the rotation angle (degrees).
+        /// </summary>
+        /// <value> The rotation. </value>
+        public double Rotation { get; set; }
+
+        /// <summary>
+        /// Gets or sets the stroke color of the background rectangle.
+        /// </summary>
+        /// <value> The stroke color. </value>
+        public OxyColor Stroke { get; set; }
+
+        /// <summary>
+        /// Gets or sets the stroke thickness of the background rectangle.
+        /// </summary>
+        /// <value> The stroke thickness. </value>
+        public double StrokeThickness { get; set; }
+
+        /// <summary>
+        /// Gets or sets the vertical alignment.
+        /// </summary>
+        /// <value> The vertical alignment. </value>
+        public VerticalAlignment VerticalAlignment { get; set; }
+
+        /// <summary>
+        /// Renders the text annotation.
+        /// </summary>
+        /// <param name="rc">
+        /// The render context.
+        /// </param>
+        /// <param name="model">
+        /// The plot model.
+        /// </param>
+        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);
+        }
+
+        /// <summary>
+        /// Tests if the plot element is hit by the specified point.
+        /// </summary>
+        /// <param name="point">
+        /// The point.
+        /// </param>
+        /// <param name="tolerance">
+        /// The tolerance.
+        /// </param>
+        /// <returns>
+        /// A hit test result.
+        /// </returns>
+        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;
+        }
+
+        /// <summary>
+        /// Gets the coordinates of the (rotated) background rectangle.
+        /// </summary>
+        /// <param name="position">
+        /// The position.
+        /// </param>
+        /// <param name="size">
+        /// The size.
+        /// </param>
+        /// <param name="padding">
+        /// The padding.
+        /// </param>
+        /// <param name="rotation">
+        /// The rotation.
+        /// </param>
+        /// <param name="horizontalAlignment">
+        /// The horizontal alignment.
+        /// </param>
+        /// <param name="verticalAlignment">
+        /// The vertical alignment.
+        /// </param>
+        /// <returns>
+        /// The background rectangle coordinates.
+        /// </returns>
+        private static IList<ScreenPoint> 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 --git a/oxyplot/OxyPlot/Annotations/TextualAnnotation.cs 
b/oxyplot/OxyPlot/Annotations/TextualAnnotation.cs
new file mode 100644
index 0000000..54e264b
--- /dev/null
+++ b/oxyplot/OxyPlot/Annotations/TextualAnnotation.cs
@@ -0,0 +1,46 @@
+// 
--------------------------------------------------------------------------------------------------------------------
+// <copyright file="TextualAnnotation.cs" company="OxyPlot">
+//   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.
+// </copyright>
+// <summary>
+//   Provides an abstract base class for annotations that contains text.
+// </summary>
+// 
--------------------------------------------------------------------------------------------------------------------
+
+namespace OxyPlot.Annotations
+{
+    /// <summary>
+    /// Provides an abstract base class for annotations that contains text.
+    /// </summary>
+    public abstract class TextualAnnotation : Annotation
+    {
+        /// <summary>
+        /// Gets or sets the annotation text.
+        /// </summary>
+        /// <value>
+        /// The text.
+        /// </value>
+        public string Text { get; set; }
+    }
+}
\ No newline at end of file
diff --git a/oxyplot/OxyPlot/Annotations/TileMapAnnotation.cs 
b/oxyplot/OxyPlot/Annotations/TileMapAnnotation.cs
new file mode 100644
index 0000000..7addbd2
--- /dev/null
+++ b/oxyplot/OxyPlot/Annotations/TileMapAnnotation.cs
@@ -0,0 +1,457 @@
+// 
--------------------------------------------------------------------------------------------------------------------
+// <copyright file="TileMapAnnotation.cs" company="OxyPlot">
+//   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.
+// </copyright>
+// <summary>
+//   Provides a tile map annotation.
+// </summary>
+// 
--------------------------------------------------------------------------------------------------------------------
+
+namespace OxyPlot.Annotations
+{
+    using System;
+    using System.Collections.Generic;
+    using System.Globalization;
+    using System.IO;
+    using System.Net;
+    using System.Threading;
+
+    /// <summary>
+    /// Provides a tile map annotation.
+    /// </summary>
+    /// <remarks>
+    /// The longitude and latitude range of the map is defined by the range of the x and y axis, 
respectively.
+    /// </remarks>
+    public class TileMapAnnotation : Annotation
+    {
+        /// <summary>
+        /// The image cache.
+        /// </summary>
+        private readonly Dictionary<string, OxyImage> images = new Dictionary<string, OxyImage>();
+
+        /// <summary>
+        /// The download queue.
+        /// </summary>
+        private readonly Queue<string> queue = new Queue<string>();
+
+        /// <summary>
+        /// The current number of downloads
+        /// </summary>
+        private int numberOfDownloads;
+
+        /// <summary>
+        /// Initializes a new instance of the <see cref="TileMapAnnotation" /> class.
+        /// </summary>
+        public TileMapAnnotation()
+        {
+            this.TileSize = 256;
+            this.MinZoomLevel = 0;
+            this.MaxZoomLevel = 20;
+            this.Opacity = 1.0;
+            this.MaxNumberOfDownloads = 8;
+        }
+
+        /// <summary>
+        /// Gets or sets the max number of simultaneous downloads.
+        /// </summary>
+        /// <value>
+        /// The max number of downloads.
+        /// </value>
+        public int MaxNumberOfDownloads { get; set; }
+
+        /// <summary>
+        /// Gets or sets the URL.
+        /// </summary>
+        /// <value>
+        /// The URL.
+        /// </value>
+        public string Url { get; set; }
+
+        /// <summary>
+        /// Gets or sets the copyright notice.
+        /// </summary>
+        /// <value>
+        /// The copyright notice.
+        /// </value>
+        public string CopyrightNotice { get; set; }
+
+        /// <summary>
+        /// Gets or sets the size of the tiles.
+        /// </summary>
+        /// <value>
+        /// The size of the tiles.
+        /// </value>
+        public int TileSize { get; set; }
+
+        /// <summary>
+        /// Gets or sets the min zoom level.
+        /// </summary>
+        /// <value>
+        /// The min zoom level.
+        /// </value>
+        public int MinZoomLevel { get; set; }
+
+        /// <summary>
+        /// Gets or sets the max zoom level.
+        /// </summary>
+        /// <value>
+        /// The max zoom level.
+        /// </value>
+        public int MaxZoomLevel { get; set; }
+
+        /// <summary>
+        /// Gets or sets the opacity.
+        /// </summary>
+        /// <value>
+        /// The opacity.
+        /// </value>
+        public double Opacity { get; set; }
+
+        /// <summary>
+        /// Renders the annotation on the specified context.
+        /// </summary>
+        /// <param name="rc">
+        /// The render context.
+        /// </param>
+        /// <param name="model">
+        /// The model.
+        /// </param>
+        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);
+        }
+
+        /// <summary>
+        /// Tests if the plot element is hit by the specified point.
+        /// </summary>
+        /// <param name="point">
+        /// The point.
+        /// </param>
+        /// <param name="tolerance">
+        /// The tolerance.
+        /// </param>
+        /// <returns>
+        /// A hit test result.
+        /// </returns>
+        protected internal override HitTestResult HitTest(ScreenPoint point, double tolerance)
+        {
+            return null;
+        }
+
+        /// <summary>
+        /// Transforms a position to a tile coordinate.
+        /// </summary>
+        /// <param name="latitude">The latitude.</param>
+        /// <param name="longitude">The longitude.</param>
+        /// <param name="zoom">The zoom.</param>
+        /// <param name="x">The x.</param>
+        /// <param name="y">The y.</param>
+        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;
+        }
+
+        /// <summary>
+        /// Transforms a tile coordinate (x,y) to a position.
+        /// </summary>
+        /// <param name="x">The x.</param>
+        /// <param name="y">The y.</param>
+        /// <param name="zoom">The zoom.</param>
+        /// <param name="latitude">The latitude.</param>
+        /// <param name="longitude">The longitude.</param>
+        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;
+        }
+
+        /// <summary>
+        /// Gets the image from the specified uri.
+        /// </summary>
+        /// <param name="uri">The URI.</param>
+        /// <param name="async">Get the image asynchronously if set to <c>true</c>. The plot model will be 
invalidated when the image has been downloaded.</param>
+        /// <returns>
+        /// The image.
+        /// </returns>
+        /// <remarks>
+        /// This method gets the image from cache, or starts an async download.
+        /// </remarks>
+        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;
+        }
+
+        /// <summary>
+        /// Downloads the image from the specified URI.
+        /// </summary>
+        /// <param name="uri">The URI.</param>
+        /// <returns>The image</returns>
+        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;
+        }
+
+        /// <summary>
+        /// Starts the next download in the queue.
+        /// </summary>
+        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);
+        }
+
+        /// <summary>
+        /// The download completed, set the image.
+        /// </summary>
+        /// <param name="uri">The URI.</param>
+        /// <param name="result">The result.</param>
+        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();
+            }
+        }
+
+        /// <summary>
+        /// Gets the tile URI.
+        /// </summary>
+        /// <param name="x">
+        /// The tile x.
+        /// </param>
+        /// <param name="y">
+        /// The tile y.
+        /// </param>
+        /// <param name="zoom">
+        /// The zoom.
+        /// </param>
+        /// <returns>
+        /// The uri.
+        /// </returns>
+        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 --git a/oxyplot/OxyPlot/Axes/AngleAxis.cs b/oxyplot/OxyPlot/Axes/AngleAxis.cs
new file mode 100644
index 0000000..4bb02d9
--- /dev/null
+++ b/oxyplot/OxyPlot/Axes/AngleAxis.cs
@@ -0,0 +1,184 @@
+// 
--------------------------------------------------------------------------------------------------------------------
+// <copyright file="AngleAxis.cs" company="OxyPlot">
+//   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.
+// </copyright>
+// <summary>
+//   Represents an angular axis for polar plots.
+// </summary>
+// 
--------------------------------------------------------------------------------------------------------------------
+namespace OxyPlot.Axes
+{
+    using System;
+
+    /// <summary>
+    /// Represents an angular axis for polar plots.
+    /// </summary>
+    public class AngleAxis : LinearAxis
+    {
+        /// <summary>
+        /// Initializes a new instance of the <see cref="AngleAxis"/> class.
+        /// </summary>
+        public AngleAxis()
+        {
+            this.IsPanEnabled = false;
+            this.IsZoomEnabled = false;
+            this.MajorGridlineStyle = LineStyle.Solid;
+            this.MinorGridlineStyle = LineStyle.Solid;
+            this.StartAngle = 0;
+            this.EndAngle = 360;
+        }
+
+        /// <summary>
+        /// Initializes a new instance of the <see cref="AngleAxis"/> class.
+        /// </summary>
+        /// <param name="minimum">
+        /// The minimum.
+        /// </param>
+        /// <param name="maximum">
+        /// The maximum.
+        /// </param>
+        /// <param name="majorStep">
+        /// The major step.
+        /// </param>
+        /// <param name="minorStep">
+        /// The minor step.
+        /// </param>
+        /// <param name="title">
+        /// The title.
+        /// </param>
+        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;
+        }
+
+        /// <summary>
+        /// Gets or sets the start angle (degrees).
+        /// </summary>
+        public double StartAngle { get; set; }
+
+        /// <summary>
+        /// Gets or sets the end angle (degrees).
+        /// </summary>
+        public double EndAngle { get; set; }
+
+        /// <summary>
+        /// Inverse transform the specified screen point.
+        /// </summary>
+        /// <param name="x">The x coordinate.</param>
+        /// <param name="y">The y coordinate.</param>
+        /// <param name="yaxis">The y-axis.</param>
+        /// <returns>
+        /// The data point.
+        /// </returns>
+        public override DataPoint InverseTransform(double x, double y, Axis yaxis)
+        {
+            throw new InvalidOperationException("Angle axis should always be the y-axis.");
+        }
+
+        /// <summary>
+        /// Determines whether the axis is used for X/Y values.
+        /// </summary>
+        /// <returns>
+        /// <c>true</c> if it is an XY axis; otherwise, <c>false</c> .
+        /// </returns>
+        public override bool IsXyAxis()
+        {
+            return false;
+        }
+
+        /// <summary>
+        /// Renders the axis on the specified render context.
+        /// </summary>
+        /// <param name="rc">The render context.</param>
+        /// <param name="model">The model.</param>
+        /// <param name="axisLayer">The rendering order.</param>
+        /// <param name="pass"></param>
+        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);
+        }
+
+        /// <summary>
+        /// Transforms the specified point to screen coordinates.
+        /// </summary>
+        /// <param name="x">
+        /// The x value (for the current axis).
+        /// </param>
+        /// <param name="y">
+        /// The y value.
+        /// </param>
+        /// <param name="yaxis">
+        /// The y axis.
+        /// </param>
+        /// <returns>
+        /// The transformed point.
+        /// </returns>
+        public override ScreenPoint Transform(double x, double y, Axis yaxis)
+        {
+            throw new InvalidOperationException("Angle axis should always be the y-axis.");
+        }
+
+        /// <summary>
+        /// The update transform.
+        /// </summary>
+        /// <param name="bounds">
+        /// The bounds.
+        /// </param>
+        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 --git a/oxyplot/OxyPlot/Axes/Axis.cs b/oxyplot/OxyPlot/Axes/Axis.cs
new file mode 100644
index 0000000..c9aead3
--- /dev/null
+++ b/oxyplot/OxyPlot/Axes/Axis.cs
@@ -0,0 +1,1753 @@
+// 
--------------------------------------------------------------------------------------------------------------------
+// <copyright file="Axis.cs" company="OxyPlot">
+//   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.
+// </copyright>
+// <summary>
+//   Abstract base class for axes.
+// </summary>
+// 
--------------------------------------------------------------------------------------------------------------------
+namespace OxyPlot.Axes
+{
+    using System;
+    using System.Collections.Generic;
+    using System.Diagnostics.CodeAnalysis;
+    using System.Globalization;
+
+    using OxyPlot.Series;
+
+    /// <summary>
+    /// Provides an abstract base class for axes.
+    /// </summary>
+    public abstract class Axis : PlotElement
+    {
+        /// <summary>
+        /// Exponent function.
+        /// </summary>
+        protected static readonly Func<double, double> Exponent = x => Math.Round(Math.Log(Math.Abs(x), 10));
+
+        /// <summary>
+        /// Mantissa function. http://en.wikipedia.org/wiki/Mantissa
+        /// </summary>
+        protected static readonly Func<double, double> Mantissa = x => x / Math.Pow(10, Exponent(x));
+
+        /// <summary>
+        /// The offset.
+        /// </summary>
+        [SuppressMessage("StyleCop.CSharp.MaintainabilityRules", "SA1401:FieldsMustBePrivate",
+            Justification = "Reviewed. Suppression is OK here.")]
+        protected double offset;
+
+        /// <summary>
+        /// The scale.
+        /// </summary>
+        [SuppressMessage("StyleCop.CSharp.MaintainabilityRules", "SA1401:FieldsMustBePrivate",
+            Justification = "Reviewed. Suppression is OK here.")]
+        protected double scale;
+
+        /// <summary>
+        /// The position.
+        /// </summary>
+        private AxisPosition position;
+
+        /// <summary>
+        /// Initializes a new instance of the <see cref="Axis"/> class.
+        /// </summary>
+        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;
+        }
+
+        /// <summary>
+        /// Initializes a new instance of the <see cref="Axis"/> class.
+        /// </summary>
+        /// <param name="pos">
+        /// The position of the axis.
+        /// </param>
+        /// <param name="minimum">
+        /// The minimum value.
+        /// </param>
+        /// <param name="maximum">
+        /// The maximum value.
+        /// </param>
+        /// <param name="title">
+        /// The axis title.
+        /// </param>
+        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;
+        }
+
+        /// <summary>
+        /// Occurs when the axis has been changed (by zooming, panning or resetting).
+        /// </summary>
+        public event EventHandler<AxisChangedEventArgs> AxisChanged;
+
+        /// <summary>
+        /// 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.
+        /// </summary>
+        /// <value> The absolute maximum. </value>
+        public double AbsoluteMaximum { get; set; }
+
+        /// <summary>
+        /// 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.
+        /// </summary>
+        /// <value> The absolute minimum. </value>
+        public double AbsoluteMinimum { get; set; }
+
+        /// <summary>
+        /// Gets the actual culture.
+        /// </summary>
+        /// <remarks>
+        /// The culture is defined in the parent PlotModel.
+        /// </remarks>
+        public CultureInfo ActualCulture
+        {
+            get
+            {
+                return this.PlotModel != null ? this.PlotModel.ActualCulture : CultureInfo.CurrentCulture;
+            }
+        }
+
+        /// <summary>
+        /// Gets or sets the actual major step.
+        /// </summary>
+        public double ActualMajorStep { get; protected set; }
+
+        /// <summary>
+        /// Gets or sets the actual maximum value of the axis.
+        /// </summary>
+        /// <remarks>
+        /// 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.
+        /// </remarks>
+        public double ActualMaximum { get; protected set; }
+
+        /// <summary>
+        /// Gets or sets the actual minimum value of the axis.
+        /// </summary>
+        /// <remarks>
+        /// 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.
+        /// </remarks>
+        public double ActualMinimum { get; protected set; }
+
+        /// <summary>
+        /// Gets or sets the maximum value of the data displayed on this axis.
+        /// </summary>
+        /// <value>The data maximum.</value>
+        public double DataMaximum { get; protected set; }
+
+        /// <summary>
+        /// Gets or sets the minimum value of the data displayed on this axis.
+        /// </summary>
+        /// <value>The data minimum.</value>
+        public double DataMinimum { get; protected set; }
+
+        /// <summary>
+        /// Gets or sets the actual minor step.
+        /// </summary>
+        public double ActualMinorStep { get; protected set; }
+
+        /// <summary>
+        /// Gets or sets the actual string format being used.
+        /// </summary>
+        public string ActualStringFormat { get; protected set; }
+
+        /// <summary>
+        /// Gets the actual title (including Unit if Unit is set).
+        /// </summary>
+        /// <value> The actual title. </value>
+        public string ActualTitle
+        {
+            get
+            {
+                if (this.Unit != null)
+                {
+                    return string.Format(this.TitleFormatString, this.Title, this.Unit);
+                }
+
+                return this.Title;
+            }
+        }
+
+        /// <summary>
+        /// Gets or sets the angle for the axis values.
+        /// </summary>
+        public double Angle { get; set; }
+
+        /// <summary>
+        /// Gets or sets the distance from axis tick to number label.
+        /// </summary>
+        /// <value> The axis tick to label distance. </value>
+        public double AxisTickToLabelDistance { get; set; }
+
+        /// <summary>
+        /// Gets or sets the distance from axis number to axis title.
+        /// </summary>
+        /// <value> The axis title distance. </value>
+        public double AxisTitleDistance { get; set; }
+
+        /// <summary>
+        /// Gets or sets the color of the axis line.
+        /// </summary>
+        public OxyColor AxislineColor { get; set; }
+
+        /// <summary>
+        /// Gets or sets the axis line.
+        /// </summary>
+        public LineStyle AxislineStyle { get; set; }
+
+        /// <summary>
+        /// Gets or sets the axis line.
+        /// </summary>
+        public double AxislineThickness { get; set; }
+
+        /// <summary>
+        /// Gets or sets a value indicating whether to clip the axis title.
+        /// </summary>
+        /// <remarks>
+        /// The default value is true.
+        /// </remarks>
+        public bool ClipTitle { get; set; }
+
+        /// <summary>
+        /// 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).
+        /// </summary>
+        public double EndPosition { get; set; }
+
+        /// <summary>
+        /// Gets or sets the color of the extra gridlines.
+        /// </summary>
+        public OxyColor ExtraGridlineColor { get; set; }
+
+        /// <summary>
+        /// Gets or sets the extra gridlines line style.
+        /// </summary>
+        public LineStyle ExtraGridlineStyle { get; set; }
+
+        /// <summary>
+        /// Gets or sets the extra gridline thickness.
+        /// </summary>
+        public double ExtraGridlineThickness { get; set; }
+
+        /// <summary>
+        /// Gets or sets the values for extra gridlines.
+        /// </summary>
+        public double[] ExtraGridlines { get; set; }
+
+        /// <summary>
+        /// Gets or sets the filter function.
+        /// </summary>
+        /// <value> The filter function. </value>
+        public Func<double, bool> FilterFunction { get; set; }
+
+        /// <summary>
+        /// Gets or sets the maximum value that can be shown using this axis. Values greater or equal to 
this value will not be shown.
+        /// </summary>
+        /// <value> The filter max value. </value>
+        public double FilterMaxValue { get; set; }
+
+        /// <summary>
+        /// Gets or sets the minimum value that can be shown using this axis. Values smaller or equal to 
this value will not be shown.
+        /// </summary>
+        /// <value> The filter min value. </value>
+        public double FilterMinValue { get; set; }
+
+        /// <summary>
+        /// 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.
+        /// </summary>
+        public double IntervalLength { get; set; }
+
+        /// <summary>
+        /// Gets or sets a value indicating whether this axis is visible.
+        /// </summary>
+        public bool IsAxisVisible { get; set; }
+
+        /// <summary>
+        /// Gets or sets a value indicating whether pan is enabled.
+        /// </summary>
+        public bool IsPanEnabled { get; set; }
+
+        /// <summary>
+        /// Gets a value indicating whether this axis is reversed. It is reversed if 
StartPosition>EndPosition.
+        /// </summary>
+        public bool IsReversed
+        {
+            get
+            {
+                return this.StartPosition > this.EndPosition;
+            }
+        }
+
+        /// <summary>
+        /// Gets or sets a value indicating whether zoom is enabled.
+        /// </summary>
+        public bool IsZoomEnabled { get; set; }
+
+        /// <summary>
+        /// 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.
+        /// </summary>
+        public string Key { get; set; }
+
+        /// <summary>
+        /// Gets or sets the layer.
+        /// </summary>
+        /// <value> The layer. </value>
+        public AxisLayer Layer { get; set; }
+
+        /// <summary>
+        /// Gets or sets the color of the major gridline.
+        /// </summary>
+        public OxyColor MajorGridlineColor { get; set; }
+
+        /// <summary>
+        /// Gets or sets the major gridline style.
+        /// </summary>
+        public LineStyle MajorGridlineStyle { get; set; }
+
+        /// <summary>
+        /// Gets or sets the major gridline thickness.
+        /// </summary>
+        public double MajorGridlineThickness { get; set; }
+
+        /// <summary>
+        /// Gets or sets the major step. (the interval between large ticks with numbers).
+        /// </summary>
+        public double MajorStep { get; set; }
+
+        /// <summary>
+        /// Gets or sets the size of the major tick.
+        /// </summary>
+        public double MajorTickSize { get; set; }
+
+        /// <summary>
+        /// Gets or sets the maximum value of the axis.
+        /// </summary>
+        public double Maximum { get; set; }
+
+        /// <summary>
+        /// 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.
+        /// </summary>
+        public double MaximumPadding { get; set; }
+
+        /// <summary>
+        /// Gets or sets the minimum value of the axis.
+        /// </summary>
+        public double Minimum { get; set; }
+
+        /// <summary>
+        /// 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.
+        /// </summary>
+        public double MinimumPadding { get; set; }
+
+        /// <summary>
+        /// Gets or sets the minimum range of the axis. Setting this property ensures that 
ActualMaximum-ActualMinimum > MinimumRange.
+        /// </summary>
+        public double MinimumRange { get; set; }
+
+        /// <summary>
+        /// Gets or sets the color of the minor gridline.
+        /// </summary>
+        public OxyColor MinorGridlineColor { get; set; }
+
+        /// <summary>
+        /// Gets or sets the minor gridline style.
+        /// </summary>
+        public LineStyle MinorGridlineStyle { get; set; }
+
+        /// <summary>
+        /// Gets or sets the minor gridline thickness.
+        /// </summary>
+        public double MinorGridlineThickness { get; set; }
+
+        /// <summary>
+        /// Gets or sets the minor step (the interval between small ticks without number).
+        /// </summary>
+        public double MinorStep { get; set; }
+
+        /// <summary>
+        /// Gets or sets the size of the minor tick.
+        /// </summary>
+        public double MinorTickSize { get; set; }
+
+        /// <summary>
+        /// Gets or sets the offset. This is used to transform between data and screen coordinates.
+        /// </summary>
+        public double Offset
+        {
+            get
+            {
+                return this.offset;
+            }
+
+            protected set
+            {
+                this.offset = value;
+            }
+        }
+
+        /// <summary>
+        /// Gets or sets the position of the axis.
+        /// </summary>
+        public AxisPosition Position
+        {
+            get
+            {
+                return this.position;
+            }
+
+            set
+            {
+                this.position = value;
+            }
+        }
+
+        /// <summary>
+        /// Gets or sets a value indicating whether the axis should be positioned on the zero-crossing of 
the related axis.
+        /// </summary>
+        public bool PositionAtZeroCrossing { get; set; }
+
+        /// <summary>
+        /// Gets or sets the position tier which defines in which tier the axis is displayed.
+        /// </summary>
+        /// <remarks>
+        /// The bigger the value the the further afar is the axis from the graph.
+        /// </remarks>
+        public int PositionTier { get; set; }
+
+        /// <summary>
+        /// Gets or sets the related axis. This is used for polar coordinate systems where the angle and 
magnitude axes are related.
+        /// </summary>
+        public Axis RelatedAxis { get; set; }
+
+        /// <summary>
+        /// Gets or sets the scaling factor of the axis. This is used to transform between data and screen 
coordinates.
+        /// </summary>
+        public double Scale
+        {
+            get
+            {
+                return this.scale;
+            }
+
+            protected set
+            {
+                this.scale = value;
+            }
+        }
+
+        /// <summary>
+        /// Gets or sets the screen coordinate of the Maximum point on the axis.
+        /// </summary>
+        public ScreenPoint ScreenMax { get; protected set; }
+
+        /// <summary>
+        /// Gets or sets the screen coordinate of the Minimum point on the axis.
+        /// </summary>
+        public ScreenPoint ScreenMin { get; protected set; }
+
+        /// <summary>
+        /// Gets or sets a value indicating whether minor ticks should be shown.
+        /// </summary>
+        public bool ShowMinorTicks { get; set; }
+
+        /// <summary>
+        /// 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).
+        /// </summary>
+        public double StartPosition { get; set; }
+
+        /// <summary>
+        /// Gets or sets the string format used for formatting the axis values.
+        /// </summary>
+        public string StringFormat { get; set; }
+
+        /// <summary>
+        /// Gets or sets the tick style (both for major and minor ticks).
+        /// </summary>
+        public TickStyle TickStyle { get; set; }
+
+        /// <summary>
+        /// Gets or sets the color of the ticks (both major and minor ticks).
+        /// </summary>
+        public OxyColor TicklineColor { get; set; }
+
+        /// <summary>
+        /// Gets or sets the title of the axis.
+        /// </summary>
+        public string Title { get; set; }
+
+        /// <summary>
+        /// Gets or sets the length of the title clipping rectangle (fraction of the available length of the 
axis).
+        /// </summary>
+        /// <remarks>
+        /// The default value is 0.9
+        /// </remarks>
+        public double TitleClippingLength { get; set; }
+
+        /// <summary>
+        /// Gets or sets the color of the title.
+        /// </summary>
+        /// <value> The color of the title. </value>
+        /// <remarks>
+        /// If TitleColor is null, the parent PlotModel's TextColor will be used.
+        /// </remarks>
+        public OxyColor TitleColor { get; set; }
+
+        /// <summary>
+        /// Gets or sets the title font.
+        /// </summary>
+        /// <value> The title font. </value>
+        public string TitleFont { get; set; }
+
+        /// <summary>
+        /// Gets or sets the size of the title font.
+        /// </summary>
+        /// <value> The size of the title font. </value>
+        public double TitleFontSize { get; set; }
+
+        /// <summary>
+        /// Gets or sets the title font weight.
+        /// </summary>
+        /// <value> The title font weight. </value>
+        public double TitleFontWeight { get; set; }
+
+        /// <summary>
+        /// 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.
+        /// </summary>
+        public string TitleFormatString { get; set; }
+
+        /// <summary>
+        /// Gets or sets the position of the title (0.5 is in the middle).
+        /// </summary>
+        public double TitlePosition { get; set; }
+
+        /// <summary>
+        /// Gets or sets the tool tip.
+        /// </summary>
+        /// <value> The tool tip. </value>
+        public string ToolTip { get; set; }
+
+        /// <summary>
+        /// Gets or sets the unit of the axis.
+        /// </summary>
+        public string Unit { get; set; }
+
+        /// <summary>
+        /// 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}
+        /// </summary>
+        public bool UseSuperExponentialFormat { get; set; }
+
+        /// <summary>
+        /// Gets or sets the position tier max shift.
+        /// </summary>
+        /// <value> The position tier max shift. </value>
+        internal double PositionTierMaxShift { get; set; }
+
+        /// <summary>
+        /// Gets or sets the position tier min shift.
+        /// </summary>
+        /// <value> The position tier min shift. </value>
+        internal double PositionTierMinShift { get; set; }
+
+        /// <summary>
+        /// Gets or sets the size of the position tier.
+        /// </summary>
+        /// <value> The size of the position tier. </value>
+        internal double PositionTierSize { get; set; }
+
+        /// <summary>
+        /// Gets the actual color of the title.
+        /// </summary>
+        /// <value> The actual color of the title. </value>
+        protected internal OxyColor ActualTitleColor
+        {
+            get
+            {
+                return this.TitleColor ?? this.PlotModel.TextColor;
+            }
+        }
+
+        /// <summary>
+        /// Gets the actual title font.
+        /// </summary>
+        protected internal string ActualTitleFont
+        {
+            get
+            {
+                return this.TitleFont ?? this.PlotModel.DefaultFont;
+            }
+        }
+
+        /// <summary>
+        /// Gets the actual size of the title font.
+        /// </summary>
+        /// <value> The actual size of the title font. </value>
+        protected internal double ActualTitleFontSize
+        {
+            get
+            {
+                return !double.IsNaN(this.TitleFontSize) ? this.TitleFontSize : this.ActualFontSize;
+            }
+        }
+
+        /// <summary>
+        /// Gets the actual title font weight.
+        /// </summary>
+        protected internal double ActualTitleFontWeight
+        {
+            get
+            {
+                return !double.IsNaN(this.TitleFontWeight) ? this.TitleFontWeight : this.ActualFontWeight;
+            }
+        }
+
+        /// <summary>
+        /// Gets or sets the current view's maximum. This value is used when the user zooms or pans.
+        /// </summary>
+        /// <value> The view maximum. </value>
+        protected double ViewMaximum { get; set; }
+
+        /// <summary>
+        /// Gets or sets the current view's minimum. This value is used when the user zooms or pans.
+        /// </summary>
+        /// <value> The view minimum. </value>
+        protected double ViewMinimum { get; set; }
+
+        /// <summary>
+        /// Transforms the specified point to screen coordinates.
+        /// </summary>
+        /// <param name="p">
+        /// The point.
+        /// </param>
+        /// <param name="xaxis">
+        /// The x axis.
+        /// </param>
+        /// <param name="yaxis">
+        /// The y axis.
+        /// </param>
+        /// <returns>
+        /// The transformed point.
+        /// </returns>
+        public static ScreenPoint Transform(DataPoint p, Axis xaxis, Axis yaxis)
+        {
+            return xaxis.Transform(p.x, p.y, yaxis);
+        }
+
+        /// <summary>
+        /// Transform the specified screen point to data coordinates.
+        /// </summary>
+        /// <param name="p">The point.</param>
+        /// <param name="xaxis">The x axis.</param>
+        /// <param name="yaxis">The y axis.</param>
+        /// <returns>The data point.</returns>
+        public static DataPoint InverseTransform(ScreenPoint p, Axis xaxis, Axis yaxis)
+        {
+            return xaxis.InverseTransform(p.x, p.y, yaxis);
+        }
+
+        /// <summary>
+        /// Transforms the specified point to screen coordinates.
+        /// </summary>
+        /// <param name="p">
+        /// The point.
+        /// </param>
+        /// <param name="xaxis">
+        /// The x axis.
+        /// </param>
+        /// <param name="yaxis">
+        /// The y axis.
+        /// </param>
+        /// <returns>
+        /// The transformed point.
+        /// </returns>
+        public static ScreenPoint Transform(IDataPoint p, Axis xaxis, Axis yaxis)
+        {
+            return xaxis.Transform(p.X, p.Y, yaxis);
+        }
+
+        /// <summary>
+        /// Coerces the actual maximum and minimum values.
+        /// </summary>
+        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.");
+            }
+        }
+
+        /// <summary>
+        /// Formats the value to be used on the axis.
+        /// </summary>
+        /// <param name="x">
+        /// The value.
+        /// </param>
+        /// <returns>
+        /// The formatted value.
+        /// </returns>
+        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);
+        }
+
+        /// <summary>
+        /// Formats the value to be used by the tracker.
+        /// </summary>
+        /// <param name="x">
+        /// The value.
+        /// </param>
+        /// <returns>
+        /// The formatted value.
+        /// </returns>
+        public virtual string FormatValueForTracker(double x)
+        {
+            return x.ToString(this.ActualCulture);
+        }
+
+        /// <summary>
+        /// Gets the coordinates used to draw ticks and tick labels (numbers or category names).
+        /// </summary>
+        /// <param name="majorLabelValues">
+        /// The major label values.
+        /// </param>
+        /// <param name="majorTickValues">
+        /// The major tick values.
+        /// </param>
+        /// <param name="minorTickValues">
+        /// The minor tick values.
+        /// </param>
+        public virtual void GetTickValues(
+            out IList<double> majorLabelValues, out IList<double> majorTickValues, out IList<double> 
minorTickValues)
+        {
+            minorTickValues = CreateTickValues(this.ActualMinimum, this.ActualMaximum, this.ActualMinorStep);
+            majorTickValues = CreateTickValues(this.ActualMinimum, this.ActualMaximum, this.ActualMajorStep);
+            majorLabelValues = majorTickValues;
+        }
+
+        /// <summary>
+        /// 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.
+        /// </summary>
+        /// <param name="x">
+        /// The coordinate.
+        /// </param>
+        /// <returns>
+        /// The value.
+        /// </returns>
+        public virtual object GetValue(double x)
+        {
+            return x;
+        }
+
+        /// <summary>
+        /// Inverse transform the specified screen point.
+        /// </summary>
+        /// <param name="x">
+        /// The x coordinate.
+        /// </param>
+        /// <param name="y">
+        /// The y coordinate.
+        /// </param>
+        /// <param name="yaxis">
+        /// The y-axis.
+        /// </param>
+        /// <returns>
+        /// The data point.
+        /// </returns>
+        public virtual DataPoint InverseTransform(double x, double y, Axis yaxis)
+        {
+            return new DataPoint(this.InverseTransform(x), yaxis != null ? yaxis.InverseTransform(y) : 0);
+        }
+
+        /// <summary>
+        /// Inverse transform the specified screen coordinate. This method can only be used with non-polar 
coordinate systems.
+        /// </summary>
+        /// <param name="sx">
+        /// The screen coordinate.
+        /// </param>
+        /// <returns>
+        /// The value.
+        /// </returns>
+        public virtual double InverseTransform(double sx)
+        {
+            return this.PostInverseTransform((sx / this.scale) + this.offset);
+        }
+
+        /// <summary>
+        /// Determines whether this axis is horizontal.
+        /// </summary>
+        /// <returns>
+        /// <c>true</c> if this axis is horizontal; otherwise, <c>false</c> .
+        /// </returns>
+        public bool IsHorizontal()
+        {
+            return this.position == AxisPosition.Top || this.position == AxisPosition.Bottom;
+        }
+
+        /// <summary>
+        /// Determines whether the specified value is valid.
+        /// </summary>
+        /// <param name="value">
+        /// The value.
+        /// </param>
+        /// <returns>
+        /// <c>true</c> if the specified value is valid; otherwise, <c>false</c> .
+        /// </returns>
+        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));
+        }
+
+        /// <summary>
+        /// Determines whether this axis is vertical.
+        /// </summary>
+        /// <returns>
+        /// <c>true</c> if this axis is vertical; otherwise, <c>false</c> .
+        /// </returns>
+        public bool IsVertical()
+        {
+            return this.position == AxisPosition.Left || this.position == AxisPosition.Right;
+        }
+
+        /// <summary>
+        /// Determines whether the axis is used for X/Y values.
+        /// </summary>
+        /// <returns>
+        /// <c>true</c> if it is an XY axis; otherwise, <c>false</c> .
+        /// </returns>
+        public abstract bool IsXyAxis();
+
+        /// <summary>
+        /// Measures the size of the axis (maximum axis label width/height).
+        /// </summary>
+        /// <param name="rc">
+        /// The render context.
+        /// </param>
+        /// <returns>
+        /// The size of the axis.
+        /// </returns>
+        public virtual OxySize Measure(IRenderContext rc)
+        {
+            IList<double> majorTickValues;
+            IList<double> minorTickValues;
+            IList<double> 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);
+        }
+
+        /// <summary>
+        /// Pans the specified axis.
+        /// </summary>
+        /// <param name="ppt">
+        /// The previous point (screen coordinates).
+        /// </param>
+        /// <param name="cpt">
+        /// The current point (screen coordinates).
+        /// </param>
+        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);
+        }
+
+        /// <summary>
+        /// Pans the specified axis.
+        /// </summary>
+        /// <param name="delta">
+        /// The delta.
+        /// </param>
+        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));
+        }
+
+        /// <summary>
+        /// Renders the axis on the specified render context.
+        /// </summary>
+        /// <param name="rc">The render context.</param>
+        /// <param name="model">The model.</param>
+        /// <param name="axisLayer">The rendering order.</param>
+        /// <param name="pass">The pass.</param>
+        public virtual void Render(IRenderContext rc, PlotModel model, AxisLayer axisLayer, int pass)
+        {
+            var r = new HorizontalAndVerticalAxisRenderer(rc, model);
+            r.Render(this, pass);
+        }
+
+        /// <summary>
+        /// Resets the user's modification (zooming/panning) to minimum and maximum of this axis.
+        /// </summary>
+        public virtual void Reset()
+        {
+            this.ViewMinimum = double.NaN;
+            this.ViewMaximum = double.NaN;
+            this.UpdateActualMaxMin();
+            this.OnAxisChanged(new AxisChangedEventArgs(AxisChangeTypes.Reset));
+        }
+
+        /// <summary>
+        /// Returns a <see cref="System.String"/> that represents this instance.
+        /// </summary>
+        /// <returns>
+        /// A <see cref="System.String"/> that represents this instance.
+        /// </returns>
+        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);
+        }
+
+        /// <summary>
+        /// Transforms the specified point to screen coordinates.
+        /// </summary>
+        /// <param name="x">
+        /// The x value (for the current axis).
+        /// </param>
+        /// <param name="y">
+        /// The y value.
+        /// </param>
+        /// <param name="yaxis">
+        /// The y axis.
+        /// </param>
+        /// <returns>
+        /// The transformed point.
+        /// </returns>
+        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));
+        }
+
+        /// <summary>
+        /// Transforms the specified coordinate to screen coordinates. This method can only be used with 
non-polar coordinate systems.
+        /// </summary>
+        /// <param name="x">
+        /// The value.
+        /// </param>
+        /// <returns>
+        /// The transformed value (screen coordinate).
+        /// </returns>
+        public virtual double Transform(double x)
+        {
+            return (x - this.offset) * this.scale;
+
+            // return (this.PreTransform(x) - this.Offset) * this.Scale;
+        }
+
+        /// <summary>
+        /// Zoom to the specified scale.
+        /// </summary>
+        /// <param name="newScale">
+        /// The new scale.
+        /// </param>
+        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();
+        }
+
+        /// <summary>
+        /// Zooms the axis to the range [x0,x1].
+        /// </summary>
+        /// <param name="x0">
+        /// The new minimum.
+        /// </param>
+        /// <param name="x1">
+        /// The new maximum.
+        /// </param>
+        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));
+        }
+
+        /// <summary>
+        /// Zooms the axis at the specified coordinate.
+        /// </summary>
+        /// <param name="factor">
+        /// The zoom factor.
+        /// </param>
+        /// <param name="x">
+        /// The coordinate to zoom at.
+        /// </param>
+        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));
+        }
+
+        /// <summary>
+        /// Modifies the data range of the axis [DataMinimum,DataMaximum] to includes the specified value.
+        /// </summary>
+        /// <param name="value">
+        /// The value.
+        /// </param>
+        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);
+        }
+
+        /// <summary>
+        /// Applies a transformation after the inverse transform of the value. This is used in logarithmic 
axis.
+        /// </summary>
+        /// <param name="x">
+        /// The value to transform.
+        /// </param>
+        /// <returns>
+        /// The transformed value.
+        /// </returns>
+        internal virtual double PostInverseTransform(double x)
+        {
+            return x;
+        }
+
+        /// <summary>
+        /// Applies a transformation before the transform the value. This is used in logarithmic axis.
+        /// </summary>
+        /// <param name="x">
+        /// The value to transform.
+        /// </param>
+        /// <returns>
+        /// The transformed value.
+        /// </returns>
+        internal virtual double PreTransform(double x)
+        {
+            return x;
+        }
+
+        /// <summary>
+        /// Resets the data maximum and minimum.
+        /// </summary>
+        internal virtual void ResetDataMaxMin()
+        {
+            this.DataMaximum = this.DataMinimum = double.NaN;
+        }
+
+        /// <summary>
+        /// 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'.
+        /// </summary>
+        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();
+        }
+
+        /// <summary>
+        /// Updates the axis with information from the plot series.
+        /// </summary>
+        /// <param name="series">
+        /// The series collection.
+        /// </param>
+        /// <remarks>
+        /// This is used by the category axis that need to know the number of series using the axis.
+        /// </remarks>
+        internal virtual void UpdateFromSeries(IEnumerable<Series> series)
+        {
+        }
+
+        /// <summary>
+        /// Updates the actual minor and major step intervals.
+        /// </summary>
+        /// <param name="plotArea">
+        /// The plot area rectangle.
+        /// </param>
+        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";
+            // }
+        }
+
+        /// <summary>
+        /// Updates the scale and offset properties of the transform from the specified boundary rectangle.
+        /// </summary>
+        /// <param name="bounds">
+        /// The bounds.
+        /// </param>
+        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;
+            }
+        }
+
+        /// <summary>
+        /// Creates tick values at the specified interval.
+        /// </summary>
+        /// <param name="min">
+        /// The minimum coordinate.
+        /// </param>
+        /// <param name="max">
+        /// The maximum coordinate.
+        /// </param>
+        /// <param name="step">
+        /// The interval.
+        /// </param>
+        /// <returns>
+        /// A list of tick values.
+        /// </returns>
+        protected static IList<double> 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<double>(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;
+        }
+
+        /// <summary>
+        /// Calculates the actual interval.
+        /// </summary>
+        /// <param name="availableSize">
+        /// Size of the available area.
+        /// </param>
+        /// <param name="maxIntervalSize">
+        /// Maximum length of the intervals.
+        /// </param>
+        /// <returns>
+        /// The calculate actual interval.
+        /// </returns>
+        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.
+
+        /// <summary>
+        /// Returns the actual interval to use to determine which values are displayed in the axis.
+        /// </summary>
+        /// <param name="availableSize">
+        /// The available size.
+        /// </param>
+        /// <param name="maxIntervalSize">
+        /// The maximum interval size.
+        /// </param>
+        /// <param name="range">
+        /// The range.
+        /// </param>
+        /// <returns>
+        /// Actual interval to use to determine which values are displayed in the axis.
+        /// </returns>
+        protected double CalculateActualInterval(double availableSize, double maxIntervalSize, double range)
+        {
+            if (availableSize <= 0)
+            {
+                return maxIntervalSize;
+            }
+
+            Func<double, double> exponent = x => Math.Ceiling(Math.Log(x, 10));
+            Func<double, double> 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;
+        }
+
+        /// <summary>
+        /// The calculate minor interval.
+        /// </summary>
+        /// <param name="majorInterval">
+        /// The major interval.
+        /// </param>
+        /// <returns>
+        /// The minor interval.
+        /// </returns>
+        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<double, double> exponent = x => Math.Ceiling(Math.Log(x, 10));
+            // Func<double, double> 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;
+            // }
+        }
+
+        /// <summary>
+        /// Raises the AxisChanged event.
+        /// </summary>
+        /// <param name="args">
+        /// The <see cref="OxyPlot.Axes.AxisChangedEventArgs"/> instance containing the event data.
+        /// </param>
+        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 --git a/oxyplot/OxyPlot/Axes/AxisChangeTypes.cs b/oxyplot/OxyPlot/Axes/AxisChangeTypes.cs
new file mode 100644
index 0000000..b93d134
--- /dev/null
+++ b/oxyplot/OxyPlot/Axes/AxisChangeTypes.cs
@@ -0,0 +1,52 @@
+// 
--------------------------------------------------------------------------------------------------------------------
+// <copyright file="AxisChangeTypes.cs" company="OxyPlot">
+//   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.
+// </copyright>
+// <summary>
+//   Change types of the Axis.AxisChanged event.
+// </summary>
+// 
--------------------------------------------------------------------------------------------------------------------
+namespace OxyPlot.Axes
+{
+    /// <summary>
+    /// Specifies change types for the <see cref="Axis.AxisChanged"/> event.
+    /// </summary>
+    public enum AxisChangeTypes
+    {
+        /// <summary>
+        /// The axis was zoomed by the user.
+        /// </summary>
+        Zoom,
+
+        /// <summary>
+        /// The axis was panned by the user.
+        /// </summary>
+        Pan,
+
+        /// <summary>
+        /// The axis zoom/pan was reset by the user.
+        /// </summary>
+        Reset
+    }
+}
\ No newline at end of file
diff --git a/oxyplot/OxyPlot/Axes/AxisChangedEventArgs.cs b/oxyplot/OxyPlot/Axes/AxisChangedEventArgs.cs
new file mode 100644
index 0000000..bbad3f0
--- /dev/null
+++ b/oxyplot/OxyPlot/Axes/AxisChangedEventArgs.cs
@@ -0,0 +1,57 @@
+// 
--------------------------------------------------------------------------------------------------------------------
+// <copyright file="AxisChangedEventArgs.cs" company="OxyPlot">
+//   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.
+// </copyright>
+// <summary>
+//   EventArgs for the Axis.AxisChanged event.
+// </summary>
+// 
--------------------------------------------------------------------------------------------------------------------
+namespace OxyPlot.Axes
+{
+    using System;
+
+    /// <summary>
+    /// Provides additional data for the <see cref="Axis.AxisChanged"/> event.
+    /// </summary>
+    public class AxisChangedEventArgs : EventArgs
+    {
+        /// <summary>
+        /// Initializes a new instance of the <see cref="AxisChangedEventArgs"/> class.
+        /// </summary>
+        /// <param name="changeType">
+        /// Type of the change.
+        /// </param>
+        public AxisChangedEventArgs(AxisChangeTypes changeType)
+        {
+            this.ChangeType = changeType;
+        }
+
+        /// <summary>
+        /// Gets or sets the type of the change.
+        /// </summary>
+        /// <value>The type of the change.</value>
+        public AxisChangeTypes ChangeType { get; set; }
+
+    }
+}
\ No newline at end of file
diff --git a/oxyplot/OxyPlot/Axes/AxisLayer.cs b/oxyplot/OxyPlot/Axes/AxisLayer.cs
new file mode 100644
index 0000000..b44a9f4
--- /dev/null
+++ b/oxyplot/OxyPlot/Axes/AxisLayer.cs
@@ -0,0 +1,47 @@
+// 
--------------------------------------------------------------------------------------------------------------------
+// <copyright file="AxisLayer.cs" company="OxyPlot">
+//   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.
+// </copyright>
+// <summary>
+//   Axis layer position.
+// </summary>
+// 
--------------------------------------------------------------------------------------------------------------------
+namespace OxyPlot.Axes
+{
+    /// <summary>
+    /// Specifies the layer position of an <see cref="Axis"/>.
+    /// </summary>
+    public enum AxisLayer
+    {
+        /// <summary>
+        /// Below all series.
+        /// </summary>
+        BelowSeries,
+
+        /// <summary>
+        /// Above all series.
+        /// </summary>
+        AboveSeries
+    }
+}
\ No newline at end of file
diff --git a/oxyplot/OxyPlot/Axes/AxisPosition.cs b/oxyplot/OxyPlot/Axes/AxisPosition.cs
new file mode 100644
index 0000000..21569b3
--- /dev/null
+++ b/oxyplot/OxyPlot/Axes/AxisPosition.cs
@@ -0,0 +1,62 @@
+// 
--------------------------------------------------------------------------------------------------------------------
+// <copyright file="AxisPosition.cs" company="OxyPlot">
+//   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.
+// </copyright>
+// <summary>
+//   Axis positions.
+// </summary>
+// 
--------------------------------------------------------------------------------------------------------------------
+namespace OxyPlot.Axes
+{
+    /// <summary>
+    /// Specifies the position of an <see cref="Axis"/>.
+    /// </summary>
+    public enum AxisPosition
+    {
+        /// <summary>
+        /// No position.
+        /// </summary>
+        None,
+
+        /// <summary>
+        /// Left of the plot area.
+        /// </summary>
+        Left,
+
+        /// <summary>
+        /// Right of the plot area.
+        /// </summary>
+        Right,
+
+        /// <summary>
+        /// Top of the plot area.
+        /// </summary>
+        Top,
+
+        /// <summary>
+        /// Bottom of the plot area.
+        /// </summary>
+        Bottom
+    }
+}
\ No newline at end of file
diff --git a/oxyplot/OxyPlot/Axes/CategoryAxis.cs b/oxyplot/OxyPlot/Axes/CategoryAxis.cs
new file mode 100644
index 0000000..388b4c9
--- /dev/null
+++ b/oxyplot/OxyPlot/Axes/CategoryAxis.cs
@@ -0,0 +1,501 @@
+// 
--------------------------------------------------------------------------------------------------------------------
+// <copyright file="CategoryAxis.cs" company="OxyPlot">
+//   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.
+// </copyright>
+// <summary>
+//   Represents a category axes.
+// </summary>
+// 
--------------------------------------------------------------------------------------------------------------------
+namespace OxyPlot.Axes
+{
+    using System.Collections;
+    using System.Collections.Generic;
+    using System.Globalization;
+    using System.Linq;
+
+    using OxyPlot.Series;
+
+    /// <summary>
+    /// Represents a category axis.
+    /// </summary>
+    /// <remarks>
+    /// 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).
+    /// </remarks>
+    public class CategoryAxis : LinearAxis
+    {
+        /// <summary>
+        /// Initializes a new instance of the <see cref="CategoryAxis"/> class.
+        /// </summary>
+        public CategoryAxis()
+        {
+            this.Labels = new List<string>();
+            this.TickStyle = TickStyle.Outside;
+            this.Position = AxisPosition.Bottom;
+            this.MinimumPadding = 0;
+            this.MaximumPadding = 0;
+            this.MajorStep = 1;
+            this.GapWidth = 1;
+        }
+
+        /// <summary>
+        /// Initializes a new instance of the <see cref="CategoryAxis"/> class.
+        /// </summary>
+        /// <param name="position">The position.</param>
+        /// <param name="title">The title.</param>
+        /// <param name="categories">The categories.</param>
+        public CategoryAxis(AxisPosition position, string title = null, params string[] categories)
+            : this(title, categories)
+        {
+            this.Position = position;
+        }
+
+        /// <summary>
+        /// Initializes a new instance of the <see cref="CategoryAxis"/> class.
+        /// </summary>
+        /// <param name="title">
+        /// The title.
+        /// </param>
+        /// <param name="categories">
+        /// The categories.
+        /// </param>
+        public CategoryAxis(string title, params string[] categories)
+            : this()
+        {
+            this.Title = title;
+            if (categories != null)
+            {
+                foreach (var c in categories)
+                {
+                    this.Labels.Add(c);
+                }
+            }
+        }
+
+        /// <summary>
+        /// Gets or sets the gap width.
+        /// </summary>
+        /// <remarks>
+        /// 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.
+        /// </remarks>
+        public double GapWidth { get; set; }
+
+        /// <summary>
+        /// 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.
+        /// </summary>
+        public bool IsTickCentered { get; set; }
+
+        /// <summary>
+        /// Gets or sets the items source (used to update the Labels collection).
+        /// </summary>
+        /// <value>
+        /// The items source.
+        /// </value>
+        public IEnumerable ItemsSource { get; set; }
+
+        /// <summary>
+        /// Gets or sets the data field for the labels.
+        /// </summary>
+        public string LabelField { get; set; }
+
+        /// <summary>
+        /// Gets or sets the labels collection.
+        /// </summary>
+        public IList<string> Labels { get; set; }
+
+        /// <summary>
+        /// Gets or sets the current offset of the bars (not used for stacked bar series).
+        /// </summary>
+        internal double[] BarOffset { get; set; }
+
+        /// <summary>
+        /// Gets or sets the max value per StackIndex and Label (only used for stacked bar series).
+        /// </summary>
+        internal double[,] MaxValue { get; set; }
+
+        /// <summary>
+        /// Gets or sets the maximal width of all labels
+        /// </summary>
+        internal double MaxWidth { get; set; }
+
+        /// <summary>
+        /// Gets or sets the min value per StackIndex and Label (only used for stacked bar series).
+        /// </summary>
+        internal double[,] MinValue { get; set; }
+
+        /// <summary>
+        /// Gets or sets per StackIndex and Label the base value for negative values of stacked bar series.
+        /// </summary>
+        internal double[,] NegativeBaseValues { get; set; }
+
+        /// <summary>
+        /// Gets or sets per StackIndex and Label the base value for positive values of stacked bar series.
+        /// </summary>
+        internal double[,] PositiveBaseValues { get; set; }
+
+        /// <summary>
+        /// Gets or sets the StackIndexMapping. The mapping indicates to which rank a specific stack index 
belongs.
+        /// </summary>
+        internal Dictionary<string, int> StackIndexMapping { get; set; }
+
+        /// <summary>
+        /// Gets or sets the offset of the bars per StackIndex and Label (only used for stacked bar series).
+        /// </summary>
+        internal double[,] StackedBarOffset { get; set; }
+
+        /// <summary>
+        /// Gets or sets sum of the widths of the single bars per label. This is used to find the bar width 
of BarSeries
+        /// </summary>
+        internal double[] TotalWidthPerCategory { get; set; }
+
+        /// <summary>
+        /// Fills the specified array.
+        /// </summary>
+        /// <param name="array">
+        /// The array.
+        /// </param>
+        /// <param name="value">
+        /// The value.
+        /// </param>
+        public static void Fill(double[] array, double value)
+        {
+            for (var i = 0; i < array.Length; i++)
+            {
+                array[i] = value;
+            }
+        }
+
+        /// <summary>
+        /// Fills the specified array.
+        /// </summary>
+        /// <param name="array">
+        /// The array.
+        /// </param>
+        /// <param name="value">
+        /// The value.
+        /// </param>
+        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;
+                }
+            }
+        }
+
+        /// <summary>
+        /// Formats the value to be used on the axis.
+        /// </summary>
+        /// <param name="x">
+        /// The value.
+        /// </param>
+        /// <returns>
+        /// The formatted value.
+        /// </returns>
+        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;
+        }
+
+        /// <summary>
+        /// Formats the value to be used by the tracker.
+        /// </summary>
+        /// <param name="x">
+        /// The value.
+        /// </param>
+        /// <returns>
+        /// The formatted value.
+        /// </returns>
+        public override string FormatValueForTracker(double x)
+        {
+            return this.FormatValue(x);
+        }
+
+        /// <summary>
+        /// Gets the category value.
+        /// </summary>
+        /// <param name="categoryIndex">
+        /// Index of the category.
+        /// </param>
+        /// <param name="stackIndex">
+        /// Index of the stack.
+        /// </param>
+        /// <param name="actualBarWidth">
+        /// Actual width of the bar.
+        /// </param>
+        /// <returns>
+        /// The get category value.
+        /// </returns>
+        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);
+        }
+
+        /// <summary>
+        /// Gets the category value.
+        /// </summary>
+        /// <param name="categoryIndex">
+        /// Index of the category.
+        /// </param>
+        /// <returns>
+        /// The get category value.
+        /// </returns>
+        public double GetCategoryValue(int categoryIndex)
+        {
+            return categoryIndex - 0.5 + this.BarOffset[categoryIndex];
+        }
+
+        /// <summary>
+        /// Gets the coordinates used to draw ticks and tick labels (numbers or category names).
+        /// </summary>
+        /// <param name="majorLabelValues">
+        /// The major label values.
+        /// </param>
+        /// <param name="majorTickValues">
+        /// The major tick values.
+        /// </param>
+        /// <param name="minorTickValues">
+        /// The minor tick values.
+        /// </param>
+        public override void GetTickValues(
+            out IList<double> majorLabelValues, out IList<double> majorTickValues, out IList<double> 
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<double>(majorLabelValues.Count);
+                mv.AddRange(majorLabelValues.Select(v => v - 0.5));
+                if (mv.Count > 0)
+                {
+                    mv.Add(mv[mv.Count - 1] + 1);
+                }
+
+                majorTickValues = mv;
+            }
+        }
+
+        /// <summary>
+        /// 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.
+        /// </summary>
+        /// <param name="x">
+        /// The coordinate.
+        /// </param>
+        /// <returns>
+        /// The value.
+        /// </returns>
+        public override object GetValue(double x)
+        {
+            return this.FormatValue(x);
+        }
+
+        /// <summary>
+        /// 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'.
+        /// </summary>
+        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;
+        }
+
+        /// <summary>
+        /// Updates the axis with information from the plot series.
+        /// </summary>
+        /// <param name="series">
+        /// The series collection.
+        /// </param>
+        /// <remarks>
+        /// This is used by the category axis that need to know the number of series using the axis.
+        /// </remarks>
+        internal override void UpdateFromSeries(IEnumerable<Series> 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<CategorizedSeries>().ToList();
+            var stackedSeries = categorizedSeries.OfType<IStackableSeries>().Where(s => 
s.IsStacked).ToList();
+            var stackIndices = stackedSeries.Select(s => s.StackGroup).Distinct().ToList();
+            var stackRankBarWidth = new Dictionary<int, double>();
+            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<string, int>();
+            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);
+        }
+
+        /// <summary>
+        /// Creates Labels list if no labels were set
+        /// </summary>
+        /// <param name="series">
+        /// The list of series which are rendered
+        /// </param>
+        internal void UpdateLabels(IEnumerable<Series> 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 --git a/oxyplot/OxyPlot/Axes/ColorAxis.cs b/oxyplot/OxyPlot/Axes/ColorAxis.cs
new file mode 100644
index 0000000..eaf943c
--- /dev/null
+++ b/oxyplot/OxyPlot/Axes/ColorAxis.cs
@@ -0,0 +1,283 @@
+// 
--------------------------------------------------------------------------------------------------------------------
+// <copyright file="ColorAxis.cs" company="OxyPlot">
+//   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.
+// </copyright>
+// <summary>
+//   The color axis.
+// </summary>
+// 
--------------------------------------------------------------------------------------------------------------------
+namespace OxyPlot.Axes
+{
+    using System;
+    using System.Collections.Generic;
+
+    /// <summary>
+    /// Represents a color axis.
+    /// </summary>
+    public class ColorAxis : Axis
+    {
+        /// <summary>
+        /// Initializes a new instance of the <see cref="ColorAxis"/> class.
+        /// </summary>
+        public ColorAxis()
+        {
+            this.Position = AxisPosition.None;
+            this.IsPanEnabled = false;
+            this.IsZoomEnabled = false;
+        }
+
+        /// <summary>
+        /// Gets or sets the color of values above the maximum value.
+        /// </summary>
+        /// <value> The color of the high values. </value>
+        public OxyColor HighColor { get; set; }
+
+        /// <summary>
+        /// Gets or sets the color of values below the minimum value.
+        /// </summary>
+        /// <value> The color of the low values. </value>
+        public OxyColor LowColor { get; set; }
+
+        /// <summary>
+        /// Gets or sets the palette.
+        /// </summary>
+        /// <value> The palette. </value>
+        public OxyPalette Palette { get; set; }
+
+        /// <summary>
+        /// Gets the color.
+        /// </summary>
+        /// <param name="paletteIndex">
+        /// The color map index (less than NumberOfEntries).
+        /// </param>
+        /// <returns>
+        /// The color.
+        /// </returns>
+        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];
+        }
+
+        /// <summary>
+        /// Gets the color for the specified value.
+        /// </summary>
+        /// <param name="value">
+        /// The value.
+        /// </param>
+        /// <returns>
+        /// The color.
+        /// </returns>
+        public OxyColor GetColor(double value)
+        {
+            return this.GetColor(this.GetPaletteIndex(value));
+        }
+
+        /// <summary>
+        /// Gets the colors.
+        /// </summary>
+        /// <returns>The colors.</returns>
+        public IEnumerable<OxyColor> GetColors()
+        {
+            yield return this.LowColor;
+            foreach (var color in this.Palette.Colors)
+            {
+                yield return color;
+            }
+
+            yield return this.HighColor;
+        }
+
+        /// <summary>
+        /// Gets the palette index of the specified value.
+        /// </summary>
+        /// <param name="value">
+        /// The value.
+        /// </param>
+        /// <returns>
+        /// The palette index.
+        /// </returns>
+        /// <remarks>
+        /// If the value is less than minimum, 0 is returned. If the value is greater than maximum, 
Palette.Colors.Count+1 is returned.
+        /// </remarks>
+        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;
+        }
+
+        /// <summary>
+        /// Determines whether the axis is used for X/Y values.
+        /// </summary>
+        /// <returns>
+        /// <c>true</c> if it is an XY axis; otherwise, <c>false</c> .
+        /// </returns>
+        public override bool IsXyAxis()
+        {
+            return false;
+        }
+
+        /// <summary>
+        /// Renders the axis on the specified render context.
+        /// </summary>
+        /// <param name="rc">The render context.</param>
+        /// <param name="model">The model.</param>
+        /// <param name="axisLayer">The rendering order.</param>
+        /// <param name="pass">The render pass.</param>
+        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<double, double, OxyColor> 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);
+        }
+
+        /// <summary>
+        /// Gets the high value of the specified palette index.
+        /// </summary>
+        /// <param name="paletteIndex">
+        /// Index of the palette.
+        /// </param>
+        /// <returns>
+        /// The value.
+        /// </returns>
+        protected double GetHighValue(int paletteIndex)
+        {
+            return this.GetLowValue(paletteIndex + 1);
+        }
+
+        /// <summary>
+        /// Gets the low value of the specified palette index.
+        /// </summary>
+        /// <param name="paletteIndex">
+        /// Index of the palette.
+        /// </param>
+        /// <returns>
+        /// The value.
+        /// </returns>
+        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 --git a/oxyplot/OxyPlot/Axes/DateTimeAxis.cs b/oxyplot/OxyPlot/Axes/DateTimeAxis.cs
new file mode 100644
index 0000000..4f6d14e
--- /dev/null
+++ b/oxyplot/OxyPlot/Axes/DateTimeAxis.cs
@@ -0,0 +1,679 @@
+// 
--------------------------------------------------------------------------------------------------------------------
+// <copyright file="DateTimeAxis.cs" company="OxyPlot">
+//   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.
+// </copyright>
+// <summary>
+//   Represents a DateTime axis.
+// </summary>
+// 
--------------------------------------------------------------------------------------------------------------------
+
+namespace OxyPlot.Axes
+{
+    using System;
+    using System.Collections.Generic;
+    using System.Collections.ObjectModel;
+    using System.Globalization;
+    using System.Linq;
+
+    /// <summary>
+    /// Represents a axis presenting <see cref="System.DateTime"/> values.
+    /// </summary>
+    /// <remarks>
+    /// 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
+    /// </remarks>
+    public class DateTimeAxis : LinearAxis
+    {
+        /// <summary>
+        /// The time origin.
+        /// </summary>
+        /// <remarks>
+        /// Same date values as Excel
+        /// </remarks>
+        private static DateTime timeOrigin = new DateTime(1900, 1, 1, 0, 0, 0, DateTimeKind.Utc);
+
+        /// <summary>
+        /// The actual interval type.
+        /// </summary>
+        private DateTimeIntervalType actualIntervalType;
+
+        /// <summary>
+        /// The actual minor interval type.
+        /// </summary>
+        private DateTimeIntervalType actualMinorIntervalType;
+
+        /// <summary>
+        /// Initializes a new instance of the <see cref = "DateTimeAxis" /> class.
+        /// </summary>
+        public DateTimeAxis()
+        {
+            this.Position = AxisPosition.Bottom;
+            this.IntervalType = DateTimeIntervalType.Auto;
+            this.FirstDayOfWeek = DayOfWeek.Monday;
+            this.CalendarWeekRule = CalendarWeekRule.FirstFourDayWeek;
+        }
+
+        /// <summary>
+        /// Initializes a new instance of the <see cref="DateTimeAxis"/> class.
+        /// </summary>
+        /// <param name="pos">
+        /// The position.
+        /// </param>
+        /// <param name="title">
+        /// The axis title.
+        /// </param>
+        /// <param name="format">
+        /// The string format for the axis values.
+        /// </param>
+        /// <param name="intervalType">
+        /// The interval type.
+        /// </param>
+        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;
+        }
+
+        /// <summary>
+        /// Initializes a new instance of the <see cref="DateTimeAxis"/> class.
+        /// </summary>
+        /// <param name="firstDateTime">
+        /// The first date/time on the axis.
+        /// </param>
+        /// <param name="lastDateTime">
+        /// The last date/time on the axis.
+        /// </param>
+        /// <param name="pos">
+        /// The position of the axis.
+        /// </param>
+        /// <param name="title">
+        /// The axis title.
+        /// </param>
+        /// <param name="format">
+        /// The string format for the axis values.
+        /// </param>
+        /// <param name="intervalType">
+        /// The interval type.
+        /// </param>
+        [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);
+        }
+
+        /// <summary>
+        /// Initializes a new instance of the <see cref="DateTimeAxis" /> class.
+        /// </summary>
+        /// <param name="pos">The position of the axis.</param>
+        /// <param name="firstDateTime">The first date/time on the axis.</param>
+        /// <param name="lastDateTime">The last date/time on the axis.</param>
+        /// <param name="title">The axis title.</param>
+        /// <param name="format">The string format for the axis values.</param>
+        /// <param name="intervalType">The interval type.</param>
+        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);
+        }
+
+        /// <summary>
+        /// Gets or sets CalendarWeekRule.
+        /// </summary>
+        public CalendarWeekRule CalendarWeekRule { get; set; }
+
+        /// <summary>
+        /// Gets or sets FirstDayOfWeek.
+        /// </summary>
+        public DayOfWeek FirstDayOfWeek { get; set; }
+
+        /// <summary>
+        /// Gets or sets IntervalType.
+        /// </summary>
+        public DateTimeIntervalType IntervalType { get; set; }
+
+        /// <summary>
+        /// Gets or sets MinorIntervalType.
+        /// </summary>
+        public DateTimeIntervalType MinorIntervalType { get; set; }
+
+        /// <summary>
+        /// Gets or sets the time zone (used when formatting date/time values).
+        /// </summary>
+        /// <remarks>
+        /// No date/time conversion will be performed if this property is null.
+        /// </remarks>
+        /// <value>
+        /// The time zone info.
+        /// </value>
+        public TimeZoneInfo TimeZone { get; set; }
+
+        /// <summary>
+        /// Creates a data point.
+        /// </summary>
+        /// <param name="x">
+        /// The x value.
+        /// </param>
+        /// <param name="y">
+        /// The y value.
+        /// </param>
+        /// <returns>
+        /// A data point.
+        /// </returns>
+        public static DataPoint CreateDataPoint(DateTime x, double y)
+        {
+            return new DataPoint(ToDouble(x), y);
+        }
+
+        /// <summary>
+        /// Creates a data point.
+        /// </summary>
+        /// <param name="x">
+        /// The x value.
+        /// </param>
+        /// <param name="y">
+        /// The y value. 
+        /// </param>
+        /// <returns>
+        /// A data point.
+        /// </returns>
+        public static DataPoint CreateDataPoint(DateTime x, DateTime y)
+        {
+            return new DataPoint(ToDouble(x), ToDouble(y));
+        }
+
+        /// <summary>
+        /// Creates a data point.
+        /// </summary>
+        /// <param name="x">
+        /// The x value.
+        /// </param>
+        /// <param name="y">
+        /// The y value.
+        /// </param>
+        /// <returns>
+        /// A data point.
+        /// </returns>
+        public static DataPoint CreateDataPoint(double x, DateTime y)
+        {
+            return new DataPoint(x, ToDouble(y));
+        }
+
+        /// <summary>
+        /// Converts a numeric representation of the date (number of days after the time origin) to a 
DateTime structure.
+        /// </summary>
+        /// <param name="value">
+        /// The number of days after the time origin.
+        /// </param>
+        /// <returns>
+        /// A date/time structure.
+        /// </returns>
+        public static DateTime ToDateTime(double value)
+        {
+            if (double.IsNaN(value))
+            {
+                return new DateTime();
+            }
+
+            return timeOrigin.AddDays(value - 1);
+        }
+
+        /// <summary>
+        /// Converts a DateTime to days after the time origin.
+        /// </summary>
+        /// <param name="value">
+        /// The date/time structure.
+        /// </param>
+        /// <returns>
+        /// The number of days after the time origin.
+        /// </returns>
+        public static double ToDouble(DateTime value)
+        {
+            var span = value - timeOrigin;
+            return span.TotalDays + 1;
+        }
+
+        /// <summary>
+        /// Formats the specified value by the axis' ActualStringFormat.
+        /// </summary>
+        /// <param name="x">
+        /// The x.
+        /// </param>
+        /// <returns>
+        /// The formatted DateTime value
+        /// </returns>
+        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);
+        }
+
+        /// <summary>
+        /// Gets the tick values.
+        /// </summary>
+        /// <param name="majorLabelValues">
+        /// The major label values.
+        /// </param>
+        /// <param name="majorTickValues">
+        /// The major tick values.
+        /// </param>
+        /// <param name="minorTickValues">
+        /// The minor tick values.
+        /// </param>
+        public override void GetTickValues(
+            out IList<double> majorLabelValues, out IList<double> majorTickValues, out IList<double> 
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;
+        }
+
+        /// <summary>
+        /// 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.
+        /// </summary>
+        /// <param name="x">
+        /// The coordinate.
+        /// </param>
+        /// <returns>
+        /// The value.
+        /// </returns>
+        public override object GetValue(double x)
+        {
+            var time = ToDateTime(x);
+
+            if (this.TimeZone != null)
+            {
+                time = TimeZoneInfo.ConvertTime(time, this.TimeZone);
+            }
+
+            return time;
+        }
+
+        /// <summary>
+        /// Updates the intervals.
+        /// </summary>
+        /// <param name="plotArea">
+        /// The plot area.
+        /// </param>
+        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;
+            }
+        }
+
+        /// <summary>
+        /// Calculates the actual interval.
+        /// </summary>
+        /// <param name="availableSize">
+        /// Size of the available area.
+        /// </param>
+        /// <param name="maxIntervalSize">
+        /// Maximum length of the intervals.
+        /// </param>
+        /// <returns>
+        /// The calculate actual interval.
+        /// </returns>
+        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;
+        }
+
+        /// <summary>
+        /// Creates the date tick values.
+        /// </summary>
+        /// <param name="min">
+        /// The min.
+        /// </param>
+        /// <param name="max">
+        /// The max.
+        /// </param>
+        /// <param name="step">
+        /// The step.
+        /// </param>
+        /// <param name="intervalType">
+        /// Type of the interval.
+        /// </param>
+        /// <returns>
+        /// Date tick values.
+        /// </returns>
+        private IList<double> 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>();
+            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;
+        }
+
+        /// <summary>
+        /// Creates date/time tick values.
+        /// </summary>
+        /// <param name="min">
+        /// The min.
+        /// </param>
+        /// <param name="max">
+        /// The max.
+        /// </param>
+        /// <param name="interval">
+        /// The interval.
+        /// </param>
+        /// <param name="intervalType">
+        /// The interval type.
+        /// </param>
+        /// DateTime tick values.
+        /// <returns>
+        /// DateTime tick values.
+        /// </returns>
+        private IList<double> 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);
+        }
+
+        /// <summary>
+        /// Gets the week number for the specified date.
+        /// </summary>
+        /// <param name="date">
+        /// The date.
+        /// </param>
+        /// <returns>
+        /// The week number for the current culture.
+        /// </returns>
+        private int GetWeek(DateTime date)
+        {
+            return this.ActualCulture.Calendar.GetWeekOfYear(date, this.CalendarWeekRule, 
this.FirstDayOfWeek);
+        }
+    }
+}
\ No newline at end of file
diff --git a/oxyplot/OxyPlot/Axes/DateTimeIntervalType.cs b/oxyplot/OxyPlot/Axes/DateTimeIntervalType.cs
new file mode 100644
index 0000000..2505608
--- /dev/null
+++ b/oxyplot/OxyPlot/Axes/DateTimeIntervalType.cs
@@ -0,0 +1,87 @@
+// 
--------------------------------------------------------------------------------------------------------------------
+// <copyright file="DateTimeIntervalType.cs" company="OxyPlot">
+//   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.
+// </copyright>
+// <summary>
+//   Defines the date time interval for DateTimeAxis.
+// </summary>
+// 
--------------------------------------------------------------------------------------------------------------------
+namespace OxyPlot.Axes
+{
+    /// <summary>
+    /// Specifies the date time interval for <see cref="DateTimeAxis"/>.
+    /// </summary>
+    public enum DateTimeIntervalType
+    {
+        /// <summary>
+        /// Automatically determine interval.
+        /// </summary>
+        Auto = 0,
+
+        /// <summary>
+        /// Manual definition of intervals.
+        /// </summary>
+        Manual = 1,
+
+        /// <summary>
+        /// Interval type is milliseconds.
+        /// </summary>
+        Milliseconds = 2,
+
+        /// <summary>
+        /// Interval type is seconds.
+        /// </summary>
+        Seconds = 3,
+
+        /// <summary>
+        /// Interval type is minutes.
+        /// </summary>
+        Minutes = 4,
+
+        /// <summary>
+        /// Interval type is hours.
+        /// </summary>
+        Hours = 5,
+
+        /// <summary>
+        /// Interval type is days.
+        /// </summary>
+        Days = 6,
+
+        /// <summary>
+        /// Interval type is weeks.
+        /// </summary>
+        Weeks = 7,
+
+        /// <summary>
+        /// Interval type is months.
+        /// </summary>
+        Months = 8,
+
+        /// <summary>
+        /// Interval type is years.
+        /// </summary>
+        Years = 9,
+    }
+}
\ No newline at end of file
diff --git a/oxyplot/OxyPlot/Axes/LinearAxis.cs b/oxyplot/OxyPlot/Axes/LinearAxis.cs
new file mode 100644
index 0000000..baa1159
--- /dev/null
+++ b/oxyplot/OxyPlot/Axes/LinearAxis.cs
@@ -0,0 +1,164 @@
+// 
--------------------------------------------------------------------------------------------------------------------
+// <copyright file="LinearAxis.cs" company="OxyPlot">
+//   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.
+// </copyright>
+// <summary>
+//   Represents an axis with linear scale.
+// </summary>
+// 
--------------------------------------------------------------------------------------------------------------------
+namespace OxyPlot.Axes
+{
+    /// <summary>
+    /// Represents an axis with linear scale.
+    /// </summary>
+    public class LinearAxis : Axis
+    {
+        /// <summary>
+        /// Initializes a new instance of the <see cref="LinearAxis"/> class.
+        /// </summary>
+        public LinearAxis()
+        {
+            this.FractionUnit = 1.0;
+            this.FractionUnitSymbol = null;
+            this.FormatAsFractions = false;
+        }
+
+        /// <summary>
+        /// Initializes a new instance of the <see cref="LinearAxis"/> class.
+        /// </summary>
+        /// <param name="pos">
+        /// The pos.
+        /// </param>
+        /// <param name="title">
+        /// The title.
+        /// </param>
+        public LinearAxis(AxisPosition pos, string title)
+            : this()
+        {
+            this.Position = pos;
+            this.Title = title;
+        }
+
+        /// <summary>
+        /// Initializes a new instance of the <see cref="LinearAxis"/> class.
+        /// </summary>
+        /// <param name="pos">
+        /// The pos.
+        /// </param>
+        /// <param name="minimum">
+        /// The minimum.
+        /// </param>
+        /// <param name="maximum">
+        /// The maximum.
+        /// </param>
+        /// <param name="title">
+        /// The title.
+        /// </param>
+        public LinearAxis(
+            AxisPosition pos, double minimum = double.NaN, double maximum = double.NaN, string title = null)
+            : this(pos, minimum, maximum, double.NaN, double.NaN, title)
+        {
+        }
+
+        /// <summary>
+        /// Initializes a new instance of the <see cref="LinearAxis"/> class.
+        /// </summary>
+        /// <param name="pos">
+        /// The pos.
+        /// </param>
+        /// <param name="minimum">
+        /// The minimum.
+        /// </param>
+        /// <param name="maximum">
+        /// The maximum.
+        /// </param>
+        /// <param name="majorStep">
+        /// The major step.
+        /// </param>
+        /// <param name="minorStep">
+        /// The minor step.
+        /// </param>
+        /// <param name="title">
+        /// The title.
+        /// </param>
+        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;
+        }
+
+        /// <summary>
+        /// Gets or sets a value indicating whether to format numbers as fractions.
+        /// </summary>
+        public bool FormatAsFractions { get; set; }
+
+        /// <summary>
+        /// Gets or sets the fraction unit. Remember to set FormatAsFractions to true.
+        /// </summary>
+        /// <value> The fraction unit. </value>
+        public double FractionUnit { get; set; }
+
+        /// <summary>
+        /// 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.
+        /// </summary>
+        /// <value> The fraction unit symbol. </value>
+        public string FractionUnitSymbol { get; set; }
+
+        /// <summary>
+        /// Formats the value to be used on the axis.
+        /// </summary>
+        /// <param name="x">
+        /// The value.
+        /// </param>
+        /// <returns>
+        /// The formatted value.
+        /// </returns>
+        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);
+        }
+
+        /// <summary>
+        /// Determines whether the axis is used for X/Y values.
+        /// </summary>
+        /// <returns>
+        /// <c>true</c> if it is an XY axis; otherwise, <c>false</c> .
+        /// </returns>
+        public override bool IsXyAxis()
+        {
+            return true;
+        }
+
+    }
+}
\ No newline at end of file
diff --git a/oxyplot/OxyPlot/Axes/LogarithmicAxis.cs b/oxyplot/OxyPlot/Axes/LogarithmicAxis.cs
new file mode 100644
index 0000000..012f2a2
--- /dev/null
+++ b/oxyplot/OxyPlot/Axes/LogarithmicAxis.cs
@@ -0,0 +1,406 @@
+// 
--------------------------------------------------------------------------------------------------------------------
+// <copyright file="LogarithmicAxis.cs" company="OxyPlot">
+//   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.
+// </copyright>
+// <summary>
+//   Represents an axis with logarithmic scale.
+// </summary>
+// 
--------------------------------------------------------------------------------------------------------------------
+namespace OxyPlot.Axes
+{
+    using System;
+    using System.Collections.Generic;
+    using System.Diagnostics;
+
+    /// <summary>
+    /// Represents an axis with logarithmic scale.
+    /// </summary>
+    /// <remarks>
+    /// See http://en.wikipedia.org/wiki/Logarithmic_scale.
+    /// </remarks>
+    public class LogarithmicAxis : Axis
+    {
+        /// <summary>
+        /// Initializes a new instance of the <see cref = "LogarithmicAxis" /> class.
+        /// </summary>
+        public LogarithmicAxis()
+        {
+            this.PowerPadding = true;
+            this.Base = 10;
+            this.FilterMinValue = 0;
+        }
+
+        /// <summary>
+        /// Initializes a new instance of the <see cref="LogarithmicAxis"/> class.
+        /// </summary>
+        /// <param name="pos">
+        /// The position.
+        /// </param>
+        /// <param name="title">
+        /// The title.
+        /// </param>
+        public LogarithmicAxis(AxisPosition pos, string title)
+            : this()
+        {
+            this.Position = pos;
+            this.Title = title;
+        }
+
+        /// <summary>
+        /// Initializes a new instance of the <see cref="LogarithmicAxis"/> class.
+        /// </summary>
+        /// <param name="position">
+        /// The position.
+        /// </param>
+        /// <param name="minimum">
+        /// The minimum.
+        /// </param>
+        /// <param name="maximum">
+        /// The maximum.
+        /// </param>
+        /// <param name="title">
+        /// The title.
+        /// </param>
+        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;
+        }
+
+        /// <summary>
+        /// Gets or sets the logarithmic base (normally 10).
+        /// </summary>
+        /// <remarks>
+        /// See http://en.wikipedia.org/wiki/Logarithm.
+        /// </remarks>
+        /// <value>The logarithmic base.</value>
+        public double Base { get; set; }
+
+        /// <summary>
+        /// Gets or sets a value indicating whether the ActualMaximum and ActualMinimum values should be 
padded to the nearest power of the Base.
+        /// </summary>
+        public bool PowerPadding { get; set; }
+
+        /// <summary>
+        /// Coerces the actual maximum and minimum values.
+        /// </summary>
+        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();
+        }
+
+        /// <summary>
+        /// Gets the coordinates used to draw ticks and tick labels (numbers or category names).
+        /// </summary>
+        /// <param name="majorLabelValues">
+        /// The major label values.
+        /// </param>
+        /// <param name="majorTickValues">
+        /// The major tick values.
+        /// </param>
+        /// <param name="minorTickValues">
+        /// The minor tick values.
+        /// </param>
+        public override void GetTickValues(
+            out IList<double> majorLabelValues, out IList<double> majorTickValues, out IList<double> 
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<double>();
+            minorTickValues = new List<double>();
+
+            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;
+            }
+        }
+
+        /// <summary>
+        /// Determines whether the specified value is valid.
+        /// </summary>
+        /// <param name="value">
+        /// The value.
+        /// </param>
+        /// <returns>
+        /// <c>true</c> if the specified value is valid; otherwise, <c>false</c>.
+        /// </returns>
+        public override bool IsValidValue(double value)
+        {
+            return value > 0 && base.IsValidValue(value);
+        }
+
+        /// <summary>
+        /// Determines whether the axis is used for X/Y values.
+        /// </summary>
+        /// <returns>
+        /// <c>true</c> if it is an XY axis; otherwise, <c>false</c> .
+        /// </returns>
+        public override bool IsXyAxis()
+        {
+            return true;
+        }
+
+        /// <summary>
+        /// Pans the specified axis.
+        /// </summary>
+        /// <param name="ppt">
+        /// The previous point (screen coordinates).
+        /// </param>
+        /// <param name="cpt">
+        /// The current point (screen coordinates).
+        /// </param>
+        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));
+        }
+
+        /// <summary>
+        /// Transforms the specified coordinate to screen coordinates.
+        /// </summary>
+        /// <param name="x">
+        /// The value.
+        /// </param>
+        /// <returns>
+        /// The transformed value (screen coordinate).
+        /// </returns>
+        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;
+        }
+
+        /// <summary>
+        /// Zooms the axis at the specified coordinate.
+        /// </summary>
+        /// <param name="factor">
+        /// The zoom factor.
+        /// </param>
+        /// <param name="x">
+        /// The coordinate to zoom at.
+        /// </param>
+        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);
+        }
+
+        /// <summary>
+        /// Applies a transformation after the inverse transform of the value. This is used in logarithmic 
axis.
+        /// </summary>
+        /// <param name="x">The value to transform.</param>
+        /// <returns>
+        /// The transformed value.
+        /// </returns>
+        internal override double PostInverseTransform(double x)
+        {
+            return Math.Exp(x);
+        }
+
+        /// <summary>
+        /// Applies a transformation before the transform the value. This is used in logarithmic axis.
+        /// </summary>
+        /// <param name="x">The value to transform.</param>
+        /// <returns>
+        /// The transformed value.
+        /// </returns>
+        internal override double PreTransform(double x)
+        {
+            Debug.Assert(x > 0, "Value should be positive.");
+
+            if (x <= 0)
+            {
+                return 0;
+            }
+
+            return Math.Log(x);
+        }
+
+        /// <summary>
+        /// 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'.
+        /// </summary>
+        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 --git a/oxyplot/OxyPlot/Axes/MagnitudeAxis.cs b/oxyplot/OxyPlot/Axes/MagnitudeAxis.cs
new file mode 100644
index 0000000..7bfe21d
--- /dev/null
+++ b/oxyplot/OxyPlot/Axes/MagnitudeAxis.cs
@@ -0,0 +1,205 @@
+// 
--------------------------------------------------------------------------------------------------------------------
+// <copyright file="MagnitudeAxis.cs" company="OxyPlot">
+//   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.
+// </copyright>
+// <summary>
+//   Represents a magnitude axis for polar plots.
+// </summary>
+// 
--------------------------------------------------------------------------------------------------------------------
+namespace OxyPlot.Axes
+{
+    using System;
+
+    /// <summary>
+    /// Represents a magnitude axis for polar plots.
+    /// </summary>
+    public class MagnitudeAxis : LinearAxis
+    {
+        /// <summary>
+        /// Initializes a new instance of the <see cref="MagnitudeAxis"/> class.
+        /// </summary>
+        public MagnitudeAxis()
+        {
+            this.Position = AxisPosition.Bottom;
+            this.IsPanEnabled = false;
+            this.IsZoomEnabled = false;
+
+            this.MajorGridlineStyle = LineStyle.Solid;
+            this.MinorGridlineStyle = LineStyle.Solid;
+        }
+
+        /// <summary>
+        /// Initializes a new instance of the <see cref="MagnitudeAxis"/> class.
+        /// </summary>
+        /// <param name="minimum">
+        /// The minimum.
+        /// </param>
+        /// <param name="maximum">
+        /// The maximum.
+        /// </param>
+        /// <param name="majorStep">
+        /// The major step.
+        /// </param>
+        /// <param name="minorStep">
+        /// The minor step.
+        /// </param>
+        /// <param name="title">
+        /// The title.
+        /// </param>
+        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;
+        }
+
+        /// <summary>
+        /// Gets or sets the midpoint (screen coordinates) of the plot area. This is used by polar 
coordinate systems.
+        /// </summary>
+        internal ScreenPoint MidPoint { get; set; }
+
+        /// <summary>
+        /// Inverse transform the specified screen point.
+        /// </summary>
+        /// <param name="x">
+        /// The x coordinate.
+        /// </param>
+        /// <param name="y">
+        /// The y coordinate.
+        /// </param>
+        /// <param name="yaxis">
+        /// The y-axis.
+        /// </param>
+        /// <returns>
+        /// The data point.
+        /// </returns>
+        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);
+        }
+
+        /// <summary>
+        /// Determines whether the axis is used for X/Y values.
+        /// </summary>
+        /// <returns>
+        /// <c>true</c> if it is an XY axis; otherwise, <c>false</c> .
+        /// </returns>
+        public override bool IsXyAxis()
+        {
+            return false;
+        }
+
+        /// <summary>
+        /// Renders the axis on the specified render context.
+        /// </summary>
+        /// <param name="rc">The render context.</param>
+        /// <param name="model">The model.</param>
+        /// <param name="axisLayer">The rendering order.</param>
+        /// <param name="pass"></param>
+        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);
+        }
+
+        /// <summary>
+        /// Transforms the specified point to screen coordinates.
+        /// </summary>
+        /// <param name="x">
+        /// The x value (for the current axis).
+        /// </param>
+        /// <param name="y">
+        /// The y value.
+        /// </param>
+        /// <param name="yaxis">
+        /// The y axis.
+        /// </param>
+        /// <returns>
+        /// The transformed point.
+        /// </returns>
+        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)));
+        }
+
+        /// <summary>
+        /// Updates the scale and offset properties of the transform from the specified boundary rectangle.
+        /// </summary>
+        /// <param name="bounds">
+        /// The bounds.
+        /// </param>
+        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 --git a/oxyplot/OxyPlot/Axes/RangeAxis.cs b/oxyplot/OxyPlot/Axes/RangeAxis.cs
new file mode 100644
index 0000000..66b945e
--- /dev/null
+++ b/oxyplot/OxyPlot/Axes/RangeAxis.cs
@@ -0,0 +1,469 @@
+// 
--------------------------------------------------------------------------------------------------------------------
+// <copyright file="RangeAxis.cs" company="OxyPlot">
+//   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.
+// </copyright>
+// <summary>
+//   Updates the minor/major step intervals if they are undefined.
+// </summary>
+// 
--------------------------------------------------------------------------------------------------------------------
+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<double> majorValues, out ICollection<double> 
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<double> 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<double>();
+            // 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;
+        }
+
+        /// <summary>
+        /// Updates the minor/major step intervals if they are undefined.
+        /// </summary>
+        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;
+        }
+
+        /// <summary>
+        /// Returns the actual interval to use to determine which values are
+        /// displayed in the axis.
+        /// </summary>
+        /// <param name="availableSize">The available size.</param>
+        /// <returns>Actual interval to use to determine which values are
+        /// displayed in the axis.
+        /// </returns>
+        private double CalculateActualInterval2(double availableSize, double maxIntervalSize)
+        {
+            Func<double, double> Exponent = x => Math.Ceiling(Math.Log(x, 10));
+            Func<double, double> 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;
+        }
+
+        /// <summary>
+        /// Removes the noise from double math.
+        /// </summary>
+        /// <param name="value">The value.</param>
+        /// <returns>A double without a noise.</returns>
+        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 --git a/oxyplot/OxyPlot/Axes/TickStyle.cs b/oxyplot/OxyPlot/Axes/TickStyle.cs
new file mode 100644
index 0000000..45a6a03
--- /dev/null
+++ b/oxyplot/OxyPlot/Axes/TickStyle.cs
@@ -0,0 +1,57 @@
+// 
--------------------------------------------------------------------------------------------------------------------
+// <copyright file="TickStyle.cs" company="OxyPlot">
+//   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.
+// </copyright>
+// <summary>
+//   Tick styles.
+// </summary>
+// 
--------------------------------------------------------------------------------------------------------------------
+namespace OxyPlot.Axes
+{
+    /// <summary>
+    /// Specifies the style of axis ticks.
+    /// </summary>
+    public enum TickStyle
+    {
+        /// <summary>
+        /// The ticks are rendered crossing the axis line.
+        /// </summary>
+        Crossing,
+
+        /// <summary>
+        /// The ticks are rendered inside of the plot area.
+        /// </summary>
+        Inside,
+
+        /// <summary>
+        /// The ticks are rendered Outside the plot area.
+        /// </summary>
+        Outside,
+
+        /// <summary>
+        /// The ticks are not rendered.
+        /// </summary>
+        None
+    }
+}
\ No newline at end of file
diff --git a/oxyplot/OxyPlot/Axes/TimeAxis.cs b/oxyplot/OxyPlot/Axes/TimeAxis.cs
new file mode 100644
index 0000000..1e5ca68
--- /dev/null
+++ b/oxyplot/OxyPlot/Axes/TimeAxis.cs
@@ -0,0 +1,120 @@
+// 
--------------------------------------------------------------------------------------------------------------------
+// <copyright file="TimeAxis.cs" company="OxyPlot">
+//   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.
+// </copyright>
+// <summary>
+//   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
+// </summary>
+// 
--------------------------------------------------------------------------------------------------------------------
+using System;
+using System.Linq;
+
+namespace OxyPlot
+{
+    /// <summary>
+    /// 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
+    /// </summary>
+    public class TimeAxis : LinearAxis
+    {
+        /// <summary>
+        /// Initializes a new instance of the <see cref = "TimeAxis" /> class.
+        /// </summary>
+        /// <param name = "pos">The position.</param>
+        /// <param name = "title">The axis title.</param>
+        /// <param name = "format">The string format for the axis values.</param>
+        public TimeAxis(AxisPosition pos, string title = null, string format = "m:ss")
+            : base(pos, title)
+        {
+            StringFormat = format;
+        }
+
+        /// <summary>
+        /// Initializes a new instance of the <see cref = "TimeAxis" /> class.
+        /// </summary>
+        /// <param name = "pos">The position.</param>
+        /// <param name = "min">The min.</param>
+        /// <param name = "max">The max.</param>
+        /// <param name = "title">The axis title.</param>
+        /// <param name = "format">The string format for the axis values.</param>
+        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;
+        }
+
+        /// <summary>
+        /// Formats the value.
+        /// </summary>
+        /// <param name = "x">The x.</param>
+        /// <returns></returns>
+        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 --git a/oxyplot/OxyPlot/Axes/TimeSpanAxis.cs b/oxyplot/OxyPlot/Axes/TimeSpanAxis.cs
new file mode 100644
index 0000000..4699ba3
--- /dev/null
+++ b/oxyplot/OxyPlot/Axes/TimeSpanAxis.cs
@@ -0,0 +1,197 @@
+// 
--------------------------------------------------------------------------------------------------------------------
+// <copyright file="TimeSpanAxis.cs" company="OxyPlot">
+//   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.
+// </copyright>
+// <summary>
+//   Time axis.
+// </summary>
+// 
--------------------------------------------------------------------------------------------------------------------
+namespace OxyPlot.Axes
+{
+    using System;
+    using System.Linq;
+
+    /// <summary>
+    /// Represents an axis presenting <see cref="System.TimeSpan"/> values.
+    /// </summary>
+    /// <remarks>
+    /// 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
+    /// </remarks>
+    public class TimeSpanAxis : LinearAxis
+    {
+        /// <summary>
+        /// Initializes a new instance of the <see cref = "TimeSpanAxis" /> class.
+        /// </summary>
+        public TimeSpanAxis()
+        {
+        }
+
+        /// <summary>
+        /// Initializes a new instance of the <see cref="TimeSpanAxis"/> class.
+        /// </summary>
+        /// <param name="pos">
+        /// The position.
+        /// </param>
+        /// <param name="title">
+        /// The axis title.
+        /// </param>
+        /// <param name="format">
+        /// The string format for the axis values.
+        /// </param>
+        public TimeSpanAxis(AxisPosition pos, string title = null, string format = "m:ss")
+            : base(pos, title)
+        {
+            this.StringFormat = format;
+        }
+
+        /// <summary>
+        /// Initializes a new instance of the <see cref="TimeSpanAxis"/> class.
+        /// </summary>
+        /// <param name="pos">
+        /// The position.
+        /// </param>
+        /// <param name="min">
+        /// The min.
+        /// </param>
+        /// <param name="max">
+        /// The max.
+        /// </param>
+        /// <param name="title">
+        /// The axis title.
+        /// </param>
+        /// <param name="format">
+        /// The string format for the axis values.
+        /// </param>
+        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;
+        }
+
+        /// <summary>
+        /// Converts a time span to a double.
+        /// </summary>
+        /// <param name="s">
+        /// The time span.
+        /// </param>
+        /// <returns>
+        /// A double value.
+        /// </returns>
+        public static double ToDouble(TimeSpan s)
+        {
+            return s.TotalSeconds;
+        }
+
+        /// <summary>
+        /// Converts a double to a time span.
+        /// </summary>
+        /// <param name="value">
+        /// The value.
+        /// </param>
+        /// <returns>
+        /// A time span.
+        /// </returns>
+        public static TimeSpan ToTimeSpan(double value)
+        {
+            return TimeSpan.FromSeconds(value);
+        }
+
+        /// <summary>
+        /// Formats the value.
+        /// </summary>
+        /// <param name="x">
+        /// The x.
+        /// </param>
+        /// <returns>
+        /// The format value.
+        /// </returns>
+        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;
+        }
+
+        /// <summary>
+        /// 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.
+        /// </summary>
+        /// <param name="x">The coordinate.</param>
+        /// <returns>
+        /// The value.
+        /// </returns>
+        public override object GetValue(double x)
+        {
+            return TimeSpan.FromSeconds(x);
+        }
+
+        /// <summary>
+        /// Calculates the actual interval.
+        /// </summary>
+        /// <param name="availableSize">Size of the available area.</param>
+        /// <param name="maxIntervalSize">Maximum length of the intervals.</param>
+        /// <returns>
+        /// The calculate actual interval.
+        /// </returns>
+        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 --git a/oxyplot/OxyPlot/ClassDiagrams/PlotModel.cd b/oxyplot/OxyPlot/ClassDiagrams/PlotModel.cd
new file mode 100644
index 0000000..c9a1c11
--- /dev/null
+++ b/oxyplot/OxyPlot/ClassDiagrams/PlotModel.cd
@@ -0,0 +1,276 @@
+<?xml version="1.0" encoding="utf-8"?>
+<ClassDiagram MajorVersion="1" MinorVersion="1">
+  <Class Name="OxyPlot.PlotModel" Collapsed="true">
+    <Position X="2.5" Y="3.25" Width="2.75" />
+    <Compartments>
+      <Compartment Name="Methods" Collapsed="true" />
+    </Compartments>
+    <TypeIdentifier>
+      <HashCode>EBZwcA2UaBI/BUK9ZBHDJRgBY1uVERMI45sgpP2SPzE=</HashCode>
+      <FileName>PlotModel\PlotModel.cs</FileName>
+    </TypeIdentifier>
+  </Class>
+  <Class Name="OxyPlot.LineSeries" Collapsed="true">
+    <Position X="9.75" Y="7.75" Width="1.5" />
+    <TypeIdentifier>
+      <HashCode>AAQCAAEIAiAAAGCAABBAAAAhRCAMEAAAADAAggACIgA=</HashCode>
+      <FileName>Series\LineSeries.cs</FileName>
+    </TypeIdentifier>
+  </Class>
+  <Class Name="OxyPlot.DataPointSeries" Collapsed="true">
+    <Position X="9.75" Y="6.5" Width="1.5" />
+    <TypeIdentifier>
+      <HashCode>IAAAAAyAEAABgAAAACACAAAABAAEAAAAAAAAAgAAAAA=</HashCode>
+      <FileName>Series\DataPointSeries.cs</FileName>
+    </TypeIdentifier>
+  </Class>
+  <Class Name="OxyPlot.AreaSeries" Collapsed="true">
+    <Position X="11" Y="9" Width="1.5" />
+    <TypeIdentifier>
+      <HashCode>AgAAAAEAEAAAAIAAAAAACAAAAAAECAAAABMAAgIAAAA=</HashCode>
+      <FileName>Series\AreaSeries.cs</FileName>
+    </TypeIdentifier>
+  </Class>
+  <Class Name="OxyPlot.FunctionSeries" Collapsed="true">
+    <Position X="9.25" Y="9" Width="1.5" />
+    <TypeIdentifier>
+      <HashCode>AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA=</HashCode>
+      <FileName>Series\FunctionSeries.cs</FileName>
+    </TypeIdentifier>
+  </Class>
+  <Class Name="OxyPlot.LinearAxis" Collapsed="true">
+    <Position X="12" Y="2" Width="1.5" />
+    <TypeIdentifier>
+      <HashCode>AAQAAAAAAQAAACAAAAAAAAAAAAAAAAAAAAEAAAAAQAA=</HashCode>
+      <FileName>Axes\LinearAxis.cs</FileName>
+    </TypeIdentifier>
+  </Class>
+  <Class Name="OxyPlot.LogarithmicAxis" Collapsed="true">
+    <Position X="14.25" Y="2" Width="1.5" />
+    <TypeIdentifier>
+      <HashCode>AAAAAAAAAQAAEgAAAIAAABQAAAAAQAAAAAAAABQAQAA=</HashCode>
+      <FileName>Axes\LogarithmicAxis.cs</FileName>
+    </TypeIdentifier>
+  </Class>
+  <Class Name="OxyPlot.TimeSpanAxis" Collapsed="true">
+    <Position X="12" Y="3.5" Width="1.5" />
+    <TypeIdentifier>
+      <HashCode>AAAAAAAAIAAAAAEAAAAAAAAAAAEAAAAAABEAAAAAAAA=</HashCode>
+      <FileName>Axes\TimeSpanAxis.cs</FileName>
+    </TypeIdentifier>
+  </Class>
+  <Class Name="OxyPlot.CategoryAxis" Collapsed="true">
+    <Position X="14.25" Y="3.5" Width="1.5" />
+    <TypeIdentifier>
+      <HashCode>AIAAEAABMAAEEAgAIBAAAFAAAAAEnAAAAAEgAJAAABE=</HashCode>
+      <FileName>Axes\CategoryAxis.cs</FileName>
+    </TypeIdentifier>
+  </Class>
+  <Class Name="OxyPlot.DateTimeAxis" Collapsed="true">
+    <Position X="16.25" Y="3.5" Width="1.5" />
+    <TypeIdentifier>
+      <HashCode>gAIAAAAAIAAkGAEBAAAAIAAAggAAAAAAABEAAAAVAAA=</HashCode>
+      <FileName>Axes\DateTimeAxis.cs</FileName>
+    </TypeIdentifier>
+  </Class>
+  <Class Name="OxyPlot.Annotation" Collapsed="true">
+    <Position X="25" Y="3.25" Width="1.5" />
+    <TypeIdentifier>
+      <HashCode>gAAQAAAFAAAAAAAAAEAAQAQAAAAAAAAEABAADAACAAA=</HashCode>
+      <FileName>Annotations\Annotation.cs</FileName>
+    </TypeIdentifier>
+  </Class>
+  <Class Name="OxyPlot.LineAnnotation" Collapsed="true">
+    <Position X="25" Y="4.25" Width="1.5" />
+    <TypeIdentifier>
+      <HashCode>BAAQEAAAACBwAIAAABgAgAAAEAAAAAAACTAAkgAgYGA=</HashCode>
+      <FileName>Annotations\LineAnnotation.cs</FileName>
+    </TypeIdentifier>
+  </Class>
+  <Class Name="OxyPlot.BarSeries" Collapsed="true">
+    <Position X="1.5" Y="10.25" Width="1.5" />
+    <TypeIdentifier>
+      <HashCode>CAAAAAgAIAQAAAAAAAAAAAAAAIAAAABAAAAAEAAAAAA=</HashCode>
+      <FileName>Series\BarSeries\BarSeries.cs</FileName>
+    </TypeIdentifier>
+  </Class>
+  <Class Name="OxyPlot.XYAxisSeries" Collapsed="true">
+    <Position X="6.5" Y="5.25" Width="1.5" />
+    <TypeIdentifier>
+      <HashCode>sAAQAAE1WAAAAAAAAEAAQAQAAAAEAAAAABAUACACEAA=</HashCode>
+      <FileName>Series\XYAxisSeries.cs</FileName>
+    </TypeIdentifier>
+  </Class>
+  <Class Name="OxyPlot.CandleStickSeries" Collapsed="true">
+    <Position X="13.5" Y="7.75" Width="1.5" />
+    <TypeIdentifier>
+      <HashCode>AAAAAAEAAAAAAAAAAAAAAAAAAAAAAAAAABAAAAAABAA=</HashCode>
+      <FileName>Series\CandleStickSeries.cs</FileName>
+    </TypeIdentifier>
+  </Class>
+  <Class Name="OxyPlot.HighLowSeries" Collapsed="true">
+    <Position X="13.5" Y="6.5" Width="1.5" />
+    <TypeIdentifier>
+      <HashCode>AAAAAAkBECABCAAAABgAAAQABAQEAAABAHAAggACAAA=</HashCode>
+      <FileName>Series\HighLowSeries.cs</FileName>
+    </TypeIdentifier>
+  </Class>
+  <Class Name="OxyPlot.ItemsSeries" Collapsed="true">
+    <Position X="6.5" Y="4.25" Width="1.5" />
+    <TypeIdentifier>
+      <HashCode>AAAAAAAAAAAAAEAAAAAAAAAAAAAAAAAAAAAAAIIAAAA=</HashCode>
+      <FileName>Series\ItemsSeries.cs</FileName>
+    </TypeIdentifier>
+  </Class>
+  <Class Name="OxyPlot.PieSeries" Collapsed="true">
+    <Position X="8.5" Y="4.25" Width="1.5" />
+    <TypeIdentifier>
+      <HashCode>AQAQAAEAWGAYACAIAAAAAAAgAAgEICJAgpQFAoCCAAI=</HashCode>
+      <FileName>Series\PieSeries.cs</FileName>
+    </TypeIdentifier>
+  </Class>
+  <Class Name="OxyPlot.ScatterSeries" Collapsed="true">
+    <Position X="11.75" Y="7.75" Width="1.5" />
+    <TypeIdentifier>
+      <HashCode>AARQAAEIEAAAAEgQAAAIAAAgACBEAAAEABAwAgQDAgA=</HashCode>
+      <FileName>Series\ScatterSeries.cs</FileName>
+    </TypeIdentifier>
+  </Class>
+  <Class Name="OxyPlot.StairStepSeries" Collapsed="true">
+    <Position X="7.5" Y="9" Width="1.5" />
+    <TypeIdentifier>
+      <HashCode>AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAABAAAgAAAAA=</HashCode>
+      <FileName>Series\StairStepSeries.cs</FileName>
+    </TypeIdentifier>
+  </Class>
+  <Class Name="OxyPlot.StemSeries" Collapsed="true">
+    <Position X="12.75" Y="9" Width="1.5" />
+    <TypeIdentifier>
+      <HashCode>AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAABAAAgAAQAA=</HashCode>
+      <FileName>Series\StemSeries.cs</FileName>
+    </TypeIdentifier>
+  </Class>
+  <Class Name="OxyPlot.AngleAxis" Collapsed="true">
+    <Position X="18.25" Y="3.5" Width="1.5" />
+    <TypeIdentifier>
+      <HashCode>AAAAAAAAAQAAAAAAAAAAQAQAAAAEAAAAABAAAAAAAAA=</HashCode>
+      <FileName>Axes\AngleAxis.cs</FileName>
+    </TypeIdentifier>
+  </Class>
+  <Class Name="OxyPlot.MagnitudeAxis" Collapsed="true">
+    <Position X="20.25" Y="3.5" Width="1.5" />
+    <TypeIdentifier>
+      <HashCode>AAAAAAAAAQAAAAAAAAAAQAQAAAAEAIAAABAAAAAAAAA=</HashCode>
+      <FileName>Axes\MagnitudeAxis.cs</FileName>
+    </TypeIdentifier>
+  </Class>
+  <Class Name="OxyPlot.Series" Collapsed="true">
+    <Position X="6.5" Y="3.25" Width="1.5" />
+    <TypeIdentifier>
+      <HashCode>AAAQAAEAWABAEEAAAAAAAAAAAAAEAAAAABAkBgISAAA=</HashCode>
+      <FileName>Series\Series.cs</FileName>
+    </TypeIdentifier>
+    <Lollipop Position="0.2" />
+  </Class>
+  <Class Name="OxyPlot.Axis" Collapsed="true">
+    <Position X="13.25" Y="0.5" Width="1.5" />
+    <TypeIdentifier>
+      <HashCode>gEeXCAGRedQgH2V09tJAe5wCkhCEgABEG1cgxZQB4CU=</HashCode>
+      <FileName>Axes\Axis.cs</FileName>
+    </TypeIdentifier>
+  </Class>
+  <Class Name="OxyPlot.ArrowAnnotation" Collapsed="true">
+    <Position X="26.75" Y="4.25" Width="1.5" />
+    <TypeIdentifier>
+      <HashCode>AAQACAAAACBAQAAAQFAAAAAAABAAAAAAgDAAgAAAAAg=</HashCode>
+      <FileName>Annotations\ArrowAnnotation.cs</FileName>
+    </TypeIdentifier>
+  </Class>
+  <Class Name="OxyPlot.PolygonAnnotation" Collapsed="true">
+    <Position X="23.25" Y="4.25" Width="1.5" />
+    <TypeIdentifier>
+      <HashCode>AAAAAAAAACBggAAAABAAAAAAAAAACAAAADAAgAAAAAA=</HashCode>
+      <FileName>Annotations\PolygonAnnotation.cs</FileName>
+    </TypeIdentifier>
+  </Class>
+  <Class Name="OxyPlot.TextAnnotation" Collapsed="true">
+    <Position X="28.5" Y="4.25" Width="1.5" />
+    <TypeIdentifier>
+      <HashCode>AAAAAAAgACBAAIAggAAAAAAAAAgAAAIAABIggAAAgAA=</HashCode>
+      <FileName>Annotations\TextAnnotation.cs</FileName>
+    </TypeIdentifier>
+  </Class>
+  <Class Name="OxyPlot.BarSeriesBase" Collapsed="true">
+    <Position X="2" Y="7.75" Width="1.5" />
+    <TypeIdentifier>
+      <HashCode>BYQAAIEAKCSAACCQAAAAAAABAAgEIBBAAhAUAgoCAAE=</HashCode>
+      <FileName>Series\BarSeries\BarSeriesBase.cs</FileName>
+    </TypeIdentifier>
+    <Lollipop Position="0.2" />
+  </Class>
+  <Class Name="OxyPlot.ColumnSeries" Collapsed="true">
+    <Position X="3.25" Y="10.25" Width="1.5" />
+    <TypeIdentifier>
+      <HashCode>AAAAAAgAIAQAAAAAAEAAAAAAAIAAAABAAAAAEAAAAAA=</HashCode>
+      <FileName>Series\BarSeries\ColumnSeries.cs</FileName>
+    </TypeIdentifier>
+  </Class>
+  <Class Name="OxyPlot.IntervalBarSeries" Collapsed="true">
+    <Position X="3.75" Y="7.75" Width="1.5" />
+    <TypeIdentifier>
+      <HashCode>DQQAAAkBGCSACECAAAAAAAABAIgEIgAAABAUEgoCAAE=</HashCode>
+      <FileName>Series\BarSeries\IntervalBarSeries.cs</FileName>
+    </TypeIdentifier>
+    <Lollipop Position="0.2" />
+  </Class>
+  <Class Name="OxyPlot.RectangleBarSeries" Collapsed="true">
+    <Position X="5.5" Y="6.5" Width="1.75" />
+    <TypeIdentifier>
+      <HashCode>AAAAAAEAECCACACAAAAAAAAAAAgEAAAAABAQAggCAAE=</HashCode>
+      <FileName>Series\BarSeries\RectangleBarSeries.cs</FileName>
+    </TypeIdentifier>
+  </Class>
+  <Class Name="OxyPlot.TornadoBarSeries" Collapsed="true">
+    <Position X="5.5" Y="7.75" Width="1.5" />
+    <TypeIdentifier>
+      <HashCode>DYQAAAsBGCUACEAAAQAgAAABAKgEAoAAABAUEgICAAE=</HashCode>
+      <FileName>Series\BarSeries\TornadoBarSeries.cs</FileName>
+    </TypeIdentifier>
+  </Class>
+  <Class Name="OxyPlot.ColorAxis" Collapsed="true">
+    <Position X="16.25" Y="2" Width="1.5" />
+    <TypeIdentifier>
+      <HashCode>AAAAABAAAQAAAAAAAQIAACAAAAAAAAiAABAAAQAAAAA=</HashCode>
+      <FileName>Axes\ColorAxis.cs</FileName>
+    </TypeIdentifier>
+  </Class>
+  <Class Name="OxyPlot.BarSeriesBase&lt;T&gt;" Collapsed="true">
+    <Position X="2" Y="8.75" Width="1.5" />
+    <TypeIdentifier>
+      <HashCode>AAAAAAAAEAAACEAAAAAAAAAAAAAAAgAAAAAAAAAAAAA=</HashCode>
+      <FileName>Series\BarSeries\BarSeriesBase{T}.cs</FileName>
+    </TypeIdentifier>
+  </Class>
+  <Class Name="OxyPlot.CategorizedSeries" Collapsed="true">
+    <Position X="2" Y="6.5" Width="1.5" />
+    <TypeIdentifier>
+      <HashCode>AAAAAAgAAAAAAAAAAAAAAAAAAIAAAgAAAAAAEAAAAAA=</HashCode>
+      <FileName>Series\BarSeries\CategorizedSeries.cs</FileName>
+    </TypeIdentifier>
+  </Class>
+  <Class Name="OxyPlot.ErrorColumnSeries" Collapsed="true">
+    <Position X="3" Y="11.25" Width="2" />
+    <TypeIdentifier>
+      <HashCode>AAAIAAAAAEAAAAAAAAAAAAAAAAAEABAAAAAAAAAAAAA=</HashCode>
+      <FileName>Series\BarSeries\ErrorColumnSeries.cs</FileName>
+    </TypeIdentifier>
+  </Class>
+  <Interface Name="OxyPlot.ITrackableSeries" Collapsed="true">
+    <Position X="6.5" Y="2" Width="1.5" />
+    <TypeIdentifier>
+      <HashCode>AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAABAAAgAQAAA=</HashCode>
+      <FileName>Series\ITrackableSeries.cs</FileName>
+    </TypeIdentifier>
+  </Interface>
+  <Font Name="Segoe UI" Size="9" />
+</ClassDiagram>
\ No newline at end of file
diff --git a/oxyplot/OxyPlot/ClassDiagrams/Reporting.cd b/oxyplot/OxyPlot/ClassDiagrams/Reporting.cd
new file mode 100644
index 0000000..666ee2b
--- /dev/null
+++ b/oxyplot/OxyPlot/ClassDiagrams/Reporting.cd
@@ -0,0 +1,204 @@
+<?xml version="1.0" encoding="utf-8"?>
+<ClassDiagram MajorVersion="1" MinorVersion="1">
+  <Class Name="OxyPlot.Reporting.TableOfContents" Collapsed="true">
+    <Position X="7.25" Y="12" Width="1.5" />
+    <InheritanceLine Type="OxyPlot.Reporting.ItemsTable" FixedToPoint="true">
+      <Path>
+        <Point X="6.75" Y="11.691" />
+        <Point X="6.75" Y="12.312" />
+        <Point X="7.25" Y="12.312" />
+      </Path>
+    </InheritanceLine>
+    <TypeIdentifier>
+      <HashCode>AAQAAAAAAAAAAAAAAAAAAEAAAAAAAAAAAAAAAABgQAA=</HashCode>
+      <FileName>Reporting\Report\TableOfContents.cs</FileName>
+    </TypeIdentifier>
+  </Class>
+  <Class Name="OxyPlot.Reporting.DrawingFigure" Collapsed="true">
+    <Position X="5.75" Y="8.5" Width="1.5" />
+    <TypeIdentifier>
+      <HashCode>AAAAAAAAAgAAAAAAAAAAAEAAAAgAAAAAAAAAAAAAAAA=</HashCode>
+      <FileName>Reporting\Report\DrawingFigure.cs</FileName>
+    </TypeIdentifier>
+  </Class>
+  <Class Name="OxyPlot.Reporting.Equation" Collapsed="true">
+    <Position X="4.75" Y="5.75" Width="1.5" />
+    <InheritanceLine Type="OxyPlot.Reporting.ReportItem" FixedToPoint="true">
+      <Path>
+        <Point X="3.25" Y="2.312" />
+        <Point X="3.25" Y="6.062" />
+        <Point X="4.75" Y="6.062" />
+      </Path>
+    </InheritanceLine>
+    <TypeIdentifier>
+      <HashCode>AAAAAAAAAgAAAAAAAAAAAEAAAAAAAAAACAAAAAAAAAA=</HashCode>
+      <FileName>Reporting\Report\Equation.cs</FileName>
+    </TypeIdentifier>
+  </Class>
+  <Class Name="OxyPlot.Reporting.Figure" Collapsed="true">
+    <Position X="4.75" Y="7" Width="1.5" />
+    <InheritanceLine Type="OxyPlot.Reporting.ReportItem" FixedToPoint="true">
+      <Path>
+        <Point X="3.25" Y="2.312" />
+        <Point X="3.25" Y="7.312" />
+        <Point X="4.75" Y="7.312" />
+      </Path>
+    </InheritanceLine>
+    <TypeIdentifier>
+      <HashCode>AAAAAAEgAAAIAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA=</HashCode>
+      <FileName>Reporting\Report\Figure.cs</FileName>
+    </TypeIdentifier>
+  </Class>
+  <Class Name="OxyPlot.Reporting.Header" Collapsed="true">
+    <Position X="4.75" Y="3.75" Width="1.5" />
+    <InheritanceLine Type="OxyPlot.Reporting.ReportItem" FixedToPoint="true">
+      <Path>
+        <Point X="3.25" Y="2.312" />
+        <Point X="3.25" Y="4.062" />
+        <Point X="4.75" Y="4.062" />
+      </Path>
+    </InheritanceLine>
+    <TypeIdentifier>
+      <HashCode>AAAAAAAAAAAAAAAEAAAAAEAAAAAAAAABAgAACAAAAAA=</HashCode>
+      <FileName>Reporting\Report\Header.cs</FileName>
+    </TypeIdentifier>
+  </Class>
+  <Class Name="OxyPlot.Reporting.Image" Collapsed="true">
+    <Position X="4" Y="8.5" Width="1.5" />
+    <TypeIdentifier>
+      <HashCode>AAAAAAAAAgAAAAAAAAAAAEAAAAAAAAAAAAAAAAAAAAA=</HashCode>
+      <FileName>Reporting\Report\Image.cs</FileName>
+    </TypeIdentifier>
+  </Class>
+  <Class Name="OxyPlot.Reporting.Paragraph" Collapsed="true">
+    <Position X="4.75" Y="4.75" Width="1.5" />
+    <InheritanceLine Type="OxyPlot.Reporting.ReportItem" FixedToPoint="true">
+      <Path>
+        <Point X="3.25" Y="2.312" />
+        <Point X="3.25" Y="5.062" />
+        <Point X="4.75" Y="5.062" />
+      </Path>
+    </InheritanceLine>
+    <TypeIdentifier>
+      <HashCode>AAAAAAAAAAAAAAAAAAAAAEAAAAAAAAAAAAAACAAAAAA=</HashCode>
+      <FileName>Reporting\Report\Paragraph.cs</FileName>
+    </TypeIdentifier>
+  </Class>
+  <Class Name="OxyPlot.Reporting.PlotFigure" Collapsed="true">
+    <Position X="7.5" Y="8.5" Width="1.5" />
+    <TypeIdentifier>
+      <HashCode>AAAAAAAABAAAAAAAAAAAAEAAAAAAAAAAAAAAAAAAQAA=</HashCode>
+      <FileName>Reporting\Report\PlotFigure.cs</FileName>
+    </TypeIdentifier>
+  </Class>
+  <Class Name="OxyPlot.Reporting.PropertyTable" Collapsed="true">
+    <Position X="7.25" Y="13" Width="1.5" />
+    <InheritanceLine Type="OxyPlot.Reporting.ItemsTable" FixedToPoint="true">
+      <Path>
+        <Point X="6.75" Y="11.691" />
+        <Point X="6.75" Y="13.312" />
+        <Point X="7.25" Y="13.312" />
+      </Path>
+    </InheritanceLine>
+    <TypeIdentifier>
+      <HashCode>AICAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA=</HashCode>
+      <FileName>Reporting\Report\PropertyTable.cs</FileName>
+    </TypeIdentifier>
+  </Class>
+  <Class Name="OxyPlot.Reporting.Report" Collapsed="true">
+    <Position X="4.75" Y="1.75" Width="1.5" />
+    <TypeIdentifier>
+      <HashCode>AAAAAAAAAAAAAEAAgAAAAEAAAAAAAAAAAAAAAAEAAAA=</HashCode>
+      <FileName>Reporting\Report\Report.cs</FileName>
+    </TypeIdentifier>
+  </Class>
+  <Class Name="OxyPlot.Reporting.ReportItem" Collapsed="true">
+    <Position X="2.5" Y="1.75" Width="1.5" />
+    <TypeIdentifier>
+      <HashCode>AAcGAAAAAACCAAAAAAAEAEAAAAAAAAAAAAAAAAELCAA=</HashCode>
+      <FileName>Reporting\Report\ReportItem.cs</FileName>
+    </TypeIdentifier>
+  </Class>
+  <Class Name="OxyPlot.Reporting.ReportSection" Collapsed="true">
+    <Position X="4.75" Y="2.75" Width="1.5" />
+    <InheritanceLine Type="OxyPlot.Reporting.ReportItem" FixedToPoint="true">
+      <Path>
+        <Point X="3.25" Y="2.312" />
+        <Point X="3.25" Y="3.062" />
+        <Point X="4.75" Y="3.062" />
+      </Path>
+    </InheritanceLine>
+    <TypeIdentifier>
+      <HashCode>AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA=</HashCode>
+      <FileName>Reporting\Report\ReportSection.cs</FileName>
+    </TypeIdentifier>
+  </Class>
+  <Class Name="OxyPlot.Reporting.Table" Collapsed="true">
+    <Position X="4.75" Y="10" Width="1.5" />
+    <InheritanceLine Type="OxyPlot.Reporting.ReportItem" FixedToPoint="true">
+      <Path>
+        <Point X="3.25" Y="2.312" />
+        <Point X="3.25" Y="10.312" />
+        <Point X="4.75" Y="10.312" />
+      </Path>
+    </InheritanceLine>
+    <TypeIdentifier>
+      <HashCode>AAQAAAAgAAAAAEAgAAAAAEBAAAAAAAEACAAAAAgAAAA=</HashCode>
+      <FileName>Reporting\Report\Table.cs</FileName>
+    </TypeIdentifier>
+  </Class>
+  <Class Name="OxyPlot.Reporting.HtmlReportWriter" Collapsed="true" BaseTypeListCollapsed="true">
+    <Position X="7.75" Y="2.75" Width="1.5" />
+    <TypeIdentifier>
+      <HashCode>ACAAgAAAAAAgAIQAAAAQAAAAAAoUAABAIEIkAAigAAA=</HashCode>
+      <FileName>Reporting\ReportWriters\HtmlReportWriter.cs</FileName>
+    </TypeIdentifier>
+    <Lollipop Position="0.2" />
+  </Class>
+  <Class Name="OxyPlot.Reporting.LatexReportWriter" Collapsed="true" BaseTypeListCollapsed="true">
+    <Position X="11.25" Y="2.75" Width="1.5" />
+    <TypeIdentifier>
+      <HashCode>ACABgAAAACAsAAQABAAAAAQAAAAAIAAAAEAkAAAiAAA=</HashCode>
+      <FileName>Reporting\ReportWriters\LatexReportWriter.cs</FileName>
+    </TypeIdentifier>
+    <Lollipop Position="0.2" />
+  </Class>
+  <Class Name="OxyPlot.Reporting.TextReportWriter" Collapsed="true" BaseTypeListCollapsed="true">
+    <Position X="9.5" Y="2.75" Width="1.5" />
+    <TypeIdentifier>
+      <HashCode>ICAAgABAAAAgAAQIAAAACIAEAAAAAAAAAEAkAAAgAAA=</HashCode>
+      <FileName>Reporting\ReportWriters\TextReportWriter.cs</FileName>
+    </TypeIdentifier>
+    <Lollipop Position="0.2" />
+  </Class>
+  <Class Name="OxyPlot.Reporting.ItemsTable" Collapsed="true">
+    <Position X="6" Y="11" Width="1.5" />
+    <InheritanceLine Type="OxyPlot.Reporting.Table" FixedToPoint="true">
+      <Path>
+        <Point X="5.5" Y="10.691" />
+        <Point X="5.5" Y="11.312" />
+        <Point X="6" Y="11.312" />
+      </Path>
+    </InheritanceLine>
+    <TypeIdentifier>
+      <HashCode>AAAAAgAAIAAACAAAACgIAEAAAAAAAAAAAAAAAAhAgAA=</HashCode>
+      <FileName>Reporting\Report\ItemsTable.cs</FileName>
+    </TypeIdentifier>
+  </Class>
+  <Class Name="OxyPlot.Reporting.WikiReportWriter" Collapsed="true">
+    <Position X="13" Y="2.75" Width="1.5" />
+    <TypeIdentifier>
+      <HashCode>ICAAkABAAAAgAAQIAAAACIAEAAAAAACEAEAkAAAgAAA=</HashCode>
+      <FileName>Reporting\ReportWriters\WikiReportWriter.cs</FileName>
+    </TypeIdentifier>
+    <Lollipop Position="0.2" />
+  </Class>
+  <Interface Name="OxyPlot.Reporting.IReportWriter" Collapsed="true">
+    <Position X="9.5" Y="1.75" Width="1.5" />
+    <TypeIdentifier>
+      <HashCode>ACAAgAAAAAAgAAQAAAAAAAAAAAAAAAAAAEAkAAAgAAA=</HashCode>
+      <FileName>Reporting\ReportWriters\IReportWriter.cs</FileName>
+    </TypeIdentifier>
+  </Interface>
+  <Font Name="Segoe UI" Size="9" />
+</ClassDiagram>
\ No newline at end of file
diff --git a/oxyplot/OxyPlot/ClassDiagrams/Series.cd b/oxyplot/OxyPlot/ClassDiagrams/Series.cd
new file mode 100644
index 0000000..f114bc3
--- /dev/null
+++ b/oxyplot/OxyPlot/ClassDiagrams/Series.cd
@@ -0,0 +1,161 @@
+<?xml version="1.0" encoding="utf-8"?>
+<ClassDiagram MajorVersion="1" MinorVersion="1">
+  <Class Name="OxyPlot.LineSeries" Collapsed="true">
+    <Position X="6.75" Y="5" Width="1.5" />
+    <TypeIdentifier>
+      <HashCode>AAQCAAEIAiAAAGCAABBAAAAhRCAMEAAAADAAggAKIgA=</HashCode>
+      <FileName>Series\LineSeries.cs</FileName>
+    </TypeIdentifier>
+  </Class>
+  <Class Name="OxyPlot.DataPointSeries" Collapsed="true">
+    <Position X="6.75" Y="3.75" Width="1.5" />
+    <TypeIdentifier>
+      <HashCode>IAAAAAyAEAABgAAAACACAAAABAAEAAAAAAAAAgAAAAA=</HashCode>
+      <FileName>Series\DataPointSeries.cs</FileName>
+    </TypeIdentifier>
+  </Class>
+  <Class Name="OxyPlot.AreaSeries" Collapsed="true">
+    <Position X="8.75" Y="6.25" Width="1.5" />
+    <TypeIdentifier>
+      <HashCode>AgAAAAEAEAAAAIAAAAAACAAAAAAECAAAABMAAgIAAAA=</HashCode>
+      <FileName>Series\AreaSeries.cs</FileName>
+    </TypeIdentifier>
+  </Class>
+  <Class Name="OxyPlot.FunctionSeries" Collapsed="true">
+    <Position X="7" Y="6.25" Width="1.5" />
+    <TypeIdentifier>
+      <HashCode>AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA=</HashCode>
+      <FileName>Series\FunctionSeries.cs</FileName>
+    </TypeIdentifier>
+  </Class>
+  <Class Name="OxyPlot.BarSeries" Collapsed="true">
+    <Position X="0.5" Y="7.25" Width="1.5" />
+    <TypeIdentifier>
+      <HashCode>CAAAAAgAIAQAAAAAAAAAAAAAAIAAAABAAAAAEAAAAAA=</HashCode>
+      <FileName>Series\BarSeries\BarSeries.cs</FileName>
+    </TypeIdentifier>
+  </Class>
+  <Class Name="OxyPlot.XYAxisSeries" Collapsed="true">
+    <Position X="5.5" Y="2.5" Width="1.5" />
+    <TypeIdentifier>
+      <HashCode>sAAQAAE1WAAAAAAAAEAAQAQAAAAEAAAAABAUACACEAA=</HashCode>
+      <FileName>Series\XYAxisSeries.cs</FileName>
+    </TypeIdentifier>
+  </Class>
+  <Class Name="OxyPlot.CandleStickSeries" Collapsed="true">
+    <Position X="10.5" Y="5" Width="1.5" />
+    <TypeIdentifier>
+      <HashCode>AAAAAAEAAAAAAAAAAAAAAAAAAAAAAAAAABAAAAAABAA=</HashCode>
+      <FileName>Series\CandleStickSeries.cs</FileName>
+    </TypeIdentifier>
+  </Class>
+  <Class Name="OxyPlot.HighLowSeries" Collapsed="true">
+    <Position X="10.5" Y="3.75" Width="1.5" />
+    <TypeIdentifier>
+      <HashCode>AAAAAAkBECABCAAAABgAAAQABAQEAAABAHAAggAKAAA=</HashCode>
+      <FileName>Series\HighLowSeries.cs</FileName>
+    </TypeIdentifier>
+  </Class>
+  <Class Name="OxyPlot.ItemsSeries" Collapsed="true">
+    <Position X="5.5" Y="1.5" Width="1.5" />
+    <TypeIdentifier>
+      <HashCode>AAAAAAAAAAAAAEAAAAAAAAAAAAAAAAAAAAAAAIIAAAA=</HashCode>
+      <FileName>Series\ItemsSeries.cs</FileName>
+    </TypeIdentifier>
+  </Class>
+  <Class Name="OxyPlot.PieSeries" Collapsed="true">
+    <Position X="7.5" Y="1.5" Width="1.5" />
+    <TypeIdentifier>
+      <HashCode>AQAQAAEAWGAYACAIAAAAAAAgAAgEICJAgpQFAoCCAAI=</HashCode>
+      <FileName>Series\PieSeries.cs</FileName>
+    </TypeIdentifier>
+  </Class>
+  <Class Name="OxyPlot.ScatterSeries" Collapsed="true">
+    <Position X="8.75" Y="5" Width="1.5" />
+    <TypeIdentifier>
+      <HashCode>AARQAAEIEAAAAEgQAAAIAAAgACBEQAIEABAwAgQDAgA=</HashCode>
+      <FileName>Series\ScatterSeries.cs</FileName>
+    </TypeIdentifier>
+  </Class>
+  <Class Name="OxyPlot.StairStepSeries" Collapsed="true">
+    <Position X="5.25" Y="6.25" Width="1.5" />
+    <TypeIdentifier>
+      <HashCode>AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAABAAAgAAAAA=</HashCode>
+      <FileName>Series\StairStepSeries.cs</FileName>
+    </TypeIdentifier>
+  </Class>
+  <Class Name="OxyPlot.StemSeries" Collapsed="true">
+    <Position X="10.5" Y="6.25" Width="1.5" />
+    <TypeIdentifier>
+      <HashCode>AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAABAAAgAAQAA=</HashCode>
+      <FileName>Series\StemSeries.cs</FileName>
+    </TypeIdentifier>
+  </Class>
+  <Class Name="OxyPlot.Series" Collapsed="true">
+    <Position X="5.5" Y="0.5" Width="1.5" />
+    <TypeIdentifier>
+      <HashCode>AAAQAAEAWABAEEAAAAAAAAAAAAAEAAAAABAkBgISAAA=</HashCode>
+      <FileName>Series\Series.cs</FileName>
+    </TypeIdentifier>
+    <Lollipop Position="0.2" />
+  </Class>
+  <Class Name="OxyPlot.BarSeriesBase" Collapsed="true">
+    <Position X="1" Y="5" Width="1.5" />
+    <TypeIdentifier>
+      <HashCode>BYQAgIEAKCSAACCQAAAAAAABAAgEIBBAAhAUEgoCAAE=</HashCode>
+      <FileName>Series\BarSeries\BarSeriesBase.cs</FileName>
+    </TypeIdentifier>
+    <Lollipop Position="0.2" />
+  </Class>
+  <Class Name="OxyPlot.ColumnSeries" Collapsed="true">
+    <Position X="2.25" Y="7.25" Width="1.5" />
+    <TypeIdentifier>
+      <HashCode>AAAAAAgAIAQAAAAAAEAAAAAAAIAAAABAAAAAEAAAAAA=</HashCode>
+      <FileName>Series\BarSeries\ColumnSeries.cs</FileName>
+    </TypeIdentifier>
+  </Class>
+  <Class Name="OxyPlot.IntervalBarSeries" Collapsed="true">
+    <Position X="2.75" Y="5" Width="1.5" />
+    <TypeIdentifier>
+      <HashCode>DQQAgAkBGCSACECAAAAAAAABAIgEIgAAABAUEgoCAAE=</HashCode>
+      <FileName>Series\BarSeries\IntervalBarSeries.cs</FileName>
+    </TypeIdentifier>
+    <Lollipop Position="0.2" />
+  </Class>
+  <Class Name="OxyPlot.RectangleBarSeries" Collapsed="true">
+    <Position X="4.5" Y="3.75" Width="1.75" />
+    <TypeIdentifier>
+      <HashCode>AAAAgAEAECCACACAAAAAAAAAAAgEAAAAABAQEggCAAE=</HashCode>
+      <FileName>Series\BarSeries\RectangleBarSeries.cs</FileName>
+    </TypeIdentifier>
+  </Class>
+  <Class Name="OxyPlot.TornadoBarSeries" Collapsed="true">
+    <Position X="4.5" Y="5" Width="1.5" />
+    <TypeIdentifier>
+      <HashCode>DYQAAAsBGCUICEAABQAgAAAFAKgEAoAAABA0EgICAAE=</HashCode>
+      <FileName>Series\BarSeries\TornadoBarSeries.cs</FileName>
+    </TypeIdentifier>
+  </Class>
+  <Class Name="OxyPlot.BarSeriesBase&lt;T&gt;" Collapsed="true">
+    <Position X="1" Y="6" Width="1.5" />
+    <TypeIdentifier>
+      <HashCode>AAAAAAAAEAAACEAAAAAAAAAAAAAAAgAAAAAAAAAAAAA=</HashCode>
+      <FileName>Series\BarSeries\BarSeriesBase{T}.cs</FileName>
+    </TypeIdentifier>
+  </Class>
+  <Class Name="OxyPlot.CategorizedSeries" Collapsed="true">
+    <Position X="1" Y="3.75" Width="1.5" />
+    <TypeIdentifier>
+      <HashCode>AAAAAAgAAAAAAAAAAAAAAAAAAIAAAgAAAAAAEAAAAAA=</HashCode>
+      <FileName>Series\BarSeries\CategorizedSeries.cs</FileName>
+    </TypeIdentifier>
+  </Class>
+  <Class Name="OxyPlot.ErrorColumnSeries" Collapsed="true">
+    <Position X="2" Y="8.25" Width="2" />
+    <TypeIdentifier>
+      <HashCode>AAAIAAAAAEAAAAAAAAAAAAAAAAAEABAAAAAAAAAAAAA=</HashCode>
+      <FileName>Series\BarSeries\ErrorColumnSeries.cs</FileName>
+    </TypeIdentifier>
+  </Class>
+  <Font Name="Segoe UI" Size="9" />
+</ClassDiagram>
\ No newline at end of file
diff --git a/oxyplot/OxyPlot/Foundation/ArrayHelper.cs b/oxyplot/OxyPlot/Foundation/ArrayHelper.cs
new file mode 100644
index 0000000..7c65609
--- /dev/null
+++ b/oxyplot/OxyPlot/Foundation/ArrayHelper.cs
@@ -0,0 +1,124 @@
+// 
--------------------------------------------------------------------------------------------------------------------
+// <copyright file="ArrayHelper.cs" company="OxyPlot">
+//   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.
+// </copyright>
+// <summary>
+//   Array helper methods.
+// </summary>
+// 
--------------------------------------------------------------------------------------------------------------------
+namespace OxyPlot
+{
+    using System;
+
+    /// <summary>
+    /// Provides utility methods for vector generation.
+    /// </summary>
+    public static class ArrayHelper
+    {
+        /// <summary>
+        /// Creates a vector.
+        /// </summary>
+        /// <param name="x0">
+        /// The first value.
+        /// </param>
+        /// <param name="x1">
+        /// The last value.
+        /// </param>
+        /// <param name="n">
+        /// The number of steps.
+        /// </param>
+        /// <returns>
+        /// A vector.
+        /// </returns>
+        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;
+        }
+
+        /// <summary>
+        /// Creates a vector.
+        /// </summary>
+        /// <param name="x0">
+        /// The first value.
+        /// </param>
+        /// <param name="x1">
+        /// The last value.
+        /// </param>
+        /// <param name="dx">
+        /// The step size.
+        /// </param>
+        /// <returns>
+        /// A vector.
+        /// </returns>
+        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;
+        }
+
+        /// <summary>
+        /// Evaluates the specified function.
+        /// </summary>
+        /// <param name="f">
+        /// The function.
+        /// </param>
+        /// <param name="x">
+        /// The x values.
+        /// </param>
+        /// <param name="y">
+        /// The y values.
+        /// </param>
+        /// <returns>
+        /// Array of evaluations. The value of f(x_i,y_j) will be placed at index [i, j].
+        /// </returns>
+        public static double[,] Evaluate(Func<double, double, double> 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 --git a/oxyplot/OxyPlot/Foundation/CanonicalSplineHelper.cs 
b/oxyplot/OxyPlot/Foundation/CanonicalSplineHelper.cs
new file mode 100644
index 0000000..146b926
--- /dev/null
+++ b/oxyplot/OxyPlot/Foundation/CanonicalSplineHelper.cs
@@ -0,0 +1,252 @@
+// 
--------------------------------------------------------------------------------------------------------------------
+// <copyright file="CanonicalSplineHelper.cs" company="OxyPlot">
+//   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.
+// </copyright>
+// <summary>
+//   Interpolates a list of points using a canonical spline.
+// </summary>
+// 
--------------------------------------------------------------------------------------------------------------------
+namespace OxyPlot
+{
+    using System;
+    using System.Collections.Generic;
+    using System.Linq;
+
+    /// <summary>
+    /// Provides functionality to interpolate a list of points by a canonical spline.
+    /// </summary>
+    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
+        /// <summary>
+        /// Creates a spline of data points.
+        /// </summary>
+        /// <param name="points">
+        /// The points.
+        /// </param>
+        /// <param name="tension">
+        /// The tension.
+        /// </param>
+        /// <param name="tensions">
+        /// The tensions.
+        /// </param>
+        /// <param name="isClosed">
+        /// True if the spline is closed.
+        /// </param>
+        /// <param name="tolerance">
+        /// The tolerance.
+        /// </param>
+        /// <returns>
+        /// A list of data points.
+        /// </returns>
+        internal static List<IDataPoint> CreateSpline(
+            IList<IDataPoint> points, double tension, IList<double> 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<IDataPoint>(interpolatedScreenPoints.Count);
+
+            foreach (var s in interpolatedScreenPoints)
+            {
+                interpolatedDataPoints.Add(new DataPoint(s.X, s.Y));
+            }
+
+            return interpolatedDataPoints;
+        }
+
+        /// <summary>
+        /// Creates a spline of screen points.
+        /// </summary>
+        /// <param name="points">
+        /// The points.
+        /// </param>
+        /// <param name="tension">
+        /// The tension.
+        /// </param>
+        /// <param name="tensions">
+        /// The tensions.
+        /// </param>
+        /// <param name="isClosed">
+        /// True if the spline is closed.
+        /// </param>
+        /// <param name="tolerance">
+        /// The tolerance.
+        /// </param>
+        /// <returns>
+        /// A list of screen points.
+        /// </returns>
+        internal static List<ScreenPoint> CreateSpline(
+            IList<ScreenPoint> points, double tension, IList<double> tensions, bool isClosed, double 
tolerance)
+        {
+            var result = new List<ScreenPoint>();
+            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;
+        }
+
+        /// <summary>
+        /// The segment.
+        /// </summary>
+        /// <param name="points">
+        /// The points.
+        /// </param>
+        /// <param name="pt0">
+        /// The pt 0.
+        /// </param>
+        /// <param name="pt1">
+        /// The pt 1.
+        /// </param>
+        /// <param name="pt2">
+        /// The pt 2.
+        /// </param>
+        /// <param name="pt3">
+        /// The pt 3.
+        /// </param>
+        /// <param name="t1">
+        /// The t 1.
+        /// </param>
+        /// <param name="t2">
+        /// The t 2.
+        /// </param>
+        /// <param name="tolerance">
+        /// The tolerance.
+        /// </param>
+        private static void Segment(
+            IList<ScreenPoint> 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 --git a/oxyplot/OxyPlot/Foundation/CodeGenerator/CodeGenerationAttribute.cs 
b/oxyplot/OxyPlot/Foundation/CodeGenerator/CodeGenerationAttribute.cs
new file mode 100644
index 0000000..2887497
--- /dev/null
+++ b/oxyplot/OxyPlot/Foundation/CodeGenerator/CodeGenerationAttribute.cs
@@ -0,0 +1,57 @@
+// 
--------------------------------------------------------------------------------------------------------------------
+// <copyright file="CodeGenerationAttribute.cs" company="OxyPlot">
+//   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.
+// </copyright>
+// <summary>
+//   Attribute that controls if code should be generated for the property.
+// </summary>
+// 
--------------------------------------------------------------------------------------------------------------------
+namespace OxyPlot
+{
+    using System;
+
+    /// <summary>
+    /// Specifies whether code should be generated for the property.
+    /// </summary>
+    [AttributeUsage(AttributeTargets.Property)]
+    public class CodeGenerationAttribute : Attribute
+    {
+        /// <summary>
+        /// Initializes a new instance of the <see cref="CodeGenerationAttribute"/> class.
+        /// </summary>
+        /// <param name="generateCode">
+        /// The generate code.
+        /// </param>
+        public CodeGenerationAttribute(bool generateCode)
+        {
+            this.GenerateCode = generateCode;
+        }
+
+        /// <summary>
+        /// Gets or sets a value indicating whether GenerateCode.
+        /// </summary>
+        public bool GenerateCode { get; set; }
+
+    }
+}
\ No newline at end of file
diff --git a/oxyplot/OxyPlot/Foundation/CodeGenerator/CodeGenerator.cs 
b/oxyplot/OxyPlot/Foundation/CodeGenerator/CodeGenerator.cs
new file mode 100644
index 0000000..52943a6
--- /dev/null
+++ b/oxyplot/OxyPlot/Foundation/CodeGenerator/CodeGenerator.cs
@@ -0,0 +1,448 @@
+// 
--------------------------------------------------------------------------------------------------------------------
+// <copyright file="CodeGenerator.cs" company="OxyPlot">
+//   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.
+// </copyright>
+// <summary>
+//   Generates c# code for the specified PlotModel.
+// </summary>
+// 
--------------------------------------------------------------------------------------------------------------------
+namespace OxyPlot
+{
+    using System;
+    using System.Collections;
+    using System.Collections.Generic;
+    using System.Globalization;
+    using System.Reflection;
+    using System.Text;
+    using System.Text.RegularExpressions;
+
+    /// <summary>
+    /// Provides functionality to generate C# code for the specified <see cref="PlotModel"/>.
+    /// </summary>
+    /// <remarks>
+    /// 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());
+    /// </remarks>
+    public class CodeGenerator
+    {
+        /// <summary>
+        /// The sb.
+        /// </summary>
+        private readonly StringBuilder sb;
+
+        /// <summary>
+        /// The variables.
+        /// </summary>
+        private readonly Dictionary<string, bool> variables;
+
+        /// <summary>
+        /// The indent string.
+        /// </summary>
+        private string indentString;
+
+        /// <summary>
+        /// The indents.
+        /// </summary>
+        private int indents;
+
+        /// <summary>
+        /// Initializes a new instance of the <see cref="CodeGenerator"/> class.
+        /// </summary>
+        /// <param name="model">
+        /// The model.
+        /// </param>
+        public CodeGenerator(PlotModel model)
+        {
+            this.variables = new Dictionary<string, bool>();
+            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("}");
+        }
+
+        /// <summary>
+        /// Gets or sets Indents.
+        /// </summary>
+        private int Indents
+        {
+            get
+            {
+                return this.indents;
+            }
+
+            set
+            {
+                this.indents = value;
+                this.indentString = new string(' ', value);
+            }
+        }
+
+        /// <summary>
+        /// Formats the code.
+        /// </summary>
+        /// <param name="format">
+        /// The format.
+        /// </param>
+        /// <param name="values">
+        /// The values.
+        /// </param>
+        /// <returns>
+        /// The format code.
+        /// </returns>
+        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);
+        }
+
+        /// <summary>
+        /// Formats a constructor.
+        /// </summary>
+        /// <param name="type">
+        /// The type.
+        /// </param>
+        /// <param name="format">
+        /// The format of the constructor arguments.
+        /// </param>
+        /// <param name="values">
+        /// The argument values.
+        /// </param>
+        /// <returns>
+        /// The format constructor.
+        /// </returns>
+        public static string FormatConstructor(Type type, string format, params object[] values)
+        {
+            return string.Format("new {0}({1})", type.Name, FormatCode(format, values));
+        }
+
+        /// <summary>
+        /// Returns the c# code for this model.
+        /// </summary>
+        /// <returns>
+        /// C# code.
+        /// </returns>
+        public string ToCode()
+        {
+            return this.sb.ToString();
+        }
+
+        /// <summary>
+        /// Adds the specified object to the generated code.
+        /// </summary>
+        /// <param name="obj">
+        /// The object.
+        /// </param>
+        /// <returns>
+        /// The variable name.
+        /// </returns>
+        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;
+        }
+
+        /// <summary>
+        /// Adds the children.
+        /// </summary>
+        /// <param name="name">
+        /// The name.
+        /// </param>
+        /// <param name="collectionName">
+        /// Name of the collection.
+        /// </param>
+        /// <param name="children">
+        /// The children.
+        /// </param>
+        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);
+            }
+        }
+
+        /// <summary>
+        /// Adds the items.
+        /// </summary>
+        /// <param name="name">
+        /// The name.
+        /// </param>
+        /// <param name="list">
+        /// The list.
+        /// </param>
+        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);
+            }
+        }
+
+        /// <summary>
+        /// Appends the line.
+        /// </summary>
+        /// <param name="format">
+        /// The format string.
+        /// </param>
+        /// <param name="args">
+        /// The args.
+        /// </param>
+        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);
+            }
+        }
+
+        /// <summary>
+        /// Determines if the two specifed lists are equal.
+        /// </summary>
+        /// <param name="list1">
+        /// The first list.
+        /// </param>
+        /// <param name="list2">
+        /// The second list.
+        /// </param>
+        /// <returns>
+        /// True if all items are equal.
+        /// </returns>
+        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;
+        }
+
+        /// <summary>
+        /// Get the first attribute of the specified type.
+        /// </summary>
+        /// <param name="pi">
+        /// The property info.
+        /// </param>
+        /// <typeparam name="T">
+        /// The type.
+        /// </typeparam>
+        /// <returns>
+        /// The attribute, or null if no attribute was found.
+        /// </returns>
+        private T GetFirstAttribute<T>(PropertyInfo pi) where T : Attribute
+        {
+            foreach (T a in pi.GetCustomAttributes(typeof(CodeGenerationAttribute), true))
+            {
+                return a;
+            }
+
+            return null;
+        }
+
+        /// <summary>
+        /// Gets a new variable name of the specified type.
+        /// </summary>
+        /// <param name="type">
+        /// The type.
+        /// </param>
+        /// <returns>
+        /// The variable name.
+        /// </returns>
+        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;
+        }
+
+        /// <summary>
+        /// Makes a valid variable name of a string. Invalid characters will simply be removed.
+        /// </summary>
+        /// <param name="title">
+        /// The title.
+        /// </param>
+        /// <returns>
+        /// A valid variable name.
+        /// </returns>
+        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();
+        }
+
+        /// <summary>
+        /// The set properties.
+        /// </summary>
+        /// <param name="instance">
+        /// The instance.
+        /// </param>
+        /// <param name="varName">
+        /// The var name.
+        /// </param>
+        /// <param name="defaultValues">
+        /// The default values.
+        /// </param>
+        private void SetProperties(object instance, string varName, object defaultValues)
+        {
+            var instanceType = instance.GetType();
+            var listsToAdd = new Dictionary<string, IList>();
+            foreach (var pi in instanceType.GetProperties())
+            {
+                // check the [CodeGeneration] attribute
+                var cga = this.GetFirstAttribute<CodeGenerationAttribute>(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);
+            }
+        }
+
+        /// <summary>
+        /// Sets the property.
+        /// </summary>
+        /// <param name="name">
+        /// The property name.
+        /// </param>
+        /// <param name="value">
+        /// The value.
+        /// </param>
+        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 --git a/oxyplot/OxyPlot/Foundation/CodeGenerator/CodeGeneratorStringExtensions.cs 
b/oxyplot/OxyPlot/Foundation/CodeGenerator/CodeGeneratorStringExtensions.cs
new file mode 100644
index 0000000..954345d
--- /dev/null
+++ b/oxyplot/OxyPlot/Foundation/CodeGenerator/CodeGeneratorStringExtensions.cs
@@ -0,0 +1,188 @@
+// 
--------------------------------------------------------------------------------------------------------------------
+// <copyright file="CodeGeneratorStringExtensions.cs" company="OxyPlot">
+//   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.
+// </copyright>
+// <summary>
+//   The code generator string extensions.
+// </summary>
+// 
--------------------------------------------------------------------------------------------------------------------
+namespace OxyPlot
+{
+    using System;
+    using System.Globalization;
+
+    /// <summary>
+    /// Provides extension methods for code generation.
+    /// </summary>
+    public static class CodeGeneratorStringExtensions
+    {
+        /// <summary>
+        /// Converts the value of this instance to c# code.
+        /// </summary>
+        /// <param name="value">
+        /// The instance.
+        /// </param>
+        /// <returns>
+        /// C# code.
+        /// </returns>
+        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 + "\"";
+        }
+
+        /// <summary>
+        /// Converts the value of this instance to c# code.
+        /// </summary>
+        /// <param name="value">
+        /// The value.
+        /// </param>
+        /// <returns>
+        /// C# code.
+        /// </returns>
+        public static string ToCode(this bool value)
+        {
+            return value.ToString().ToLower();
+        }
+
+        /// <summary>
+        /// Converts the value of this instance to c# code.
+        /// </summary>
+        /// <param name="value">
+        /// The instance.
+        /// </param>
+        /// <returns>
+        /// C# code.
+        /// </returns>
+        public static string ToCode(this int value)
+        {
+            return value.ToString(CultureInfo.InvariantCulture);
+        }
+
+        /// <summary>
+        /// Converts the value of this instance to c# code.
+        /// </summary>
+        /// <param name="value">
+        /// The instance.
+        /// </param>
+        /// <returns>
+        /// C# code.
+        /// </returns>
+        public static string ToCode(this Enum value)
+        {
+            return string.Format("{0}.{1}", value.GetType().Name, value);
+        }
+
+        /// <summary>
+        /// Converts the value of this instance to c# code.
+        /// </summary>
+        /// <param name="value">
+        /// The instance.
+        /// </param>
+        /// <returns>
+        /// C# code.
+        /// </returns>
+        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);
+        }
+
+        /// <summary>
+        /// Converts the value of this instance to c# code.
+        /// </summary>
+        /// <param name="value">
+        /// The instance.
+        /// </param>
+        /// <returns>
+        /// C# code.
+        /// </returns>
+        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 --git a/oxyplot/OxyPlot/Foundation/CodeGenerator/ICodeGenerating.cs 
b/oxyplot/OxyPlot/Foundation/CodeGenerator/ICodeGenerating.cs
new file mode 100644
index 0000000..b76274e
--- /dev/null
+++ b/oxyplot/OxyPlot/Foundation/CodeGenerator/ICodeGenerating.cs
@@ -0,0 +1,45 @@
+// 
--------------------------------------------------------------------------------------------------------------------
+// <copyright file="ICodeGenerating.cs" company="OxyPlot">
+//   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.
+// </copyright>
+// <summary>
+//   Provides functionality to generate c# code of an object.
+// </summary>
+// 
--------------------------------------------------------------------------------------------------------------------
+namespace OxyPlot
+{
+    /// <summary>
+    /// Provides functionality to generate C# code of an object.
+    /// </summary>
+    public interface ICodeGenerating
+    {
+        /// <summary>
+        /// Returns c# code that generates this instance.
+        /// </summary>
+        /// <returns>
+        /// C# code.
+        /// </returns>
+        string ToCode();
+    }
+}
\ No newline at end of file
diff --git a/oxyplot/OxyPlot/Foundation/CohenSutherlandClipping.cs 
b/oxyplot/OxyPlot/Foundation/CohenSutherlandClipping.cs
new file mode 100644
index 0000000..9d8ef7e
--- /dev/null
+++ b/oxyplot/OxyPlot/Foundation/CohenSutherlandClipping.cs
@@ -0,0 +1,298 @@
+// 
--------------------------------------------------------------------------------------------------------------------
+// <copyright file="CohenSutherlandClipping.cs" company="OxyPlot">
+//   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.
+// </copyright>
+// <summary>
+//   Line clipping algorithm.
+// </summary>
+// 
--------------------------------------------------------------------------------------------------------------------
+namespace OxyPlot
+{
+    /// <summary>
+    /// Provides a line clipping algorithm.
+    /// </summary>
+    /// <remarks>
+    /// See http://en.wikipedia.org/wiki/Cohen%E2%80%93Sutherland
+    /// </remarks>
+    public class CohenSutherlandClipping
+    {
+        /// <summary>
+        /// The bottom code.
+        /// </summary>
+        private const int Bottom = 4; // 0100
+
+        /// <summary>
+        /// The inside code.
+        /// </summary>
+        private const int Inside = 0; // 0000
+
+        /// <summary>
+        /// The left code.
+        /// </summary>
+        private const int Left = 1; // 0001
+
+        /// <summary>
+        /// The right code.
+        /// </summary>
+        private const int Right = 2; // 0010
+
+        /// <summary>
+        /// The top code.
+        /// </summary>
+        private const int Top = 8; // 1000
+
+        /// <summary>
+        /// The x maximum.
+        /// </summary>
+        private readonly double xmax;
+
+        /// <summary>
+        /// The x minimum.
+        /// </summary>
+        private readonly double xmin;
+
+        /// <summary>
+        /// The y maximum.
+        /// </summary>
+        private readonly double ymax;
+
+        /// <summary>
+        /// The y minimum.
+        /// </summary>
+        private readonly double ymin;
+
+        /// <summary>
+        /// Initializes a new instance of the <see cref="CohenSutherlandClipping"/> class.
+        /// </summary>
+        /// <param name="rect">
+        /// The clipping rectangle.
+        /// </param>
+        public CohenSutherlandClipping(OxyRect rect)
+        {
+            this.xmin = rect.Left;
+            this.xmax = rect.Right;
+            this.ymin = rect.Top;
+            this.ymax = rect.Bottom;
+        }
+
+        /// <summary>
+        /// Initializes a new instance of the <see cref="CohenSutherlandClipping"/> class.
+        /// </summary>
+        /// <param name="xmin">
+        /// The xmin.
+        /// </param>
+        /// <param name="xmax">
+        /// The xmax.
+        /// </param>
+        /// <param name="ymin">
+        /// The ymin.
+        /// </param>
+        /// <param name="ymax">
+        /// The ymax.
+        /// </param>
+        public CohenSutherlandClipping(double xmin, double xmax, double ymin, double ymax)
+        {
+            this.xmin = xmin;
+            this.ymin = ymin;
+            this.xmax = xmax;
+            this.ymax = ymax;
+        }
+
+        /// <summary>
+        /// 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).
+        /// </summary>
+        /// <param name="x0">X coordinate of the first point.</param>
+        /// <param name="y0">Y coordinate of the first point.</param>
+        /// <param name="x1">X coordinate of the second point.</param>
+        /// <param name="y1">Y coordinate of the second point.</param>
+        /// <returns>
+        /// true if the line is inside.
+        /// </returns>
+        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;
+        }
+
+        /// <summary>
+        /// 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).
+        /// </summary>
+        /// <param name="s0">
+        /// The s 0.
+        /// </param>
+        /// <param name="s1">
+        /// The s 1.
+        /// </param>
+        /// <returns>
+        /// true if the line is inside
+        /// </returns>
+        public bool ClipLine(ref ScreenPoint s0, ref ScreenPoint s1)
+        {
+            return this.ClipLine(ref s0.x, ref s0.y, ref s1.x, ref s1.y);
+        }
+
+        /// <summary>
+        /// Determines whether the specified point is inside the rectangle.
+        /// </summary>
+        /// <param name="x">The x coordinate.</param>
+        /// <param name="y">The y coordinate.</param>
+        /// <returns>
+        ///  <c>true</c> if the specified point is inside; otherwise, <c>false</c>.
+        /// </returns>
+        public bool IsInside(double x, double y)
+        {
+            return this.ComputeOutCode(x, y) == Inside;
+        }
+
+        /// <summary>
+        /// Determines whether the specified point is inside the rectangle.
+        /// </summary>
+        /// <param name="s">The point.</param>
+        /// <returns>
+        ///  <c>true</c> if the specified point is inside; otherwise, <c>false</c>.
+        /// </returns>
+        public bool IsInside(ScreenPoint s)
+        {
+            return this.ComputeOutCode(s.X, s.Y) == Inside;
+        }
+
+        /// <summary>
+        /// Computes the out code.
+        /// </summary>
+        /// <param name="x">
+        /// The x.
+        /// </param>
+        /// <param name="y">
+        /// The y.
+        /// </param>
+        /// <returns>
+        /// The out code.
+        /// </returns>
+        /// <remarks>
+        /// Compute the bit code for a point (x, y) using the clip rectangle
+        /// bounded diagonally by (xmin, ymin), and (xmax, ymax)
+        /// </remarks>
+        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 --git a/oxyplot/OxyPlot/Foundation/Color.cs b/oxyplot/OxyPlot/Foundation/Color.cs
new file mode 100644
index 0000000..7bcdf7b
--- /dev/null
+++ b/oxyplot/OxyPlot/Foundation/Color.cs
@@ -0,0 +1,55 @@
+// 
--------------------------------------------------------------------------------------------------------------------
+// <copyright file="Color.cs" company="OxyPlot">
+//   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.
+// </copyright>
+// 
--------------------------------------------------------------------------------------------------------------------
+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 --git a/oxyplot/OxyPlot/Foundation/Colors.cs b/oxyplot/OxyPlot/Foundation/Colors.cs
new file mode 100644
index 0000000..a89055b
--- /dev/null
+++ b/oxyplot/OxyPlot/Foundation/Colors.cs
@@ -0,0 +1,45 @@
+// 
--------------------------------------------------------------------------------------------------------------------
+// <copyright file="Colors.cs" company="OxyPlot">
+//   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.
+// </copyright>
+// 
--------------------------------------------------------------------------------------------------------------------
+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 --git a/oxyplot/OxyPlot/Foundation/Conrec.cs b/oxyplot/OxyPlot/Foundation/Conrec.cs
new file mode 100644
index 0000000..2810aec
--- /dev/null
+++ b/oxyplot/OxyPlot/Foundation/Conrec.cs
@@ -0,0 +1,294 @@
+// 
--------------------------------------------------------------------------------------------------------------------
+// <copyright file="Conrec.cs" company="OxyPlot">
+//   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.
+// </copyright>
+// <summary>
+//   Creates contours from a triangular mesh.
+// </summary>
+// 
--------------------------------------------------------------------------------------------------------------------
+namespace OxyPlot
+{
+    using System;
+
+    /// <summary>
+    /// Provides functionality to create contours from a triangular mesh.
+    /// </summary>
+    /// <remarks>
+    /// <para>
+    /// Ported from C / Fortran code by Paul Bourke.
+    /// See <a href="http://paulbourke.net/papers/conrec/";>Conrec</a> for
+    /// full description of code and the original source.
+    ///  </para>
+    /// <para>
+    /// 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.
+    ///  </para>
+    /// </remarks>
+    public static class Conrec
+    {
+        /// <summary>
+        /// Renderer delegate
+        /// </summary>
+        /// <param name="x1">
+        /// Start point x-coordinate
+        /// </param>
+        /// <param name="y1">
+        /// Start point y-coordinate
+        /// </param>
+        /// <param name="x2">
+        /// End point x-coordinate
+        /// </param>
+        /// <param name="y2">
+        /// End point y-coordinate
+        /// </param>
+        /// <param name="z">
+        /// Contour level
+        /// </param>
+        public delegate void RendererDelegate(double x1, double y1, double x2, double y2, double z);
+
+        /// <summary>
+        /// 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.
+        /// </summary>
+        /// <param name="d">
+        /// Matrix of data to contour.
+        /// </param>
+        /// <param name="x">
+        /// Data matrix column coordinates.
+        /// </param>
+        /// <param name="y">
+        /// Data matrix row coordinates.
+        /// </param>
+        /// <param name="z">
+        /// Contour levels in increasing order.
+        /// </param>
+        /// <param name="renderer">
+        /// The renderer.
+        /// </param>
+        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<int, int, double> xsect = (p1, p2) => ((h[p2] * xh[p1]) - (h[p1] * xh[p2])) / (h[p2] - 
h[p1]);
+            Func<int, int, double> 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 --git a/oxyplot/OxyPlot/Foundation/DataPoint.cs b/oxyplot/OxyPlot/Foundation/DataPoint.cs
new file mode 100644
index 0000000..61cac54
--- /dev/null
+++ b/oxyplot/OxyPlot/Foundation/DataPoint.cs
@@ -0,0 +1,136 @@
+// 
--------------------------------------------------------------------------------------------------------------------
+// <copyright file="DataPoint.cs" company="OxyPlot">
+//   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.
+// </copyright>
+// <summary>
+//   DataPoint value type.
+// </summary>
+// 
--------------------------------------------------------------------------------------------------------------------
+namespace OxyPlot
+{
+    using System.Diagnostics.CodeAnalysis;
+
+    /// <summary>
+    /// Represents a point in the data coordinate system.
+    /// </summary>
+    /// <remarks>
+    /// <see cref="DataPoint"/>s are transformed to <see cref="ScreenPoint"/>s.
+    /// </remarks>
+    public struct DataPoint : IDataPoint, ICodeGenerating
+    {
+        /// <summary>
+        /// The undefined.
+        /// </summary>
+        public static readonly DataPoint Undefined = new DataPoint(double.NaN, double.NaN);
+
+        /// <summary>
+        /// The x-coordinate.
+        /// </summary>
+        [SuppressMessage("StyleCop.CSharp.NamingRules", 
"SA1307:AccessibleFieldsMustBeginWithUpperCaseLetter",
+            Justification = "Reviewed. Suppression is OK here.")]
+        internal double x;
+
+        /// <summary>
+        /// The y-coordinate.
+        /// </summary>
+        [SuppressMessage("StyleCop.CSharp.NamingRules", 
"SA1307:AccessibleFieldsMustBeginWithUpperCaseLetter",
+            Justification = "Reviewed. Suppression is OK here.")]
+        internal double y;
+
+        /// <summary>
+        /// Initializes a new instance of the <see cref="DataPoint"/> struct.
+        /// </summary>
+        /// <param name="x">
+        /// The x.
+        /// </param>
+        /// <param name="y">
+        /// The y.
+        /// </param>
+        public DataPoint(double x, double y)
+        {
+            this.x = x;
+            this.y = y;
+        }
+
+        /// <summary>
+        /// Gets or sets the X.
+        /// </summary>
+        /// <value>
+        /// The X.
+        /// </value>
+        public double X
+        {
+            get
+            {
+                return this.x;
+            }
+
+            set
+            {
+                this.x = value;
+            }
+        }
+
+        /// <summary>
+        /// Gets or sets the Y.
+        /// </summary>
+        /// <value>
+        /// The Y.
+        /// </value>
+        public double Y
+        {
+            get
+            {
+                return this.y;
+            }
+
+            set
+            {
+                this.y = value;
+            }
+        }
+
+        /// <summary>
+        /// Returns C# code that generates this instance.
+        /// </summary>
+        /// <returns>
+        /// The to code.
+        /// </returns>
+        public string ToCode()
+        {
+            return CodeGenerator.FormatConstructor(this.GetType(), "{0},{1}", this.x, this.y);
+        }
+
+        /// <summary>
+        /// Returns a <see cref="System.String"/> that represents this instance.
+        /// </summary>
+        /// <returns>
+        /// A <see cref="System.String"/> that represents this instance.
+        /// </returns>
+        public override string ToString()
+        {
+            return this.x + " " + this.y;
+        }
+    }
+}
\ No newline at end of file
diff --git a/oxyplot/OxyPlot/Foundation/DataPointConverter.cs 
b/oxyplot/OxyPlot/Foundation/DataPointConverter.cs
new file mode 100644
index 0000000..eab0008
--- /dev/null
+++ b/oxyplot/OxyPlot/Foundation/DataPointConverter.cs
@@ -0,0 +1,82 @@
+// 
--------------------------------------------------------------------------------------------------------------------
+// <copyright file="DataPointConverter.cs" company="OxyPlot">
+//   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.
+// </copyright>
+// <summary>
+//   The DataPoint converter.
+// </summary>
+// 
--------------------------------------------------------------------------------------------------------------------
+namespace OxyPlot
+{
+    using System;
+    using System.ComponentModel;
+    using System.Globalization;
+
+    /// <summary>
+    /// Converts a <see cref="DataPoint"/> object from one data type to another.
+    /// </summary>
+    public class DataPointConverter : TypeConverter
+    {
+        /// <summary>
+        /// Returns whether this converter can convert an object of the given type to the type of this 
converter, using the specified context.
+        /// </summary>
+        /// <param name="context">An <see cref="T:System.ComponentModel.ITypeDescriptorContext" /> that 
provides a format context.</param>
+        /// <param name="sourceType">A <see cref="T:System.Type" /> that represents the type you want to 
convert from.</param>
+        /// <returns>
+        /// true if this converter can perform the conversion; otherwise, false.
+        /// </returns>
+        public override bool CanConvertFrom(ITypeDescriptorContext context, Type sourceType)
+        {
+            if (sourceType == typeof(string))
+            {
+                return true;
+            }
+
+            return base.CanConvertFrom(context, sourceType);
+        }
+
+        /// <summary>
+        /// Converts the given object to the type of this converter, using the specified context and culture 
information.
+        /// </summary>
+        /// <param name="context">An <see cref="T:System.ComponentModel.ITypeDescriptorContext" /> that 
provides a format context.</param>
+        /// <param name="culture">The <see cref="T:System.Globalization.CultureInfo" /> to use as the 
current culture.</param>
+        /// <param name="value">The <see cref="T:System.Object" /> to convert.</param>
+        /// <returns>
+        /// An <see cref="T:System.Object" /> that represents the converted value.
+        /// </returns>
+        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 --git a/oxyplot/OxyPlot/Foundation/DoubleExtensions.cs b/oxyplot/OxyPlot/Foundation/DoubleExtensions.cs
new file mode 100644
index 0000000..70f55d0
--- /dev/null
+++ b/oxyplot/OxyPlot/Foundation/DoubleExtensions.cs
@@ -0,0 +1,236 @@
+// 
--------------------------------------------------------------------------------------------------------------------
+// <copyright file="DoubleExtensions.cs" company="OxyPlot">
+//   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.
+// </copyright>
+// <summary>
+//   Extension methods for double values.
+// </summary>
+// 
--------------------------------------------------------------------------------------------------------------------
+namespace OxyPlot
+{
+    using System;
+    using System.Globalization;
+
+    /// <summary>
+    /// Provides extension methods for the <see cref="Double"/> type.
+    /// </summary>
+    public static class DoubleExtensions
+    {
+        /// <summary>
+        /// Squares the specified value.
+        /// </summary>
+        /// <param name="x">
+        /// The value.
+        /// </param>
+        /// <returns>
+        /// Squared value.
+        /// </returns>
+        public static double Squared(this double x)
+        {
+            return x * x;
+        }
+
+        /// <summary>
+        /// Exponent function.
+        /// </summary>
+        /// <param name="x">
+        /// The value.
+        /// </param>
+        /// <returns>
+        /// The exponent.
+        /// </returns>
+        public static double GetExponent(this double x)
+        {
+            return Math.Round(Math.Log(Math.Abs(x), 10));
+        }
+
+        /// <summary>
+        /// Mantissa function.
+        /// http://en.wikipedia.org/wiki/Mantissa
+        /// </summary>
+        /// <param name="x">
+        /// The value.
+        /// </param>
+        /// <returns>
+        /// The mantissa.
+        /// </returns>
+        public static double GetMantissa(this double x)
+        {
+            return x / Math.Pow(10, x.GetExponent());
+        }
+
+        /// <summary>
+        /// Removes the floating point noise.
+        /// </summary>
+        /// <param name="value">
+        /// The value.
+        /// </param>
+        /// <returns>
+        /// A double without noise.
+        /// </returns>
+        public static double RemoveNoise2(this double value)
+        {
+            return (double)((decimal)value);
+        }
+
+        /// <summary>
+        /// Removes the floating point noise.
+        /// </summary>
+        /// <param name="value">
+        /// The value.
+        /// </param>
+        /// <param name="maxDigits">
+        /// The maximum number of digits.
+        /// </param>
+        /// <returns>
+        /// A double without noise.
+        /// </returns>
+        public static double RemoveNoise(this double value, int maxDigits = 8)
+        {
+            return double.Parse(value.ToString("e" + maxDigits));
+        }
+
+        /// <summary>
+        /// Removes the noise from double math.
+        /// </summary>
+        /// <param name="value">
+        /// The value.
+        /// </param>
+        /// <returns>
+        /// A double without noise.
+        /// </returns>
+        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);
+        }
+
+        /// <summary>
+        /// Determines whether the specified value is zero.
+        /// </summary>
+        /// <param name="value">The value.</param>
+        /// <returns>
+        /// <c>true</c> if the specified value is zero; otherwise, <c>false</c>.
+        /// </returns>
+        public static bool IsZero(this double value)
+        {
+            return Math.Abs(value) < double.Epsilon;
+        }
+
+        /// <summary>
+        /// Calculates the nearest larger multiple of the specified value.
+        /// </summary>
+        /// <param name="value">
+        /// The value.
+        /// </param>
+        /// <param name="step">
+        /// The multiplier.
+        /// </param>
+        /// <returns>
+        /// The multiple value.
+        /// </returns>
+        public static double ToUpperMultiple(this double value, double step)
+        {
+            var i = (int)Math.Ceiling(value / step);
+            return (step * i).RemoveNoise();
+        }
+
+        /// <summary>
+        /// Calculates the nearest smaller multiple of the specified value.
+        /// </summary>
+        /// <param name="value">
+        /// The value.
+        /// </param>
+        /// <param name="step">
+        /// The multiplier.
+        /// </param>
+        /// <returns>
+        /// The multiple value.
+        /// </returns>
+        public static double ToLowerMultiple(this double value, double step)
+        {
+            var i = (int)Math.Floor(value / step);
+            return (step * i).RemoveNoise();
+        }
+
+#if THISISNOTINUSE
+
+    // <summary>
+    // Gets the mantissa and exponent.
+    // </summary>
+    /// <remarks>
+    /// From <see 
cref="http://stackoverflow.com/questions/389993/extracting-mantissa-and-exponent-from-double-in-c"/>
+    /// </remarks>
+    /// <param name="d">The d.</param>
+    /// <param name="negative">if set to <c>true</c> [negative].</param>
+    /// <param name="mantissa">The mantissa.</param>
+    /// <param name="exponent">The exponent.</param>
+        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 --git a/oxyplot/OxyPlot/Foundation/FontWeights.cs b/oxyplot/OxyPlot/Foundation/FontWeights.cs
new file mode 100644
index 0000000..3e801f5
--- /dev/null
+++ b/oxyplot/OxyPlot/Foundation/FontWeights.cs
@@ -0,0 +1,48 @@
+// 
--------------------------------------------------------------------------------------------------------------------
+// <copyright file="FontWeights.cs" company="OxyPlot">
+//   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.
+// </copyright>
+// <summary>
+//   Static font weights.
+// </summary>
+// 
--------------------------------------------------------------------------------------------------------------------
+namespace OxyPlot
+{
+    /// <summary>
+    /// Provides a set of static predefined font weight values.
+    /// </summary>
+    public static class FontWeights
+    {
+        /// <summary>
+        /// Specifies a bold font weight.
+        /// </summary>
+        public const double Bold = 700;
+
+        /// <summary>
+        /// Specifies a normal font weight.
+        /// </summary>
+        public const double Normal = 400;
+
+    }
+}
\ No newline at end of file
diff --git a/oxyplot/OxyPlot/Foundation/FractionHelper.cs b/oxyplot/OxyPlot/Foundation/FractionHelper.cs
new file mode 100644
index 0000000..c41f1b7
--- /dev/null
+++ b/oxyplot/OxyPlot/Foundation/FractionHelper.cs
@@ -0,0 +1,155 @@
+// 
--------------------------------------------------------------------------------------------------------------------
+// <copyright file="FractionHelper.cs" company="OxyPlot">
+//   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.
+// </copyright>
+// <summary>
+//   Generates fraction strings from double values.
+// </summary>
+// 
--------------------------------------------------------------------------------------------------------------------
+namespace OxyPlot
+{
+    using System;
+    using System.Globalization;
+
+    /// <summary>
+    /// Provides functionality to generate fraction strings from double values.
+    /// </summary>
+    /// <remarks>
+    /// Examples: "3/4", "PI/2"
+    /// </remarks>
+    public static class FractionHelper
+    {
+        /// <summary>
+        /// Converts a double to a fraction string.
+        /// </summary>
+        /// <param name="value">
+        /// The value.
+        /// </param>
+        /// <param name="unit">
+        /// The unit.
+        /// </param>
+        /// <param name="unitSymbol">
+        /// The unit symbol.
+        /// </param>
+        /// <param name="eps">
+        /// The tolerance.
+        /// </param>
+        /// <param name="formatProvider">
+        /// The format Provider.
+        /// </param>
+        /// <returns>
+        /// The convert to fraction string.
+        /// </returns>
+        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);
+        }
+
+        /// <summary>
+        /// Finds the greates common divisor.
+        /// </summary>
+        /// <param name="a">
+        /// The a.
+        /// </param>
+        /// <param name="b">
+        /// The b.
+        /// </param>
+        /// <returns>
+        /// The gcd.
+        /// </returns>
+        public static int gcd(int a, int b)
+        {
+            if (b == 0)
+            {
+                return a;
+            }
+
+            return gcd(b, a % b);
+        }
+
+        /// <summary>
+        /// Finds the greatest common factor.
+        /// </summary>
+        /// <param name="x">
+        /// The x.
+        /// </param>
+        /// <param name="y">
+        /// The y.
+        /// </param>
+        /// <returns>
+        /// The gcf.
+        /// </returns>
+        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 --git a/oxyplot/OxyPlot/Foundation/HorizontalAlignment.cs 
b/oxyplot/OxyPlot/Foundation/HorizontalAlignment.cs
new file mode 100644
index 0000000..ba88e23
--- /dev/null
+++ b/oxyplot/OxyPlot/Foundation/HorizontalAlignment.cs
@@ -0,0 +1,52 @@
+// 
--------------------------------------------------------------------------------------------------------------------
+// <copyright file="HorizontalAlignment.cs" company="OxyPlot">
+//   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.
+// </copyright>
+// <summary>
+//   Horizontal text alignment.
+// </summary>
+// 
--------------------------------------------------------------------------------------------------------------------
+namespace OxyPlot
+{
+    /// <summary>
+    /// Specifies the horizontal alignment.
+    /// </summary>
+    public enum HorizontalAlignment
+    {
+        /// <summary>
+        /// Aligned to the left.
+        /// </summary>
+        Left = -1,
+
+        /// <summary>
+        /// Aligned in the center.
+        /// </summary>
+        Center = 0,
+
+        /// <summary>
+        /// Aligned to the right.
+        /// </summary>
+        Right = 1
+    }
+}
\ No newline at end of file
diff --git a/oxyplot/OxyPlot/Foundation/IDataPoint.cs b/oxyplot/OxyPlot/Foundation/IDataPoint.cs
new file mode 100644
index 0000000..b968966
--- /dev/null
+++ b/oxyplot/OxyPlot/Foundation/IDataPoint.cs
@@ -0,0 +1,49 @@
+// 
--------------------------------------------------------------------------------------------------------------------
+// <copyright file="IDataPoint.cs" company="OxyPlot">
+//   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.
+// </copyright>
+// <summary>
+//   DataPoint interface.
+// </summary>
+// 
--------------------------------------------------------------------------------------------------------------------
+namespace OxyPlot
+{
+    /// <summary>
+    /// Defines a point.
+    /// </summary>
+    public interface IDataPoint
+    {
+        /// <summary>
+        /// Gets or sets the x-coordinate.
+        /// </summary>
+        /// <value>The x-coordinate.</value>
+        double X { get; set; }
+
+        /// <summary>
+        /// Gets or sets the y-coordinate.
+        /// </summary>
+        /// <value>The y-coordinate.</value>
+        double Y { get; set; }
+    }
+}
\ No newline at end of file
diff --git a/oxyplot/OxyPlot/Foundation/IDataPointProvider.cs 
b/oxyplot/OxyPlot/Foundation/IDataPointProvider.cs
new file mode 100644
index 0000000..7a79b43
--- /dev/null
+++ b/oxyplot/OxyPlot/Foundation/IDataPointProvider.cs
@@ -0,0 +1,45 @@
+// 
--------------------------------------------------------------------------------------------------------------------
+// <copyright file="IDataPointProvider.cs" company="OxyPlot">
+//   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.
+// </copyright>
+// <summary>
+//   Provides functionality to create data points for items in an <see cref="ItemsSeries"/>.
+// </summary>
+// 
--------------------------------------------------------------------------------------------------------------------
+namespace OxyPlot
+{
+    /// <summary>
+    /// Provides functionality to create data points.
+    /// </summary>
+    public interface IDataPointProvider
+    {
+        /// <summary>
+        /// Gets the data point.
+        /// </summary>
+        /// <returns>
+        /// The data point.
+        /// </returns>
+        DataPoint GetDataPoint();
+    }
+}
\ No newline at end of file
diff --git a/oxyplot/OxyPlot/Foundation/LineStyle.cs b/oxyplot/OxyPlot/Foundation/LineStyle.cs
new file mode 100644
index 0000000..2182d8f
--- /dev/null
+++ b/oxyplot/OxyPlot/Foundation/LineStyle.cs
@@ -0,0 +1,97 @@
+// 
--------------------------------------------------------------------------------------------------------------------
+// <copyright file="LineStyle.cs" company="OxyPlot">
+//   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.
+// </copyright>
+// <summary>
+//   Enumeration of line styles.
+// </summary>
+// 
--------------------------------------------------------------------------------------------------------------------
+namespace OxyPlot
+{
+    /// <summary>
+    /// Specifies the style of a line.
+    /// </summary>
+    public enum LineStyle
+    {
+        /// <summary>
+        /// The solid line style.
+        /// </summary>
+        Solid,
+
+        /// <summary>
+        /// The dash line style.
+        /// </summary>
+        Dash,
+
+        /// <summary>
+        /// The dot line style.
+        /// </summary>
+        Dot,
+
+        /// <summary>
+        /// The dash dot line style.
+        /// </summary>
+        DashDot,
+
+        /// <summary>
+        /// The dash dash dot line style.
+        /// </summary>
+        DashDashDot,
+
+        /// <summary>
+        /// The dash dot dot line style.
+        /// </summary>
+        DashDotDot,
+
+        /// <summary>
+        /// The dash dash dot dot line style.
+        /// </summary>
+        DashDashDotDot,
+
+        /// <summary>
+        /// The long dash line style.
+        /// </summary>
+        LongDash,
+
+        /// <summary>
+        /// The long dash dot line style.
+        /// </summary>
+        LongDashDot,
+
+        /// <summary>
+        /// The long dash dot dot line style.
+        /// </summary>
+        LongDashDotDot,
+
+        /// <summary>
+        /// The hidden line style.
+        /// </summary>
+        None,
+
+        /// <summary>
+        /// The undefined line style.
+        /// </summary>
+        Undefined
+    }
+}
\ No newline at end of file
diff --git a/oxyplot/OxyPlot/Foundation/LineStyleHelper.cs b/oxyplot/OxyPlot/Foundation/LineStyleHelper.cs
new file mode 100644
index 0000000..cff2f20
--- /dev/null
+++ b/oxyplot/OxyPlot/Foundation/LineStyleHelper.cs
@@ -0,0 +1,76 @@
+// 
--------------------------------------------------------------------------------------------------------------------
+// <copyright file="LineStyleHelper.cs" company="OxyPlot">
+//   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.
+// </copyright>
+// <summary>
+//   Converts from LineStyle to stroke dash array.
+// </summary>
+// 
--------------------------------------------------------------------------------------------------------------------
+namespace OxyPlot
+{
+    /// <summary>
+    /// Provides functionality to convert from LineStyle to a stroke dash array.
+    /// </summary>
+    public static class LineStyleHelper
+    {
+        /// <summary>
+        /// Gets the stroke dash array for a given <see cref="LineStyle"/>.
+        /// </summary>
+        /// <param name="style">
+        /// The line style.
+        /// </param>
+        /// <returns>
+        /// A dash array.
+        /// </returns>
+        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 --git a/oxyplot/OxyPlot/Foundation/ListFiller.cs b/oxyplot/OxyPlot/Foundation/ListFiller.cs
new file mode 100644
index 0000000..51b797b
--- /dev/null
+++ b/oxyplot/OxyPlot/Foundation/ListFiller.cs
@@ -0,0 +1,145 @@
+// 
--------------------------------------------------------------------------------------------------------------------
+// <copyright file="ListFiller.cs" company="OxyPlot">
+//   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.
+// </copyright>
+// 
--------------------------------------------------------------------------------------------------------------------
+namespace OxyPlot
+{
+    using System;
+    using System.Collections;
+    using System.Collections.Generic;
+    using System.Reflection;
+
+    /// <summary>
+    ///     Provides functionality to fill a list by specified properties of another list.
+    /// </summary>
+    /// <remarks>
+    ///     This class uses reflection.
+    /// </remarks>
+    /// <typeparam name="T">
+    ///     The target list item type.
+    /// </typeparam>
+    public class ListFiller<T>
+        where T : class, new()
+    {
+        /// <summary>
+        ///     The properties.
+        /// </summary>
+        private readonly Dictionary<string, Action<T, object>> properties;
+
+        /// <summary>
+        ///     Initializes a new instance of the <see cref="ListFiller{T}" /> class.
+        /// </summary>
+        public ListFiller()
+        {
+            this.properties = new Dictionary<string, Action<T, object>>();
+        }
+
+        /// <summary>
+        ///     Adds a setter for the specified property.
+        /// </summary>
+        /// <param name="propertyName">
+        ///     Name of the property.
+        /// </param>
+        /// <param name="setter">
+        ///     The setter.
+        /// </param>
+        public void Add(string propertyName, Action<T, object> setter)
+        {
+            if (string.IsNullOrEmpty(propertyName))
+            {
+                return;
+            }
+
+            this.properties.Add(propertyName, setter);
+        }
+
+        /// <summary>
+        ///     Fills the specified target list.
+        /// </summary>
+        /// <param name="target">The target.</param>
+        /// <param name="source">The source.</param>
+        public void FillT(IList<T> target, IEnumerable source)
+        {
+            this.Fill((IList)target, source);
+        }
+
+        /// <summary>
+        ///     Fills the specified target list.
+        /// </summary>
+        /// <param name="target">
+        ///     The target.
+        /// </param>
+        /// <param name="source">
+        ///     The source list.
+        /// </param>
+        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 --git a/oxyplot/OxyPlot/Foundation/MarkerType.cs b/oxyplot/OxyPlot/Foundation/MarkerType.cs
new file mode 100644
index 0000000..36ba3b7
--- /dev/null
+++ b/oxyplot/OxyPlot/Foundation/MarkerType.cs
@@ -0,0 +1,91 @@
+// 
--------------------------------------------------------------------------------------------------------------------
+// <copyright file="MarkerType.cs" company="OxyPlot">
+//   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.
+// </copyright>
+// <summary>
+//   Enumeration of marker types.
+// </summary>
+// 
--------------------------------------------------------------------------------------------------------------------
+namespace OxyPlot
+{
+    /// <summary>
+    /// Specifies the marker type.
+    /// </summary>
+    public enum MarkerType
+    {
+        /// <summary>
+        /// Do not render markers.
+        /// </summary>
+        None,
+
+        /// <summary>
+        /// Render markers as circles.
+        /// </summary>
+        Circle,
+
+        /// <summary>
+        /// Render markers as squares.
+        /// </summary>
+        Square,
+
+        /// <summary>
+        /// Render markers as diamonds.
+        /// </summary>
+        Diamond,
+
+        /// <summary>
+        /// Render markers as triangles.
+        /// </summary>
+        Triangle,
+
+        /// <summary>
+        /// Render markers as crosses (note: this marker type requires the stroke color to be set).
+        /// </summary>
+        /// <remarks>
+        /// This marker type requires the stroke color to be set.
+        /// </remarks>
+        Cross,
+
+        /// <summary>
+        /// Renders markers as plus signs (note: this marker type requires the stroke color to be set).
+        /// </summary>
+        /// <remarks>
+        /// This marker type requires the stroke color to be set.
+        /// </remarks>
+        Plus,
+
+        /// <summary>
+        /// Renders markers as stars (note: this marker type requires the stroke color to be set).
+        /// </summary>
+        /// <remarks>
+        /// This marker type requires the stroke color to be set.
+        /// </remarks>
+        Star,
+
+        /// <summary>
+        /// Render markers by a custom shape (defined by outline).
+        /// </summary>
+        Custom
+    }
+}
\ No newline at end of file
diff --git a/oxyplot/OxyPlot/Foundation/OxyColor.cs b/oxyplot/OxyPlot/Foundation/OxyColor.cs
new file mode 100644
index 0000000..7df247d
--- /dev/null
+++ b/oxyplot/OxyPlot/Foundation/OxyColor.cs
@@ -0,0 +1,626 @@
+// 
--------------------------------------------------------------------------------------------------------------------
+// <copyright file="OxyColor.cs" company="OxyPlot">
+//   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.
+// </copyright>
+// <summary>
+//   Describes a color in terms of alpha, red, green, and blue channels.
+// </summary>
+// 
--------------------------------------------------------------------------------------------------------------------
+namespace OxyPlot
+{
+    using System;
+    using System.ComponentModel;
+    using System.Globalization;
+    using System.Linq;
+    using System.Reflection;
+
+    /// <summary>
+    /// Describes a color in terms of alpha, red, green, and blue channels.
+    /// </summary>
+    public class OxyColor : ICodeGenerating
+    {
+        /// <summary>
+        /// Gets or sets the alpha value.
+        /// </summary>
+        /// <value> The alpha value. </value>
+        public byte A { get; set; }
+
+        /// <summary>
+        /// Gets or sets the blue value.
+        /// </summary>
+        /// <value> The blue value. </value>
+        public byte B { get; set; }
+
+        /// <summary>
+        /// Gets or sets the green value.
+        /// </summary>
+        /// <value> The green value. </value>
+        public byte G { get; set; }
+
+        /// <summary>
+        /// Gets or sets the red value.
+        /// </summary>
+        /// <value> The red value. </value>
+        public byte R { get; set; }
+
+        /// <summary>
+        /// Parse a string.
+        /// </summary>
+        /// <param name="value">
+        /// The string in the format "#FFFFFF00" or "255,200,180,50".
+        /// </param>
+        /// <returns>
+        /// The OxyColor.
+        /// </returns>
+        /// <exception cref="System.FormatException">
+        /// Invalid format.
+        /// </exception>
+        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);
+        }
+
+        /// <summary>
+        /// Calculates the difference between two <see cref="OxyColor"/>s
+        /// </summary>
+        /// <param name="c1">
+        /// The first color.
+        /// </param>
+        /// <param name="c2">
+        /// The second color.
+        /// </param>
+        /// <returns>
+        /// L2-norm in RGBA space
+        /// </returns>
+        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);
+        }
+
+        /// <summary>
+        /// Convert an <see cref="uint"/> to a <see cref="OxyColor"/>.
+        /// </summary>
+        /// <param name="color">
+        /// The unsigned integer color value.
+        /// </param>
+        /// <returns>
+        /// The <see cref="OxyColor"/>.
+        /// </returns>
+        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);
+        }
+
+        /// <summary>
+        /// Creates a OxyColor from the specified HSV array.
+        /// </summary>
+        /// <param name="hsv">
+        /// The HSV value array.
+        /// </param>
+        /// <returns>
+        /// A OxyColor.
+        /// </returns>
+        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]);
+        }
+
+        /// <summary>
+        /// Convert from HSV to <see cref="OxyColor"/>
+        /// http://en.wikipedia.org/wiki/HSL_Color_space
+        /// </summary>
+        /// <param name="hue">
+        /// The hue value [0,1]
+        /// </param>
+        /// <param name="sat">
+        /// The saturation value [0,1]
+        /// </param>
+        /// <param name="val">
+        /// The intensity value [0,1]
+        /// </param>
+        /// <returns>
+        /// The <see cref="OxyColor"/>.
+        /// </returns>
+        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));
+        }
+
+        /// <summary>
+        /// Calculate the difference in hue between two <see cref="OxyColor"/>s.
+        /// </summary>
+        /// <param name="c1">
+        /// The first color.
+        /// </param>
+        /// <param name="c2">
+        /// The second color.
+        /// </param>
+        /// <returns>
+        /// The hue difference.
+        /// </returns>
+        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);
+        }
+
+        /// <summary>
+        /// Creates a color defined by an alpha value and another color.
+        /// </summary>
+        /// <param name="a">
+        /// Alpha value.
+        /// </param>
+        /// <param name="color">
+        /// The original color.
+        /// </param>
+        /// <returns>
+        /// A color.
+        /// </returns>
+        public static OxyColor FromAColor(byte a, OxyColor color)
+        {
+            return new OxyColor { A = a, R = color.R, G = color.G, B = color.B };
+        }
+
+        /// <summary>
+        /// Creates a color from the specified ARGB values.
+        /// </summary>
+        /// <param name="a">
+        /// The alpha value.
+        /// </param>
+        /// <param name="r">
+        /// The red value.
+        /// </param>
+        /// <param name="g">
+        /// The green value.
+        /// </param>
+        /// <param name="b">
+        /// The blue value.
+        /// </param>
+        /// <returns>
+        /// A color.
+        /// </returns>
+        public static OxyColor FromArgb(byte a, byte r, byte g, byte b)
+        {
+            return new OxyColor { A = a, R = r, G = g, B = b };
+        }
+
+        /// <summary>
+        /// Creates a new <see cref="OxyColor"/> structure from the specified RGB values.
+        /// </summary>
+        /// <param name="r">
+        /// The red value.
+        /// </param>
+        /// <param name="g">
+        /// The green value.
+        /// </param>
+        /// <param name="b">
+        /// The blue value.
+        /// </param>
+        /// <returns>
+        /// A <see cref="OxyColor"/> structure with the specified values and an alpha channel value of 1.
+        /// </returns>
+        public static OxyColor FromRgb(byte r, byte g, byte b)
+        {
+            // ReSharper restore InconsistentNaming
+            return new OxyColor { A = 255, R = r, G = g, B = b };
+        }
+
+        /// <summary>
+        /// Interpolates the specified colors.
+        /// </summary>
+        /// <param name="color1">
+        /// The color1.
+        /// </param>
+        /// <param name="color2">
+        /// The color2.
+        /// </param>
+        /// <param name="t">
+        /// The t.
+        /// </param>
+        /// <returns>
+        /// The interpolated color
+        /// </returns>
+        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);
+        }
+
+        /// <summary>
+        /// Convert OxyColor to double string.
+        /// </summary>
+        /// <returns>
+        /// A OxyColor string, e.g. "255,200,180,50".
+        /// </returns>
+        public string ToByteString()
+        {
+            return string.Format(CultureInfo.InvariantCulture, "{0},{1},{2},{3}", this.A, this.R, this.G, 
this.B);
+        }
+
+        /// <summary>
+        /// Determines whether the specified <see cref="System.Object"/> is equal to this instance.
+        /// </summary>
+        /// <param name="obj">
+        /// The <see cref="System.Object"/> to compare with this instance.
+        /// </param>
+        /// <returns>
+        /// <c>true</c> if the specified <see cref="System.Object"/> is equal to this instance; otherwise, 
<c>false</c> .
+        /// </returns>
+        public override bool Equals(object obj)
+        {
+            if (ReferenceEquals(null, obj))
+            {
+                return false;
+            }
+
+            if (ReferenceEquals(this, obj))
+            {
+                return true;
+            }
+
+            if (obj.GetType() != typeof(OxyColor))
+            {
+                return false;
+            }
+
+            return this.Equals((OxyColor)obj);
+        }
+
+        /// <summary>
+        /// Determines whether the specified <see cref="OxyColor"/> is equal to this instance.
+        /// </summary>
+        /// <param name="other">
+        /// The <see cref="OxyColor"/> to compare with this instance.
+        /// </param>
+        /// <returns>
+        /// <c>true</c> if the specified <see cref="OxyColor"/> is equal to this instance; otherwise, 
<c>false</c> .
+        /// </returns>
+        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;
+        }
+
+        /// <summary>
+        /// Gets the color name.
+        /// </summary>
+        /// <returns>
+        /// The color name.
+        /// </returns>
+        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;
+        }
+
+        /// <summary>
+        /// Returns a hash code for this instance.
+        /// </summary>
+        /// <returns>
+        /// A hash code for this instance, suitable for use in hashing algorithms and data structures like a 
hash table.
+        /// </returns>
+        public override int GetHashCode()
+        {
+            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;
+            }
+        }
+
+        /// <summary>
+        /// Returns a <see cref="System.String"/> that represents this instance.
+        /// </summary>
+        /// <returns>
+        /// A <see cref="System.String"/> that represents this instance.
+        /// </returns>
+        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);
+        }
+
+        /// <summary>
+        /// Changes the opacity value.
+        /// </summary>
+        /// <param name="newAlpha">
+        /// The new alpha.
+        /// </param>
+        /// <returns>
+        /// The new color.
+        /// </returns>
+        public OxyColor ChangeAlpha(byte newAlpha)
+        {
+            return FromArgb(newAlpha, this.R, this.G, this.B);
+        }
+
+        /// <summary>
+        /// Calculates the complementary OxyColor.
+        /// </summary>
+        /// <returns>
+        /// The complementary OxyColor.
+        /// </returns>
+        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]);
+        }
+
+        /// <summary>
+        /// Converts from a <see cref="OxyColor"/> to HSV values (double)
+        /// </summary>
+        /// <returns>
+        /// Array of [Hue,Saturation,Value] in the range [0,1]
+        /// </returns>
+        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;
+        }
+
+        /// <summary>
+        /// Changes the intensity.
+        /// </summary>
+        /// <param name="factor">
+        /// The factor.
+        /// </param>
+        /// <returns>
+        /// The new OxyColor.
+        /// </returns>
+        public OxyColor ChangeIntensity(double factor)
+        {
+            var hsv = this.ToHsv();
+            hsv[2] *= factor;
+            if (hsv[2] > 1.0)
+            {
+                hsv[2] = 1.0;
+            }
+
+            return FromHsv(hsv);
+        }
+
+        /// <summary>
+        /// Converts to an unsigned integer.
+        /// </summary>
+        /// <returns>
+        /// The <see cref="uint"/>.
+        /// </returns>
+        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);
+        }
+
+        /// <summary>
+        /// Returns C# code that generates this instance.
+        /// </summary>
+        /// <returns>
+        /// The to code.
+        /// </returns>
+        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 --git a/oxyplot/OxyPlot/Foundation/OxyColorConverter.cs b/oxyplot/OxyPlot/Foundation/OxyColorConverter.cs
new file mode 100644
index 0000000..f6a8329
--- /dev/null
+++ b/oxyplot/OxyPlot/Foundation/OxyColorConverter.cs
@@ -0,0 +1,135 @@
+// 
--------------------------------------------------------------------------------------------------------------------
+// <copyright file="OxyColorConverter.cs" company="OxyPlot">
+//   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.
+// </copyright>
+// <summary>
+//   Converts colors from one data type to another. Access this class through the TypeDescriptor.
+// </summary>
+// 
--------------------------------------------------------------------------------------------------------------------
+namespace OxyPlot
+{
+    using System;
+    using System.ComponentModel;
+    using System.Globalization;
+
+    /// <summary>
+    /// Converts between <see cref="OxyColor"/> and <see cref="System.String"/>. Access this class through 
the TypeDescriptor.
+    /// </summary>
+    public class OxyColorConverter : TypeConverter
+    {
+        /// <summary>
+        /// Determines whether an object can be converted from a given type to an instance of a <see 
cref="OxyColor"/>.
+        /// </summary>
+        /// <param name="context">
+        /// Describes the context information of a type.
+        /// </param>
+        /// <param name="sourceType">
+        /// The type of the source that is being evaluated for conversion.
+        /// </param>
+        /// <returns>
+        /// True if the type can be converted to a <see cref="OxyColor"/>; otherwise, false.
+        /// </returns>
+        public override bool CanConvertFrom(ITypeDescriptorContext context, Type sourceType)
+        {
+            return (sourceType == typeof(string)) || base.CanConvertFrom(context, sourceType);
+        }
+
+        /// <summary>
+        /// Determines whether an instance of a <see cref="OxyColor"/> can be converted to a different type.
+        /// </summary>
+        /// <param name="context">
+        /// Describes the context information of a type.
+        /// </param>
+        /// <param name="destinationType">
+        /// The desired type this <see cref="OxyColor"/> is being evaluated for conversion.
+        /// </param>
+        /// <returns>
+        /// True if this <see cref="OxyColor"/> can be converted to destinationType; otherwise, false.
+        /// </returns>
+        public override bool CanConvertTo(ITypeDescriptorContext context, Type destinationType)
+        {
+            return (destinationType == typeof(string)) || base.CanConvertTo(context, destinationType);
+        }
+
+        /// <summary>
+        /// Attempts to convert the specified object to a <see cref="OxyColor"/>.
+        /// </summary>
+        /// <param name="context">
+        /// Describes the context information of a type.
+        /// </param>
+        /// <param name="culture">
+        /// Cultural information to respect during conversion.
+        /// </param>
+        /// <param name="value">
+        /// The object being converted.
+        /// </param>
+        /// <returns>
+        /// The <see cref="OxyColor"/> created from converting value.
+        /// </returns>
+        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);
+        }
+
+        /// <summary>
+        /// Attempts to convert a <see cref="OxyColor"/> to a specified type.
+        /// </summary>
+        /// <param name="context">
+        /// Describes the context information of a type.
+        /// </param>
+        /// <param name="culture">
+        /// Describes the <see cref="CultureInfo"/> of the type being converted.
+        /// </param>
+        /// <param name="value">
+        /// The <see cref="OxyColor"/> to convert.
+        /// </param>
+        /// <param name="destinationType">
+        /// The type to convert this <see cref="OxyColor"/> to.
+        /// </param>
+        /// <returns>
+        /// The object created from converting this <see cref="OxyColor"/>.
+        /// </returns>
+        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 --git a/oxyplot/OxyPlot/Foundation/OxyColors.cs b/oxyplot/OxyPlot/Foundation/OxyColors.cs
new file mode 100644
index 0000000..e8aed0b
--- /dev/null
+++ b/oxyplot/OxyPlot/Foundation/OxyColors.cs
@@ -0,0 +1,743 @@
+// 
--------------------------------------------------------------------------------------------------------------------
+// <copyright file="OxyColors.cs" company="OxyPlot">
+//   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.
+// </copyright>
+// <summary>
+//   Implements a set of predefined colors.
+// </summary>
+// 
--------------------------------------------------------------------------------------------------------------------
+namespace OxyPlot
+{
+    /// <summary>
+    /// Implements a set of predefined colors.
+    /// </summary>
+    public static class OxyColors
+    {
+        /// <summary>
+        /// The alice blue.
+        /// </summary>
+        public static readonly OxyColor AliceBlue = OxyColor.FromUInt32(0xFFF0F8FF);
+
+        /// <summary>
+        /// The antique white.
+        /// </summary>
+        public static readonly OxyColor AntiqueWhite = OxyColor.FromUInt32(0xFFFAEBD7);
+
+        /// <summary>
+        /// The aqua.
+        /// </summary>
+        public static readonly OxyColor Aqua = OxyColor.FromUInt32(0xFF00FFFF);
+
+        /// <summary>
+        /// The aquamarine.
+        /// </summary>
+        public static readonly OxyColor Aquamarine = OxyColor.FromUInt32(0xFF7FFFD4);
+
+        /// <summary>
+        /// The azure.
+        /// </summary>
+        public static readonly OxyColor Azure = OxyColor.FromUInt32(0xFFF0FFFF);
+
+        /// <summary>
+        /// The beige.
+        /// </summary>
+        public static readonly OxyColor Beige = OxyColor.FromUInt32(0xFFF5F5DC);
+
+        /// <summary>
+        /// The bisque.
+        /// </summary>
+        public static readonly OxyColor Bisque = OxyColor.FromUInt32(0xFFFFE4C4);
+
+        /// <summary>
+        /// The black.
+        /// </summary>
+        public static readonly OxyColor Black = OxyColor.FromUInt32(0xFF000000);
+
+        /// <summary>
+        /// The blanched almond.
+        /// </summary>
+        public static readonly OxyColor BlanchedAlmond = OxyColor.FromUInt32(0xFFFFEBCD);
+
+        /// <summary>
+        /// The blue.
+        /// </summary>
+        public static readonly OxyColor Blue = OxyColor.FromUInt32(0xFF0000FF);
+
+        /// <summary>
+        /// The blue violet.
+        /// </summary>
+        public static readonly OxyColor BlueViolet = OxyColor.FromUInt32(0xFF8A2BE2);
+
+        /// <summary>
+        /// The brown.
+        /// </summary>
+        public static readonly OxyColor Brown = OxyColor.FromUInt32(0xFFA52A2A);
+
+        /// <summary>
+        /// The burly wood.
+        /// </summary>
+        public static readonly OxyColor BurlyWood = OxyColor.FromUInt32(0xFFDEB887);
+
+        /// <summary>
+        /// The cadet blue.
+        /// </summary>
+        public static readonly OxyColor CadetBlue = OxyColor.FromUInt32(0xFF5F9EA0);
+
+        /// <summary>
+        /// The chartreuse.
+        /// </summary>
+        public static readonly OxyColor Chartreuse = OxyColor.FromUInt32(0xFF7FFF00);
+
+        /// <summary>
+        /// The chocolate.
+        /// </summary>
+        public static readonly OxyColor Chocolate = OxyColor.FromUInt32(0xFFD2691E);
+
+        /// <summary>
+        /// The coral.
+        /// </summary>
+        public static readonly OxyColor Coral = OxyColor.FromUInt32(0xFFFF7F50);
+
+        /// <summary>
+        /// The cornflower blue.
+        /// </summary>
+        public static readonly OxyColor CornflowerBlue = OxyColor.FromUInt32(0xFF6495ED);
+
+        /// <summary>
+        /// The cornsilk.
+        /// </summary>
+        public static readonly OxyColor Cornsilk = OxyColor.FromUInt32(0xFFFFF8DC);
+
+        /// <summary>
+        /// The crimson.
+        /// </summary>
+        public static readonly OxyColor Crimson = OxyColor.FromUInt32(0xFFDC143C);
+
+        /// <summary>
+        /// The cyan.
+        /// </summary>
+        public static readonly OxyColor Cyan = OxyColor.FromUInt32(0xFF00FFFF);
+
+        /// <summary>
+        /// The dark blue.
+        /// </summary>
+        public static readonly OxyColor DarkBlue = OxyColor.FromUInt32(0xFF00008B);
+
+        /// <summary>
+        /// The dark cyan.
+        /// </summary>
+        public static readonly OxyColor DarkCyan = OxyColor.FromUInt32(0xFF008B8B);
+
+        /// <summary>
+        /// The dark goldenrod.
+        /// </summary>
+        public static readonly OxyColor DarkGoldenrod = OxyColor.FromUInt32(0xFFB8860B);
+
+        /// <summary>
+        /// The dark gray.
+        /// </summary>
+        public static readonly OxyColor DarkGray = OxyColor.FromUInt32(0xFFA9A9A9);
+
+        /// <summary>
+        /// The dark green.
+        /// </summary>
+        public static readonly OxyColor DarkGreen = OxyColor.FromUInt32(0xFF006400);
+
+        /// <summary>
+        /// The dark khaki.
+        /// </summary>
+        public static readonly OxyColor DarkKhaki = OxyColor.FromUInt32(0xFFBDB76B);
+
+        /// <summary>
+        /// The dark magenta.
+        /// </summary>
+        public static readonly OxyColor DarkMagenta = OxyColor.FromUInt32(0xFF8B008B);
+
+        /// <summary>
+        /// The dark olive green.
+        /// </summary>
+        public static readonly OxyColor DarkOliveGreen = OxyColor.FromUInt32(0xFF556B2F);
+
+        /// <summary>
+        /// The dark orange.
+        /// </summary>
+        public static readonly OxyColor DarkOrange = OxyColor.FromUInt32(0xFFFF8C00);
+
+        /// <summary>
+        /// The dark orchid.
+        /// </summary>
+        public static readonly OxyColor DarkOrchid = OxyColor.FromUInt32(0xFF9932CC);
+
+        /// <summary>
+        /// The dark red.
+        /// </summary>
+        public static readonly OxyColor DarkRed = OxyColor.FromUInt32(0xFF8B0000);
+
+        /// <summary>
+        /// The dark salmon.
+        /// </summary>
+        public static readonly OxyColor DarkSalmon = OxyColor.FromUInt32(0xFFE9967A);
+
+        /// <summary>
+        /// The dark sea green.
+        /// </summary>
+        public static readonly OxyColor DarkSeaGreen = OxyColor.FromUInt32(0xFF8FBC8F);
+
+        /// <summary>
+        /// The dark slate blue.
+        /// </summary>
+        public static readonly OxyColor DarkSlateBlue = OxyColor.FromUInt32(0xFF483D8B);
+
+        /// <summary>
+        /// The dark slate gray.
+        /// </summary>
+        public static readonly OxyColor DarkSlateGray = OxyColor.FromUInt32(0xFF2F4F4F);
+
+        /// <summary>
+        /// The dark turquoise.
+        /// </summary>
+        public static readonly OxyColor DarkTurquoise = OxyColor.FromUInt32(0xFF00CED1);
+
+        /// <summary>
+        /// The dark violet.
+        /// </summary>
+        public static readonly OxyColor DarkViolet = OxyColor.FromUInt32(0xFF9400D3);
+
+        /// <summary>
+        /// The deep pink.
+        /// </summary>
+        public static readonly OxyColor DeepPink = OxyColor.FromUInt32(0xFFFF1493);
+
+        /// <summary>
+        /// The deep sky blue.
+        /// </summary>
+        public static readonly OxyColor DeepSkyBlue = OxyColor.FromUInt32(0xFF00BFFF);
+
+        /// <summary>
+        /// The dim gray.
+        /// </summary>
+        public static readonly OxyColor DimGray = OxyColor.FromUInt32(0xFF696969);
+
+        /// <summary>
+        /// The dodger blue.
+        /// </summary>
+        public static readonly OxyColor DodgerBlue = OxyColor.FromUInt32(0xFF1E90FF);
+
+        /// <summary>
+        /// The firebrick.
+        /// </summary>
+        public static readonly OxyColor Firebrick = OxyColor.FromUInt32(0xFFB22222);
+
+        /// <summary>
+        /// The floral white.
+        /// </summary>
+        public static readonly OxyColor FloralWhite = OxyColor.FromUInt32(0xFFFFFAF0);
+
+        /// <summary>
+        /// The forest green.
+        /// </summary>
+        public static readonly OxyColor ForestGreen = OxyColor.FromUInt32(0xFF228B22);
+
+        /// <summary>
+        /// The fuchsia.
+        /// </summary>
+        public static readonly OxyColor Fuchsia = OxyColor.FromUInt32(0xFFFF00FF);
+
+        /// <summary>
+        /// The gainsboro.
+        /// </summary>
+        public static readonly OxyColor Gainsboro = OxyColor.FromUInt32(0xFFDCDCDC);
+
+        /// <summary>
+        /// The ghost white.
+        /// </summary>
+        public static readonly OxyColor GhostWhite = OxyColor.FromUInt32(0xFFF8F8FF);
+
+        /// <summary>
+        /// The gold.
+        /// </summary>
+        public static readonly OxyColor Gold = OxyColor.FromUInt32(0xFFFFD700);
+
+        /// <summary>
+        /// The goldenrod.
+        /// </summary>
+        public static readonly OxyColor Goldenrod = OxyColor.FromUInt32(0xFFDAA520);
+
+        /// <summary>
+        /// The gray.
+        /// </summary>
+        public static readonly OxyColor Gray = OxyColor.FromUInt32(0xFF808080);
+
+        /// <summary>
+        /// The green.
+        /// </summary>
+        public static readonly OxyColor Green = OxyColor.FromUInt32(0xFF008000);
+
+        /// <summary>
+        /// The green yellow.
+        /// </summary>
+        public static readonly OxyColor GreenYellow = OxyColor.FromUInt32(0xFFADFF2F);
+
+        /// <summary>
+        /// The honeydew.
+        /// </summary>
+        public static readonly OxyColor Honeydew = OxyColor.FromUInt32(0xFFF0FFF0);
+
+        /// <summary>
+        /// The hot pink.
+        /// </summary>
+        public static readonly OxyColor HotPink = OxyColor.FromUInt32(0xFFFF69B4);
+
+        /// <summary>
+        /// The indian red.
+        /// </summary>
+        public static readonly OxyColor IndianRed = OxyColor.FromUInt32(0xFFCD5C5C);
+
+        /// <summary>
+        /// The indigo.
+        /// </summary>
+        public static readonly OxyColor Indigo = OxyColor.FromUInt32(0xFF4B0082);
+
+        /// <summary>
+        /// The ivory.
+        /// </summary>
+        public static readonly OxyColor Ivory = OxyColor.FromUInt32(0xFFFFFFF0);
+
+        /// <summary>
+        /// The khaki.
+        /// </summary>
+        public static readonly OxyColor Khaki = OxyColor.FromUInt32(0xFFF0E68C);
+
+        /// <summary>
+        /// The lavender.
+        /// </summary>
+        public static readonly OxyColor Lavender = OxyColor.FromUInt32(0xFFE6E6FA);
+
+        /// <summary>
+        /// The lavender blush.
+        /// </summary>
+        public static readonly OxyColor LavenderBlush = OxyColor.FromUInt32(0xFFFFF0F5);
+
+        /// <summary>
+        /// The lawn green.
+        /// </summary>
+        public static readonly OxyColor LawnGreen = OxyColor.FromUInt32(0xFF7CFC00);
+
+        /// <summary>
+        /// The lemon chiffon.
+        /// </summary>
+        public static readonly OxyColor LemonChiffon = OxyColor.FromUInt32(0xFFFFFACD);
+
+        /// <summary>
+        /// The light blue.
+        /// </summary>
+        public static readonly OxyColor LightBlue = OxyColor.FromUInt32(0xFFADD8E6);
+
+        /// <summary>
+        /// The light coral.
+        /// </summary>
+        public static readonly OxyColor LightCoral = OxyColor.FromUInt32(0xFFF08080);
+
+        /// <summary>
+        /// The light cyan.
+        /// </summary>
+        public static readonly OxyColor LightCyan = OxyColor.FromUInt32(0xFFE0FFFF);
+
+        /// <summary>
+        /// The light goldenrod yellow.
+        /// </summary>
+        public static readonly OxyColor LightGoldenrodYellow = OxyColor.FromUInt32(0xFFFAFAD2);
+
+        /// <summary>
+        /// The light gray.
+        /// </summary>
+        public static readonly OxyColor LightGray = OxyColor.FromUInt32(0xFFD3D3D3);
+
+        /// <summary>
+        /// The light green.
+        /// </summary>
+        public static readonly OxyColor LightGreen = OxyColor.FromUInt32(0xFF90EE90);
+
+        /// <summary>
+        /// The light pink.
+        /// </summary>
+        public static readonly OxyColor LightPink = OxyColor.FromUInt32(0xFFFFB6C1);
+
+        /// <summary>
+        /// The light salmon.
+        /// </summary>
+        public static readonly OxyColor LightSalmon = OxyColor.FromUInt32(0xFFFFA07A);
+
+        /// <summary>
+        /// The light sea green.
+        /// </summary>
+        public static readonly OxyColor LightSeaGreen = OxyColor.FromUInt32(0xFF20B2AA);
+
+        /// <summary>
+        /// The light sky blue.
+        /// </summary>
+        public static readonly OxyColor LightSkyBlue = OxyColor.FromUInt32(0xFF87CEFA);
+
+        /// <summary>
+        /// The light slate gray.
+        /// </summary>
+        public static readonly OxyColor LightSlateGray = OxyColor.FromUInt32(0xFF778899);
+
+        /// <summary>
+        /// The light steel blue.
+        /// </summary>
+        public static readonly OxyColor LightSteelBlue = OxyColor.FromUInt32(0xFFB0C4DE);
+
+        /// <summary>
+        /// The light yellow.
+        /// </summary>
+        public static readonly OxyColor LightYellow = OxyColor.FromUInt32(0xFFFFFFE0);
+
+        /// <summary>
+        /// The lime.
+        /// </summary>
+        public static readonly OxyColor Lime = OxyColor.FromUInt32(0xFF00FF00);
+
+        /// <summary>
+        /// The lime green.
+        /// </summary>
+        public static readonly OxyColor LimeGreen = OxyColor.FromUInt32(0xFF32CD32);
+
+        /// <summary>
+        /// The linen.
+        /// </summary>
+        public static readonly OxyColor Linen = OxyColor.FromUInt32(0xFFFAF0E6);
+
+        /// <summary>
+        /// The magenta.
+        /// </summary>
+        public static readonly OxyColor Magenta = OxyColor.FromUInt32(0xFFFF00FF);
+
+        /// <summary>
+        /// The maroon.
+        /// </summary>
+        public static readonly OxyColor Maroon = OxyColor.FromUInt32(0xFF800000);
+
+        /// <summary>
+        /// The medium aquamarine.
+        /// </summary>
+        public static readonly OxyColor MediumAquamarine = OxyColor.FromUInt32(0xFF66CDAA);
+
+        /// <summary>
+        /// The medium blue.
+        /// </summary>
+        public static readonly OxyColor MediumBlue = OxyColor.FromUInt32(0xFF0000CD);
+
+        /// <summary>
+        /// The medium orchid.
+        /// </summary>
+        public static readonly OxyColor MediumOrchid = OxyColor.FromUInt32(0xFFBA55D3);
+
+        /// <summary>
+        /// The medium purple.
+        /// </summary>
+        public static readonly OxyColor MediumPurple = OxyColor.FromUInt32(0xFF9370DB);
+
+        /// <summary>
+        /// The medium sea green.
+        /// </summary>
+        public static readonly OxyColor MediumSeaGreen = OxyColor.FromUInt32(0xFF3CB371);
+
+        /// <summary>
+        /// The medium slate blue.
+        /// </summary>
+        public static readonly OxyColor MediumSlateBlue = OxyColor.FromUInt32(0xFF7B68EE);
+
+        /// <summary>
+        /// The medium spring green.
+        /// </summary>
+        public static readonly OxyColor MediumSpringGreen = OxyColor.FromUInt32(0xFF00FA9A);
+
+        /// <summary>
+        /// The medium turquoise.
+        /// </summary>
+        public static readonly OxyColor MediumTurquoise = OxyColor.FromUInt32(0xFF48D1CC);
+
+        /// <summary>
+        /// The medium violet red.
+        /// </summary>
+        public static readonly OxyColor MediumVioletRed = OxyColor.FromUInt32(0xFFC71585);
+
+        /// <summary>
+        /// The midnight blue.
+        /// </summary>
+        public static readonly OxyColor MidnightBlue = OxyColor.FromUInt32(0xFF191970);
+
+        /// <summary>
+        /// The mint cream.
+        /// </summary>
+        public static readonly OxyColor MintCream = OxyColor.FromUInt32(0xFFF5FFFA);
+
+        /// <summary>
+        /// The misty rose.
+        /// </summary>
+        public static readonly OxyColor MistyRose = OxyColor.FromUInt32(0xFFFFE4E1);
+
+        /// <summary>
+        /// The moccasin.
+        /// </summary>
+        public static readonly OxyColor Moccasin = OxyColor.FromUInt32(0xFFFFE4B5);
+
+        /// <summary>
+        /// The navajo white.
+        /// </summary>
+        public static readonly OxyColor NavajoWhite = OxyColor.FromUInt32(0xFFFFDEAD);
+
+        /// <summary>
+        /// The navy.
+        /// </summary>
+        public static readonly OxyColor Navy = OxyColor.FromUInt32(0xFF000080);
+
+        /// <summary>
+        /// The old lace.
+        /// </summary>
+        public static readonly OxyColor OldLace = OxyColor.FromUInt32(0xFFFDF5E6);
+
+        /// <summary>
+        /// The olive.
+        /// </summary>
+        public static readonly OxyColor Olive = OxyColor.FromUInt32(0xFF808000);
+
+        /// <summary>
+        /// The olive drab.
+        /// </summary>
+        public static readonly OxyColor OliveDrab = OxyColor.FromUInt32(0xFF6B8E23);
+
+        /// <summary>
+        /// The orange.
+        /// </summary>
+        public static readonly OxyColor Orange = OxyColor.FromUInt32(0xFFFFA500);
+
+        /// <summary>
+        /// The orange red.
+        /// </summary>
+        public static readonly OxyColor OrangeRed = OxyColor.FromUInt32(0xFFFF4500);
+
+        /// <summary>
+        /// The orchid.
+        /// </summary>
+        public static readonly OxyColor Orchid = OxyColor.FromUInt32(0xFFDA70D6);
+
+        /// <summary>
+        /// The pale goldenrod.
+        /// </summary>
+        public static readonly OxyColor PaleGoldenrod = OxyColor.FromUInt32(0xFFEEE8AA);
+
+        /// <summary>
+        /// The pale green.
+        /// </summary>
+        public static readonly OxyColor PaleGreen = OxyColor.FromUInt32(0xFF98FB98);
+
+        /// <summary>
+        /// The pale turquoise.
+        /// </summary>
+        public static readonly OxyColor PaleTurquoise = OxyColor.FromUInt32(0xFFAFEEEE);
+
+        /// <summary>
+        /// The pale violet red.
+        /// </summary>
+        public static readonly OxyColor PaleVioletRed = OxyColor.FromUInt32(0xFFDB7093);
+
+        /// <summary>
+        /// The papaya whip.
+        /// </summary>
+        public static readonly OxyColor PapayaWhip = OxyColor.FromUInt32(0xFFFFEFD5);
+
+        /// <summary>
+        /// The peach puff.
+        /// </summary>
+        public static readonly OxyColor PeachPuff = OxyColor.FromUInt32(0xFFFFDAB9);
+
+        /// <summary>
+        /// The peru.
+        /// </summary>
+        public static readonly OxyColor Peru = OxyColor.FromUInt32(0xFFCD853F);
+
+        /// <summary>
+        /// The pink.
+        /// </summary>
+        public static readonly OxyColor Pink = OxyColor.FromUInt32(0xFFFFC0CB);
+
+        /// <summary>
+        /// The plum.
+        /// </summary>
+        public static readonly OxyColor Plum = OxyColor.FromUInt32(0xFFDDA0DD);
+
+        /// <summary>
+        /// The powder blue.
+        /// </summary>
+        public static readonly OxyColor PowderBlue = OxyColor.FromUInt32(0xFFB0E0E6);
+
+        /// <summary>
+        /// The purple.
+        /// </summary>
+        public static readonly OxyColor Purple = OxyColor.FromUInt32(0xFF800080);
+
+        /// <summary>
+        /// The red.
+        /// </summary>
+        public static readonly OxyColor Red = OxyColor.FromUInt32(0xFFFF0000);
+
+        /// <summary>
+        /// The rosy brown.
+        /// </summary>
+        public static readonly OxyColor RosyBrown = OxyColor.FromUInt32(0xFFBC8F8F);
+
+        /// <summary>
+        /// The royal blue.
+        /// </summary>
+        public static readonly OxyColor RoyalBlue = OxyColor.FromUInt32(0xFF4169E1);
+
+        /// <summary>
+        /// The saddle brown.
+        /// </summary>
+        public static readonly OxyColor SaddleBrown = OxyColor.FromUInt32(0xFF8B4513);
+
+        /// <summary>
+        /// The salmon.
+        /// </summary>
+        public static readonly OxyColor Salmon = OxyColor.FromUInt32(0xFFFA8072);
+
+        /// <summary>
+        /// The sandy brown.
+        /// </summary>
+        public static readonly OxyColor SandyBrown = OxyColor.FromUInt32(0xFFF4A460);
+
+        /// <summary>
+        /// The sea green.
+        /// </summary>
+        public static readonly OxyColor SeaGreen = OxyColor.FromUInt32(0xFF2E8B57);
+
+        /// <summary>
+        /// The sea shell.
+        /// </summary>
+        public static readonly OxyColor SeaShell = OxyColor.FromUInt32(0xFFFFF5EE);
+
+        /// <summary>
+        /// The sienna.
+        /// </summary>
+        public static readonly OxyColor Sienna = OxyColor.FromUInt32(0xFFA0522D);
+
+        /// <summary>
+        /// The silver.
+        /// </summary>
+        public static readonly OxyColor Silver = OxyColor.FromUInt32(0xFFC0C0C0);
+
+        /// <summary>
+        /// The sky blue.
+        /// </summary>
+        public static readonly OxyColor SkyBlue = OxyColor.FromUInt32(0xFF87CEEB);
+
+        /// <summary>
+        /// The slate blue.
+        /// </summary>
+        public static readonly OxyColor SlateBlue = OxyColor.FromUInt32(0xFF6A5ACD);
+
+        /// <summary>
+        /// The slate gray.
+        /// </summary>
+        public static readonly OxyColor SlateGray = OxyColor.FromUInt32(0xFF708090);
+
+        /// <summary>
+        /// The snow.
+        /// </summary>
+        public static readonly OxyColor Snow = OxyColor.FromUInt32(0xFFFFFAFA);
+
+        /// <summary>
+        /// The spring green.
+        /// </summary>
+        public static readonly OxyColor SpringGreen = OxyColor.FromUInt32(0xFF00FF7F);
+
+        /// <summary>
+        /// The steel blue.
+        /// </summary>
+        public static readonly OxyColor SteelBlue = OxyColor.FromUInt32(0xFF4682B4);
+
+        /// <summary>
+        /// The tan.
+        /// </summary>
+        public static readonly OxyColor Tan = OxyColor.FromUInt32(0xFFD2B48C);
+
+        /// <summary>
+        /// The teal.
+        /// </summary>
+        public static readonly OxyColor Teal = OxyColor.FromUInt32(0xFF008080);
+
+        /// <summary>
+        /// The thistle.
+        /// </summary>
+        public static readonly OxyColor Thistle = OxyColor.FromUInt32(0xFFD8BFD8);
+
+        /// <summary>
+        /// The tomato.
+        /// </summary>
+        public static readonly OxyColor Tomato = OxyColor.FromUInt32(0xFFFF6347);
+
+        /// <summary>
+        /// The transparent.
+        /// </summary>
+        public static readonly OxyColor Transparent = OxyColor.FromUInt32(0x00FFFFFF);
+
+        /// <summary>
+        /// The turquoise.
+        /// </summary>
+        public static readonly OxyColor Turquoise = OxyColor.FromUInt32(0xFF40E0D0);
+
+        /// <summary>
+        /// The violet.
+        /// </summary>
+        public static readonly OxyColor Violet = OxyColor.FromUInt32(0xFFEE82EE);
+
+        /// <summary>
+        /// The wheat.
+        /// </summary>
+        public static readonly OxyColor Wheat = OxyColor.FromUInt32(0xFFF5DEB3);
+
+        /// <summary>
+        /// The white.
+        /// </summary>
+        public static readonly OxyColor White = OxyColor.FromUInt32(0xFFFFFFFF);
+
+        /// <summary>
+        /// The white smoke.
+        /// </summary>
+        public static readonly OxyColor WhiteSmoke = OxyColor.FromUInt32(0xFFF5F5F5);
+
+        /// <summary>
+        /// The yellow.
+        /// </summary>
+        public static readonly OxyColor Yellow = OxyColor.FromUInt32(0xFFFFFF00);
+
+        /// <summary>
+        /// The yellow green.
+        /// </summary>
+        public static readonly OxyColor YellowGreen = OxyColor.FromUInt32(0xFF9ACD32);
+
+    }
+}
\ No newline at end of file
diff --git a/oxyplot/OxyPlot/Foundation/OxyImage.cs b/oxyplot/OxyPlot/Foundation/OxyImage.cs
new file mode 100644
index 0000000..715fe0f
--- /dev/null
+++ b/oxyplot/OxyPlot/Foundation/OxyImage.cs
@@ -0,0 +1,444 @@
+// 
--------------------------------------------------------------------------------------------------------------------
+// <copyright file="OxyImage.cs" company="OxyPlot">
+//   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.
+// </copyright>
+// <summary>
+//   Represents an image, encoded as DIB, JPEG or PNG.
+// </summary>
+// 
--------------------------------------------------------------------------------------------------------------------
+namespace OxyPlot
+{
+    using System;
+    using System.IO;
+    using System.Linq;
+
+    /// <summary>
+    /// Represents an image, encoded as DIB, JPEG or PNG.
+    /// </summary>
+    public class OxyImage
+    {
+        /// <summary>
+        /// The image data.
+        /// </summary>
+        private readonly byte[] data;
+
+        /// <summary>
+        /// Initializes a new instance of the <see cref="OxyImage"/> class from the specified stream.
+        /// </summary>
+        /// <param name="s">
+        /// A stream that provides the image data.
+        /// </param>
+        public OxyImage(Stream s)
+        {
+            using (var ms = new MemoryStream())
+            {
+                s.CopyTo(ms);
+                this.data = ms.ToArray();
+            }
+        }
+
+        /// <summary>
+        /// Initializes a new instance of the <see cref="OxyImage"/> class from a byte array.
+        /// </summary>
+        /// <param name="bytes">
+        /// The image bytes.
+        /// </param>
+        public OxyImage(byte[] bytes)
+        {
+            this.data = bytes;
+        }
+
+        /// <summary>
+        /// Creates an <see cref="OxyImage"/> from the specified <see cref="OxyColor"/> array.
+        /// </summary>
+        /// <param name="data">
+        /// The pixel data, indexed as [row,column] (from bottom-left).
+        /// </param>
+        /// <param name="dpi">
+        /// The resolution.
+        /// </param>
+        /// <returns>
+        /// An <see cref="OxyImage"/>.
+        /// </returns>
+        /// <remarks>
+        /// This method is creating a simple BitmapInfoHeader.
+        /// </remarks>
+        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);
+        }
+
+        /// <summary>
+        /// Creates an <see cref="OxyImage"/> from the specified <see cref="OxyColor"/> array.
+        /// </summary>
+        /// <param name="data">
+        /// The pixel data, indexed as [row,column] (from bottom-left).
+        /// </param>
+        /// <param name="dpi">
+        /// The resolution.
+        /// </param>
+        /// <returns>
+        /// An <see cref="OxyImage"/>.
+        /// </returns>
+        /// <remarks>
+        /// This method is creating a Bitmap V4 info header, including channel bit masks and color space 
information.
+        /// </remarks>
+        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);
+        }
+
+        /// <summary>
+        /// Creates an <see cref="OxyImage"/> from the specified pixel data.
+        /// </summary>
+        /// <param name="width">
+        /// The width.
+        /// </param>
+        /// <param name="height">
+        /// The height.
+        /// </param>
+        /// <param name="pixelData">
+        /// The pixel data (BGRA from bottom-left).
+        /// </param>
+        /// <param name="dpi">
+        /// The resolution.
+        /// </param>
+        /// <returns>
+        /// An <see cref="OxyImage"/>.
+        /// </returns>
+        /// <remarks>
+        /// This method is creating a Bitmap V4 info header, including channel bit masks and color space 
information.
+        /// </remarks>
+        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());
+        }
+
+        /// <summary>
+        /// Creates an <see cref="OxyImage"/> from the specified 8-bit indexed pixel data.
+        /// </summary>
+        /// <param name="indexedData">
+        /// The indexed pixel data (from bottom-left).
+        /// </param>
+        /// <param name="palette">
+        /// The palette.
+        /// </param>
+        /// <param name="dpi">
+        /// The resolution.
+        /// </param>
+        /// <returns>
+        /// An <see cref="OxyImage"/>.
+        /// </returns>
+        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<byte>().ToArray(), palette, dpi);
+        }
+
+        /// <summary>
+        /// Creates an <see cref="OxyImage"/> from the specified 8-bit indexed pixel data.
+        /// </summary>
+        /// <param name="width">
+        /// The width.
+        /// </param>
+        /// <param name="height">
+        /// The height.
+        /// </param>
+        /// <param name="indexedPixelData">
+        /// The indexed pixel data (from bottom-left).
+        /// </param>
+        /// <param name="palette">
+        /// The palette.
+        /// </param>
+        /// <param name="dpi">
+        /// The resolution.
+        /// </param>
+        /// <returns>
+        /// An <see cref="OxyImage"/>.
+        /// </returns>
+        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());
+        }
+
+        /// <summary>
+        /// Creates an <see cref="OxyImage"/> from the specified pixel data.
+        /// </summary>
+        /// <param name="width">
+        /// The width.
+        /// </param>
+        /// <param name="height">
+        /// The height.
+        /// </param>
+        /// <param name="pixelData">
+        /// The pixel data (BGRA from bottom-left).
+        /// </param>
+        /// <param name="dpi">
+        /// The resolution.
+        /// </param>
+        /// <returns>
+        /// An <see cref="OxyImage"/>.
+        /// </returns>
+        /// <remarks>
+        /// This method is creating a simple BitmapInfoHeader.
+        /// </remarks>
+        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());
+        }
+
+        /// <summary>
+        /// Gets the image data.
+        /// </summary>
+        /// <returns>
+        /// The image data as a byte array.
+        /// </returns>
+        public byte[] GetData()
+        {
+            return this.data;
+        }
+
+        /// <summary>
+        /// Writes the bitmap info header.
+        /// </summary>
+        /// <param name="w">
+        /// The writer.
+        /// </param>
+        /// <param name="width">
+        /// The width.
+        /// </param>
+        /// <param name="height">
+        /// The height.
+        /// </param>
+        /// <param name="bitsPerPixel">
+        /// The number of bits per pixel.
+        /// </param>
+        /// <param name="length">
+        /// The length of the pixel data.
+        /// </param>
+        /// <param name="dpi">
+        /// The dpi.
+        /// </param>
+        /// <param name="colors">
+        /// The number of colors.
+        /// </param>
+        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);
+        }
+
+        /// <summary>
+        /// Writes the bitmap V4 header.
+        /// </summary>
+        /// <param name="w">
+        /// The writer.
+        /// </param>
+        /// <param name="width">
+        /// The width.
+        /// </param>
+        /// <param name="height">
+        /// The height.
+        /// </param>
+        /// <param name="bitsPerPixel">
+        /// The number of bits per pixel.
+        /// </param>
+        /// <param name="length">
+        /// The length.
+        /// </param>
+        /// <param name="dpi">
+        /// The resolution.
+        /// </param>
+        /// <param name="colors">
+        /// The number of colors.
+        /// </param>
+        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);
+        }
+
+        /// <summary>
+        /// Creates a PNG image from the specified pixels.
+        /// </summary>
+        /// <param name="pixels">The pixels (bottom line first).</param>
+        /// <returns>An OxyImage.</returns>
+        public static OxyImage PngFromArgb(OxyColor[,] pixels)
+        {
+            return new OxyImage(PngEncoder.Encode(pixels));
+        }
+    }
+}
\ No newline at end of file
diff --git a/oxyplot/OxyPlot/Foundation/OxyPalette.cs b/oxyplot/OxyPlot/Foundation/OxyPalette.cs
new file mode 100644
index 0000000..1240c18
--- /dev/null
+++ b/oxyplot/OxyPlot/Foundation/OxyPalette.cs
@@ -0,0 +1,102 @@
+// 
--------------------------------------------------------------------------------------------------------------------
+// <copyright file="OxyPalette.cs" company="OxyPlot">
+//   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.
+// </copyright>
+// <summary>
+//   Represents a palette of colors.
+// </summary>
+// 
--------------------------------------------------------------------------------------------------------------------
+namespace OxyPlot
+{
+    using System.Collections.Generic;
+
+    /// <summary>
+    /// Represents a palette of colors.
+    /// </summary>
+    public class OxyPalette
+    {
+        /// <summary>
+        /// Initializes a new instance of the <see cref="OxyPalette"/> class.
+        /// </summary>
+        public OxyPalette()
+        {
+            this.Colors = new List<OxyColor>();
+        }
+
+        /// <summary>
+        /// Initializes a new instance of the <see cref="OxyPalette"/> class.
+        /// </summary>
+        /// <param name="colors">
+        /// The colors.
+        /// </param>
+        public OxyPalette(params OxyColor[] colors)
+        {
+            this.Colors = new List<OxyColor>(colors);
+        }
+
+        /// <summary>
+        /// Initializes a new instance of the <see cref="OxyPalette"/> class.
+        /// </summary>
+        /// <param name="colors">
+        /// The colors.
+        /// </param>
+        public OxyPalette(IEnumerable<OxyColor> colors)
+        {
+            this.Colors = new List<OxyColor>(colors);
+        }
+
+        /// <summary>
+        /// Gets or sets the colors.
+        /// </summary>
+        /// <value> The colors. </value>
+        public IList<OxyColor> Colors { get; set; }
+
+        /// <summary>
+        /// Interpolates the specified colors to a palette of the specified size.
+        /// </summary>
+        /// <param name="paletteSize">
+        /// The size of the palette.
+        /// </param>
+        /// <param name="colors">
+        /// The colors.
+        /// </param>
+        /// <returns>
+        /// A palette.
+        /// </returns>
+        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 --git a/oxyplot/OxyPlot/Foundation/OxyPalettes.cs b/oxyplot/OxyPlot/Foundation/OxyPalettes.cs
new file mode 100644
index 0000000..2fbe27a
--- /dev/null
+++ b/oxyplot/OxyPlot/Foundation/OxyPalettes.cs
@@ -0,0 +1,208 @@
+// 
--------------------------------------------------------------------------------------------------------------------
+// <copyright file="OxyPalettes.cs" company="OxyPlot">
+//   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.
+// </copyright>
+// <summary>
+//   Provides predefined palettes.
+// </summary>
+// 
--------------------------------------------------------------------------------------------------------------------
+namespace OxyPlot
+{
+    /// <summary>
+    /// Provides predefined palettes.
+    /// </summary>
+    public static class OxyPalettes
+    {
+        /// <summary>
+        /// Initializes static members of the <see cref="OxyPalettes"/> class.
+        /// </summary>
+        static OxyPalettes()
+        {
+            BlueWhiteRed31 = BlueWhiteRed(31);
+            Hot64 = Hot(64);
+            Hue64 = Hue(64);
+        }
+
+        /// <summary>
+        /// Gets the blue white red (31) palette.
+        /// </summary>
+        public static OxyPalette BlueWhiteRed31 { get; private set; }
+
+        /// <summary>
+        /// Gets the hot (64) palette.
+        /// </summary>
+        public static OxyPalette Hot64 { get; private set; }
+
+        /// <summary>
+        /// Gets the hue64 palette.
+        /// </summary>
+        public static OxyPalette Hue64 { get; private set; }
+
+        /// <summary>
+        /// Creates a black/white/red palette with the specified number of colors.
+        /// </summary>
+        /// <param name="numberOfColors">
+        /// The number of colors to create for the palette.
+        /// </param>
+        /// <returns>
+        /// A palette.
+        /// </returns>
+        public static OxyPalette BlackWhiteRed(int numberOfColors)
+        {
+            return OxyPalette.Interpolate(numberOfColors, OxyColors.Black, OxyColors.White, OxyColors.Red);
+        }
+
+        /// <summary>
+        /// Creates a blue/white/red palette with the specified number of colors.
+        /// </summary>
+        /// <param name="numberOfColors">
+        /// The number of colors to create for the palette.
+        /// </param>
+        /// <returns>
+        /// A palette.
+        /// </returns>
+        public static OxyPalette BlueWhiteRed(int numberOfColors)
+        {
+            return OxyPalette.Interpolate(numberOfColors, OxyColors.Blue, OxyColors.White, OxyColors.Red);
+        }
+
+        /// <summary>
+        /// Creates a 'cool' palette with the specified number of colors.
+        /// </summary>
+        /// <param name="numberOfColors">
+        /// The number of colors to create for the palette.
+        /// </param>
+        /// <returns>
+        /// A palette.
+        /// </returns>
+        public static OxyPalette Cool(int numberOfColors)
+        {
+            return OxyPalette.Interpolate(numberOfColors, OxyColors.Cyan, OxyColors.Magenta);
+        }
+
+        /// <summary>
+        /// Creates a gray-scale palette with the specified number of colors.
+        /// </summary>
+        /// <param name="numberOfColors">
+        /// The number of colors to create for the palette.
+        /// </param>
+        /// <returns>
+        /// A palette.
+        /// </returns>
+        public static OxyPalette Gray(int numberOfColors)
+        {
+            return OxyPalette.Interpolate(numberOfColors, OxyColors.Black, OxyColors.White);
+        }
+
+        /// <summary>
+        /// Creates a 'hot' palette with the specified number of colors.
+        /// </summary>
+        /// <param name="numberOfColors">
+        /// The number of colors to create for the palette.
+        /// </param>
+        /// <returns>
+        /// A palette.
+        /// </returns>
+        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);
+        }
+
+        /// <summary>
+        /// Creates a palette from the hue component of the HSV color model.
+        /// </summary>
+        /// <param name="numberOfColors">
+        /// The number of colors.
+        /// </param>
+        /// <returns>
+        /// The palette.
+        /// </returns>
+        /// <remarks>
+        /// This palette is particularly appropriate for displaying periodic functions.
+        /// </remarks>
+        public static OxyPalette Hue(int numberOfColors)
+        {
+            return OxyPalette.Interpolate(
+                numberOfColors,
+                OxyColors.Red,
+                OxyColors.Yellow,
+                OxyColors.Green,
+                OxyColors.Cyan,
+                OxyColors.Blue,
+                OxyColors.Magenta,
+                OxyColors.Red);
+        }
+
+        /// <summary>
+        /// Creates a 'jet' palette with the specified number of colors.
+        /// </summary>
+        /// <param name="numberOfColors">
+        /// The number of colors to create for the palette.
+        /// </param>
+        /// <returns>
+        /// A palette.
+        /// </returns>
+        /// <remarks>
+        /// See http://www.mathworks.se/help/techdoc/ref/colormap.html.
+        /// </remarks>
+        public static OxyPalette Jet(int numberOfColors)
+        {
+            return OxyPalette.Interpolate(
+                numberOfColors,
+                OxyColors.DarkBlue,
+                OxyColors.Cyan,
+                OxyColors.Yellow,
+                OxyColors.Orange,
+                OxyColors.DarkRed);
+        }
+
+        /// <summary>
+        /// Creates a rainbow palette with the specified number of colors.
+        /// </summary>
+        /// <param name="numberOfColors">
+        /// The number of colors to create for the palette.
+        /// </param>
+        /// <returns>
+        /// A palette.
+        /// </returns>
+        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 --git a/oxyplot/OxyPlot/Foundation/OxyPen.cs b/oxyplot/OxyPlot/Foundation/OxyPen.cs
new file mode 100644
index 0000000..16127f3
--- /dev/null
+++ b/oxyplot/OxyPlot/Foundation/OxyPen.cs
@@ -0,0 +1,138 @@
+// 
--------------------------------------------------------------------------------------------------------------------
+// <copyright file="OxyPen.cs" company="OxyPlot">
+//   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.
+// </copyright>
+// <summary>
+//   Describes a pen in terms of color, thickness, line style and line join type.
+// </summary>
+// 
--------------------------------------------------------------------------------------------------------------------
+namespace OxyPlot
+{
+    using System;
+
+    /// <summary>
+    /// Describes a pen in terms of color, thickness, line style and line join type.
+    /// </summary>
+    public class OxyPen
+    {
+        /// <summary>
+        /// Initializes a new instance of the <see cref="OxyPen"/> class.
+        /// </summary>
+        /// <param name="color">
+        /// The color.
+        /// </param>
+        /// <param name="thickness">
+        /// The thickness.
+        /// </param>
+        /// <param name="lineStyle">
+        /// The line style.
+        /// </param>
+        /// <param name="lineJoin">
+        /// The line join.
+        /// </param>
+        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;
+        }
+
+        /// <summary>
+        /// Gets or sets the color.
+        /// </summary>
+        /// <value>The color.</value>
+        public OxyColor Color { get; set; }
+
+        /// <summary>
+        /// Gets or sets the dash array.
+        /// </summary>
+        /// <value>The dash array.</value>
+        public double[] DashArray { get; set; }
+
+        /// <summary>
+        /// Gets or sets the line join.
+        /// </summary>
+        /// <value>The line join.</value>
+        public OxyPenLineJoin LineJoin { get; set; }
+
+        /// <summary>
+        /// Gets or sets the line style.
+        /// </summary>
+        /// <value>The line style.</value>
+        public LineStyle LineStyle { get; set; }
+
+        /// <summary>
+        /// Gets or sets the thickness.
+        /// </summary>
+        /// <value>The thickness.</value>
+        public double Thickness { get; set; }
+
+        /// <summary>
+        /// Creates the specified pen.
+        /// </summary>
+        /// <param name="color">The color.</param>
+        /// <param name="thickness">The thickness.</param>
+        /// <param name="lineStyle">The line style.</param>
+        /// <param name="lineJoin">The line join.</param>
+        /// <returns>A pen.</returns>
+        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);
+        }
+
+        /// <summary>
+        /// Returns a hash code for this instance.
+        /// </summary>
+        /// <returns>
+        /// A hash code for this instance, suitable for use in hashing algorithms and data structures like a 
hash table.
+        /// </returns>
+        public override int GetHashCode()
+        {
+            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 --git a/oxyplot/OxyPlot/Foundation/OxyPenLineJoin.cs b/oxyplot/OxyPlot/Foundation/OxyPenLineJoin.cs
new file mode 100644
index 0000000..22a0cbf
--- /dev/null
+++ b/oxyplot/OxyPlot/Foundation/OxyPenLineJoin.cs
@@ -0,0 +1,52 @@
+// 
--------------------------------------------------------------------------------------------------------------------
+// <copyright file="OxyPenLineJoin.cs" company="OxyPlot">
+//   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.
+// </copyright>
+// <summary>
+//   Pen line join.
+// </summary>
+// 
--------------------------------------------------------------------------------------------------------------------
+namespace OxyPlot
+{
+    /// <summary>
+    /// Specifies how to join line segments.
+    /// </summary>
+    public enum OxyPenLineJoin
+    {
+        /// <summary>
+        /// Line joins use regular angular vertices.
+        /// </summary>
+        Miter,
+
+        /// <summary>
+        /// Line joins use rounded vertices.
+        /// </summary>
+        Round,
+
+        /// <summary>
+        /// Line joins use beveled vertices.
+        /// </summary>
+        Bevel
+    }
+}
\ No newline at end of file
diff --git a/oxyplot/OxyPlot/Foundation/OxyRect.cs b/oxyplot/OxyPlot/Foundation/OxyRect.cs
new file mode 100644
index 0000000..a8072f1
--- /dev/null
+++ b/oxyplot/OxyPlot/Foundation/OxyRect.cs
@@ -0,0 +1,287 @@
+// 
--------------------------------------------------------------------------------------------------------------------
+// <copyright file="OxyRect.cs" company="OxyPlot">
+//   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.
+// </copyright>
+// <summary>
+//   Describes the width, height, and point origin of a rectangle.
+// </summary>
+// 
--------------------------------------------------------------------------------------------------------------------
+namespace OxyPlot
+{
+    using System;
+    using System.Diagnostics;
+    using System.Globalization;
+
+    /// <summary>
+    /// Describes the width, height, and point origin of a rectangle.
+    /// </summary>
+    public struct OxyRect
+    {
+        /// <summary>
+        /// The height of the rectangle.
+        /// </summary>
+        private double height;
+
+        /// <summary>
+        /// The x-coordinate location of the left side of the rectangle.
+        /// </summary>
+        private double left;
+
+        /// <summary>
+        /// The y-coordinate location of the top side of the rectangle.
+        /// </summary>
+        private double top;
+
+        /// <summary>
+        /// The width of the rectangle.
+        /// </summary>
+        private double width;
+
+        /// <summary>
+        /// Initializes a new instance of the <see cref="OxyRect"/> structure that has the specified 
x-coordinate, y-coordinate, width, and height.
+        /// </summary>
+        /// <param name="left">
+        /// The x-coordinate location of the left side of the rectangle.
+        /// </param>
+        /// <param name="top">
+        /// The y-coordinate location of the top side of the rectangle.
+        /// </param>
+        /// <param name="width">
+        /// The width of the rectangle.
+        /// </param>
+        /// <param name="height">
+        /// The height of the rectangle.
+        /// </param>
+        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.");
+        }
+
+        /// <summary>
+        /// Gets or sets the y-axis value of the bottom of the rectangle.
+        /// </summary>
+        /// <value>
+        /// The bottom.
+        /// </value>
+        public double Bottom
+        {
+            get
+            {
+                return this.top + this.height;
+            }
+
+            set
+            {
+                this.height = value - this.top;
+            }
+        }
+
+        /// <summary>
+        /// Gets or sets the height of the rectangle.
+        /// </summary>
+        /// <value>
+        /// The height.
+        /// </value>
+        public double Height
+        {
+            get
+            {
+                return this.height;
+            }
+
+            set
+            {
+                this.height = value;
+            }
+        }
+
+        /// <summary>
+        /// Gets or sets the x-axis value of the left side of the rectangle.
+        /// </summary>
+        /// <value>
+        /// The left.
+        /// </value>
+        public double Left
+        {
+            get
+            {
+                return this.left;
+            }
+
+            set
+            {
+                this.left = value;
+            }
+        }
+
+        /// <summary>
+        /// Gets or sets the x-axis value of the right side of the rectangle.
+        /// </summary>
+        /// <value>
+        /// The right.
+        /// </value>
+        public double Right
+        {
+            get
+            {
+                return this.left + this.width;
+            }
+
+            set
+            {
+                this.width = value - this.left;
+            }
+        }
+
+        /// <summary>
+        /// Gets or sets the y-axis position of the top of the rectangle.
+        /// </summary>
+        /// <value>
+        /// The top.
+        /// </value>
+        public double Top
+        {
+            get
+            {
+                return this.top;
+            }
+
+            set
+            {
+                this.top = value;
+            }
+        }
+
+        /// <summary>
+        /// Gets or sets the width of the rectangle.
+        /// </summary>
+        /// <value>
+        /// The width.
+        /// </value>
+        public double Width
+        {
+            get
+            {
+                return this.width;
+            }
+
+            set
+            {
+                this.width = value;
+            }
+        }
+
+        /// <summary>
+        /// Gets the center point of the rectangle.
+        /// </summary>
+        /// <value>The center.</value>
+        public ScreenPoint Center
+        {
+            get
+            {
+                return new ScreenPoint(this.left + (this.width * 0.5), this.top + (this.height * 0.5));
+            }
+        }
+
+        /// <summary>
+        /// Creates a rectangle from the specified corner coordinates.
+        /// </summary>
+        /// <param name="x0">
+        /// The x0.
+        /// </param>
+        /// <param name="y0">
+        /// The y0.
+        /// </param>
+        /// <param name="x1">
+        /// The x1.
+        /// </param>
+        /// <param name="y1">
+        /// The y1.
+        /// </param>
+        /// <returns>
+        /// A rectangle.
+        /// </returns>
+        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));
+        }
+
+        /// <summary>
+        /// Creates a rectangle from the specified corner coordinates.
+        /// </summary>
+        /// <param name="p0">The first corner.</param>
+        /// <param name="p1">The second corner.</param>
+        /// <returns>A rectangle.</returns>
+        public static OxyRect Create(ScreenPoint p0, ScreenPoint p1)
+        {
+            return Create(p0.X, p0.Y, p1.X, p1.Y);
+        }
+
+        /// <summary>
+        /// Determines whether the specified point is inside the rectangle.
+        /// </summary>
+        /// <param name="x">
+        /// The x coordinate.
+        /// </param>
+        /// <param name="y">
+        /// The y coordinate.
+        /// </param>
+        /// <returns>
+        /// <c>true</c> if the rectangle contains the specified point; otherwise, <c>false</c>.
+        /// </returns>
+        public bool Contains(double x, double y)
+        {
+            return x >= this.Left && x <= this.Right && y >= this.Top && y <= this.Bottom;
+        }
+
+        /// <summary>
+        /// Determines whether the specified point is inside the rectangle.
+        /// </summary>
+        /// <param name="p">The point.</param>
+        /// <returns>
+        /// <c>true</c> if the rectangle contains the specified point; otherwise, <c>false</c>.
+        /// </returns>
+        public bool Contains(ScreenPoint p)
+        {
+            return this.Contains(p.x, p.y);
+        }
+
+        /// <summary>
+        /// Returns a <see cref="System.String"/> that represents this instance.
+        /// </summary>
+        /// <returns>
+        /// A <see cref="System.String"/> that represents this instance.
+        /// </returns>
+        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 --git a/oxyplot/OxyPlot/Foundation/OxySize.cs b/oxyplot/OxyPlot/Foundation/OxySize.cs
new file mode 100644
index 0000000..b31ba1b
--- /dev/null
+++ b/oxyplot/OxyPlot/Foundation/OxySize.cs
@@ -0,0 +1,87 @@
+// 
--------------------------------------------------------------------------------------------------------------------
+// <copyright file="OxySize.cs" company="OxyPlot">
+//   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.
+// </copyright>
+// <summary>
+//   Implements a structure that is used to describe the Size of an object.
+// </summary>
+// 
--------------------------------------------------------------------------------------------------------------------
+namespace OxyPlot
+{
+    using System.Globalization;
+
+    /// <summary>
+    /// Implements a structure that is used to describe the size of an object.
+    /// </summary>
+    public struct OxySize
+    {
+        /// <summary>
+        /// Empty Size.
+        /// </summary>
+        public static OxySize Empty = new OxySize(0, 0);
+
+        /// <summary>
+        /// Initializes a new instance of the <see cref="OxySize"/> struct.
+        /// </summary>
+        /// <param name="width">
+        /// The width.
+        /// </param>
+        /// <param name="height">
+        /// The height.
+        /// </param>
+        public OxySize(double width, double height)
+            : this()
+        {
+            this.Width = width;
+            this.Height = height;
+        }
+
+        /// <summary>
+        /// Gets or sets the height.
+        /// </summary>
+        /// <value>
+        /// The height.
+        /// </value>
+        public double Height { get; set; }
+
+        /// <summary>
+        /// Gets or sets the width.
+        /// </summary>
+        /// <value>
+        /// The width.
+        /// </value>
+        public double Width { get; set; }
+
+        /// <summary>
+        /// Returns a <see cref="System.String"/> that represents this instance.
+        /// </summary>
+        /// <returns>
+        /// A <see cref="System.String"/> that represents this instance.
+        /// </returns>
+        public override string ToString()
+        {
+            return string.Format(CultureInfo.InvariantCulture, "({0}, {1})", this.Width, this.Height);
+        }
+    }
+}
\ No newline at end of file
diff --git a/oxyplot/OxyPlot/Foundation/OxyThickness.cs b/oxyplot/OxyPlot/Foundation/OxyThickness.cs
new file mode 100644
index 0000000..548876d
--- /dev/null
+++ b/oxyplot/OxyPlot/Foundation/OxyThickness.cs
@@ -0,0 +1,220 @@
+// 
--------------------------------------------------------------------------------------------------------------------
+// <copyright file="OxyThickness.cs" company="OxyPlot">
+//   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.
+// </copyright>
+// <summary>
+//   Describes the thickness of a frame around a rectangle. Four Double values describe the Left, Top, 
Right, and Bottom sides of the rectangle, respectively.
+// </summary>
+// 
--------------------------------------------------------------------------------------------------------------------
+namespace OxyPlot
+{
+    using System.Globalization;
+
+    /// <summary>
+    /// Describes the thickness of a frame around a rectangle. Four <see cref="System.Double"/> values 
describe the left, top, right, and bottom sides of the rectangle, respectively.
+    /// </summary>
+    public struct OxyThickness : ICodeGenerating
+    {
+        /// <summary>
+        /// The bottom.
+        /// </summary>
+        private double bottom;
+
+        /// <summary>
+        /// The left.
+        /// </summary>
+        private double left;
+
+        /// <summary>
+        /// The right.
+        /// </summary>
+        private double right;
+
+        /// <summary>
+        /// The top.
+        /// </summary>
+        private double top;
+
+        /// <summary>
+        /// Initializes a new instance of the <see cref="OxyThickness"/> struct.
+        /// </summary>
+        /// <param name="thickness">
+        /// The thickness.
+        /// </param>
+        public OxyThickness(double thickness)
+            : this(thickness, thickness, thickness, thickness)
+        {
+        }
+
+        /// <summary>
+        /// Initializes a new instance of the <see cref="OxyThickness"/> struct.
+        /// </summary>
+        /// <param name="left">
+        /// The left.
+        /// </param>
+        /// <param name="top">
+        /// The top.
+        /// </param>
+        /// <param name="right">
+        /// The right.
+        /// </param>
+        /// <param name="bottom">
+        /// The bottom.
+        /// </param>
+        public OxyThickness(double left, double top, double right, double bottom)
+        {
+            this.left = left;
+            this.top = top;
+            this.right = right;
+            this.bottom = bottom;
+        }
+
+        /// <summary>
+        /// Gets or sets the bottom thickness.
+        /// </summary>
+        /// <value>
+        /// The bottom thickness.
+        /// </value>
+        public double Bottom
+        {
+            get
+            {
+                return this.bottom;
+            }
+
+            set
+            {
+                this.bottom = value;
+            }
+        }
+
+        /// <summary>
+        /// Gets the height.
+        /// </summary>
+        public double Height
+        {
+            get
+            {
+                return this.Bottom - this.Top;
+            }
+        }
+
+        /// <summary>
+        /// Gets or sets the left thickness.
+        /// </summary>
+        /// <value>
+        /// The left thickness.
+        /// </value>
+        public double Left
+        {
+            get
+            {
+                return this.left;
+            }
+
+            set
+            {
+                this.left = value;
+            }
+        }
+
+        /// <summary>
+        /// Gets or sets the right thickness.
+        /// </summary>
+        /// <value>
+        /// The right thickness.
+        /// </value>
+        public double Right
+        {
+            get
+            {
+                return this.right;
+            }
+
+            set
+            {
+                this.right = value;
+            }
+        }
+
+        /// <summary>
+        /// Gets or sets the top thickness.
+        /// </summary>
+        /// <value>
+        /// The top thickness.
+        /// </value>
+        public double Top
+        {
+            get
+            {
+                return this.top;
+            }
+
+            set
+            {
+                this.top = value;
+            }
+        }
+
+        /// <summary>
+        /// Gets the width.
+        /// </summary>
+        public double Width
+        {
+            get
+            {
+                return this.Right - this.Left;
+            }
+        }
+
+        /// <summary>
+        /// Returns C# code that generates this instance.
+        /// </summary>
+        /// <returns>
+        /// The to code.
+        /// </returns>
+        public string ToCode()
+        {
+            return string.Format(
+                CultureInfo.InvariantCulture,
+                "new OxyThickness({0},{1},{2},{3})",
+                this.Left,
+                this.Top,
+                this.Right,
+                this.Bottom);
+        }
+
+        /// <summary>
+        /// Returns a <see cref="System.String"/> that represents this instance.
+        /// </summary>
+        /// <returns>
+        /// A <see cref="System.String"/> that represents this instance.
+        /// </returns>
+        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 --git a/oxyplot/OxyPlot/Foundation/Pen.cs b/oxyplot/OxyPlot/Foundation/Pen.cs
new file mode 100644
index 0000000..4cbd390
--- /dev/null
+++ b/oxyplot/OxyPlot/Foundation/Pen.cs
@@ -0,0 +1,42 @@
+// 
--------------------------------------------------------------------------------------------------------------------
+// <copyright file="Pen.cs" company="OxyPlot">
+//   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.
+// </copyright>
+// 
--------------------------------------------------------------------------------------------------------------------
+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 --git a/oxyplot/OxyPlot/Foundation/PlotLength.cs b/oxyplot/OxyPlot/Foundation/PlotLength.cs
new file mode 100644
index 0000000..e29e4bf
--- /dev/null
+++ b/oxyplot/OxyPlot/Foundation/PlotLength.cs
@@ -0,0 +1,91 @@
+// 
--------------------------------------------------------------------------------------------------------------------
+// <copyright file="PlotLength.cs" company="OxyPlot">
+//   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.
+// </copyright>
+// <summary>
+//   Represents lengths in the plot.
+// </summary>
+// 
--------------------------------------------------------------------------------------------------------------------
+
+namespace OxyPlot
+{
+    /// <summary>
+    /// Represents lengths in the plot. 
+    /// </summary>
+    public struct PlotLength
+    {
+        /// <summary>
+        /// The unit type
+        /// </summary>
+        private readonly PlotLengthUnit unit;
+
+        /// <summary>
+        /// The value
+        /// </summary>
+        private readonly double value;
+
+        /// <summary>
+        /// Initializes a new instance of the <see cref="PlotLength"/> struct.
+        /// </summary>
+        /// <param name="value">
+        /// The value.
+        /// </param>
+        /// <param name="unit">
+        /// The unit.
+        /// </param>
+        public PlotLength(double value, PlotLengthUnit unit)
+        {
+            this.value = value;
+            this.unit = unit;
+        }
+
+        /// <summary>
+        /// Gets the value.
+        /// </summary>
+        /// <value>
+        /// The value.
+        /// </value>
+        public double Value
+        {
+            get
+            {
+                return this.value;
+            }
+        }
+
+        /// <summary>
+        /// Gets the type of the unit.
+        /// </summary>
+        /// <value>
+        /// The type of the unit.
+        /// </value>
+        public PlotLengthUnit Unit
+        {
+            get
+            {
+                return this.unit;
+            }
+        }
+    }
+}
\ No newline at end of file
diff --git a/oxyplot/OxyPlot/Foundation/PlotLengthUnit.cs b/oxyplot/OxyPlot/Foundation/PlotLengthUnit.cs
new file mode 100644
index 0000000..79bea0c
--- /dev/null
+++ b/oxyplot/OxyPlot/Foundation/PlotLengthUnit.cs
@@ -0,0 +1,58 @@
+// 
--------------------------------------------------------------------------------------------------------------------
+// <copyright file="PlotLengthUnit.cs" company="OxyPlot">
+//   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.
+// </copyright>
+// <summary>
+//   Describes the kind of value that a <see cref="PlotLength" /> object is holding.
+// </summary>
+// 
--------------------------------------------------------------------------------------------------------------------
+
+namespace OxyPlot
+{
+    /// <summary>
+    /// Describes the kind of value that a <see cref="PlotLength"/> object is holding.
+    /// </summary>
+    public enum PlotLengthUnit
+    {
+        /// <summary>
+        /// The value is in data space (transformed by x/y axis)
+        /// </summary>
+        Data = 0, 
+
+        /// <summary>
+        /// The value is in screen units
+        /// </summary>
+        ScreenUnits = 1, 
+
+        /// <summary>
+        /// The value is relative to the plot viewport (0-1)
+        /// </summary>
+        RelativeToViewport = 2, 
+
+        /// <summary>
+        /// The value is relative to the plot area (0-1)
+        /// </summary>
+        RelativeToPlotArea = 3
+    }
+}
\ No newline at end of file
diff --git a/oxyplot/OxyPlot/Foundation/PngEncoder.cs b/oxyplot/OxyPlot/Foundation/PngEncoder.cs
new file mode 100644
index 0000000..af6f090
--- /dev/null
+++ b/oxyplot/OxyPlot/Foundation/PngEncoder.cs
@@ -0,0 +1,323 @@
+// 
--------------------------------------------------------------------------------------------------------------------
+// <copyright file="PngEncoder.cs" company="OxyPlot">
+//   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.
+// </copyright>
+// 
--------------------------------------------------------------------------------------------------------------------
+
+namespace OxyPlot
+{
+    using System;
+    using System.Collections.Generic;
+    using System.IO;
+    using System.Linq;
+
+    /// <summary>
+    /// Provides encoding of uncompressed png images.
+    /// </summary>
+    public class PngEncoder
+    {
+        /// <summary>
+        /// The CRC table
+        /// </summary>
+        private static readonly ulong[] CrcTable;
+
+        /// <summary>
+        /// Initializes static members of the <see cref="PngEncoder" /> class.
+        /// </summary>
+        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;
+            }
+        }
+
+        /// <summary>
+        /// Encodes the specified image data to png.
+        /// </summary>
+        /// <param name="pixels">
+        /// The pixel data (bottom line first).
+        /// </param>
+        /// <param name="dpi">
+        /// The image resolution in dots per inch.
+        /// </param>
+        /// <returns>
+        /// The png image data.
+        /// </returns>
+        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();
+        }
+
+        /// <summary>
+        /// Calculates the Adler-32 check sum.
+        /// </summary>
+        /// <param name="data">
+        /// The data.
+        /// </param>
+        /// <returns>
+        /// The check sum.
+        /// </returns>
+        private static uint Adler32(IEnumerable<byte> 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;
+        }
+
+        /// <summary>
+        /// Creates the header data.
+        /// </summary>
+        /// <param name="width">
+        /// The width.
+        /// </param>
+        /// <param name="height">
+        /// The height.
+        /// </param>
+        /// <returns>
+        /// The header.
+        /// </returns>
+        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();
+        }
+
+        /// <summary>
+        /// Creates the physical dimensions data.
+        /// </summary>
+        /// <param name="dpix">
+        /// The horizontal resolution.
+        /// </param>
+        /// <param name="dpiy">
+        /// The vertical resolution.
+        /// </param>
+        /// <returns>
+        /// The data.
+        /// </returns>
+        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();
+        }
+
+        /// <summary>
+        /// Creates the uncompressed blocks.
+        /// </summary>
+        /// <param name="bytes">
+        /// The data.
+        /// </param>
+        /// <returns>
+        /// The output data.
+        /// </returns>
+        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();
+        }
+
+        /// <summary>
+        /// Updates the CRC check sum.
+        /// </summary>
+        /// <param name="crc">
+        /// The input CRC.
+        /// </param>
+        /// <param name="data">
+        /// The data.
+        /// </param>
+        /// <returns>
+        /// The updated CRC.
+        /// </returns>
+        private static ulong UpdateCrc(ulong crc, IEnumerable<byte> data)
+        {
+            return data.Aggregate(crc, (current, x) => CrcTable[(current ^ x) & 0xff] ^ (current >> 8));
+        }
+
+        /// <summary>
+        /// Writes the integer value with big endian byte order.
+        /// </summary>
+        /// <param name="w">
+        /// The writer.
+        /// </param>
+        /// <param name="value">
+        /// The value.
+        /// </param>
+        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]);
+        }
+
+        /// <summary>
+        /// Writes the unsigned integer value with big endian byte order.
+        /// </summary>
+        /// <param name="w">
+        /// The writer.
+        /// </param>
+        /// <param name="value">
+        /// The value.
+        /// </param>
+        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]);
+        }
+
+        /// <summary>
+        /// Writes a png chunk.
+        /// </summary>
+        /// <param name="w">
+        /// The writer.
+        /// </param>
+        /// <param name="type">
+        /// The chunk type.
+        /// </param>
+        /// <param name="data">
+        /// The chunk data.
+        /// </param>
+        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);
+        }
+
+        /// <summary>
+        /// Provides a binary writer that writes to memory.
+        /// </summary>
+        private class MemoryWriter : BinaryWriter
+        {
+            /// <summary>
+            /// Initializes a new instance of the <see cref="MemoryWriter" /> class.
+            /// </summary>
+            public MemoryWriter()
+                : base(new MemoryStream())
+            {
+            }
+
+            /// <summary>
+            /// Gets the content as a byte array.
+            /// </summary>
+            /// <returns>The byte array.</returns>
+            public byte[] ToArray()
+            {
+                this.BaseStream.Flush();
+                return ((MemoryStream)this.BaseStream).ToArray();
+            }
+        }
+    }
+}
\ No newline at end of file
diff --git a/oxyplot/OxyPlot/Foundation/Point.cs b/oxyplot/OxyPlot/Foundation/Point.cs
new file mode 100644
index 0000000..1dd3b52
--- /dev/null
+++ b/oxyplot/OxyPlot/Foundation/Point.cs
@@ -0,0 +1,58 @@
+// 
--------------------------------------------------------------------------------------------------------------------
+// <copyright file="Point.cs" company="OxyPlot">
+//   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.
+// </copyright>
+// 
--------------------------------------------------------------------------------------------------------------------
+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 --git a/oxyplot/OxyPlot/Foundation/Rectangle.cs b/oxyplot/OxyPlot/Foundation/Rectangle.cs
new file mode 100644
index 0000000..da5b00e
--- /dev/null
+++ b/oxyplot/OxyPlot/Foundation/Rectangle.cs
@@ -0,0 +1,36 @@
+// 
--------------------------------------------------------------------------------------------------------------------
+// <copyright file="Rectangle.cs" company="OxyPlot">
+//   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.
+// </copyright>
+// 
--------------------------------------------------------------------------------------------------------------------
+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 --git a/oxyplot/OxyPlot/Foundation/ReflectionHelper.cs b/oxyplot/OxyPlot/Foundation/ReflectionHelper.cs
new file mode 100644
index 0000000..8ec13c8
--- /dev/null
+++ b/oxyplot/OxyPlot/Foundation/ReflectionHelper.cs
@@ -0,0 +1,81 @@
+// 
--------------------------------------------------------------------------------------------------------------------
+// <copyright file="ReflectionHelper.cs" company="OxyPlot">
+//   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.
+// </copyright>
+// <summary>
+//   Provides reflection based support methods.
+// </summary>
+// 
--------------------------------------------------------------------------------------------------------------------
+namespace OxyPlot
+{
+    using System;
+    using System.Collections;
+    using System.Collections.Generic;
+    using System.Globalization;
+    using System.Reflection;
+
+    /// <summary>
+    /// Provides utility methods reflection based support methods.
+    /// </summary>
+    public static class ReflectionHelper
+    {
+        /// <summary>
+        /// Fills a list by the specified property of a source list/enumerable.
+        /// </summary>
+        /// <param name="source">
+        /// The source list.
+        /// </param>
+        /// <param name="propertyName">
+        /// The property name.
+        /// </param>
+        /// <param name="list">
+        /// The list to be filled.
+        /// </param>
+        /// <typeparam name="T">
+        /// The type of the destination list items (and the source property).
+        /// </typeparam>
+        public static void FillList<T>(IEnumerable source, string propertyName, IList<T> 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 --git a/oxyplot/OxyPlot/Foundation/ScreenPoint.cs b/oxyplot/OxyPlot/Foundation/ScreenPoint.cs
new file mode 100644
index 0000000..0abfb00
--- /dev/null
+++ b/oxyplot/OxyPlot/Foundation/ScreenPoint.cs
@@ -0,0 +1,198 @@
+// 
--------------------------------------------------------------------------------------------------------------------
+// <copyright file="ScreenPoint.cs" company="OxyPlot">
+//   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.
+// </copyright>
+// <summary>
+//   Describes a point defined in the screen coordinate system.
+// </summary>
+// 
--------------------------------------------------------------------------------------------------------------------
+namespace OxyPlot
+{
+    using System;
+
+    /// <summary>
+    /// Represents a point defined in the screen coordinate system.
+    /// </summary>
+    /// <remarks>
+    /// The rendering methods transforms <see cref="DataPoint"/>s to <see cref="ScreenPoint"/>s.
+    /// </remarks>
+    public struct ScreenPoint
+    {
+        /// <summary>
+        /// The undefined point.
+        /// </summary>
+        public static readonly ScreenPoint Undefined = new ScreenPoint(double.NaN, double.NaN);
+
+        /// <summary>
+        /// The x-coordinate.
+        /// </summary>
+        internal double x;
+
+        /// <summary>
+        /// The y-coordinate.
+        /// </summary>
+        internal double y;
+
+        /// <summary>
+        /// Initializes a new instance of the <see cref="ScreenPoint"/> struct.
+        /// </summary>
+        /// <param name="x">
+        /// The x-coordinate.
+        /// </param>
+        /// <param name="y">
+        /// The y-coordinate.
+        /// </param>
+        public ScreenPoint(double x, double y)
+        {
+            this.x = x;
+            this.y = y;
+        }
+
+        /// <summary>
+        /// Gets or sets the x-coordinate.
+        /// </summary>
+        /// <value> The x-coordinate. </value>
+        public double X
+        {
+            get
+            {
+                return this.x;
+            }
+
+            set
+            {
+                this.x = value;
+            }
+        }
+
+        /// <summary>
+        /// Gets or sets the y-coordinate.
+        /// </summary>
+        /// <value> The y-coordinate. </value>
+        public double Y
+        {
+            get
+            {
+                return this.y;
+            }
+
+            set
+            {
+                this.y = value;
+            }
+        }
+
+        /// <summary>
+        /// Determines whether the specified point is undefined.
+        /// </summary>
+        /// <param name="point">
+        /// The point.
+        /// </param>
+        /// <returns>
+        /// <c>true</c> if the specified point is undefined; otherwise, <c>false</c> .
+        /// </returns>
+        public static bool IsUndefined(ScreenPoint point)
+        {
+            return double.IsNaN(point.X) && double.IsNaN(point.Y);
+        }
+
+        /// <summary>
+        /// Gets the distance to the specified point.
+        /// </summary>
+        /// <param name="point">
+        /// The point.
+        /// </param>
+        /// <returns>
+        /// The distance.
+        /// </returns>
+        public double DistanceTo(ScreenPoint point)
+        {
+            double dx = point.x - this.x;
+            double dy = point.y - this.y;
+            return Math.Sqrt((dx * dx) + (dy * dy));
+        }
+
+        /// <summary>
+        /// Gets the squared distance to the specified point.
+        /// </summary>
+        /// <param name="point">
+        /// The point.
+        /// </param>
+        /// <returns>
+        /// The squared distance.
+        /// </returns>
+        public double DistanceToSquared(ScreenPoint point)
+        {
+            double dx = point.x - this.x;
+            double dy = point.y - this.y;
+            return (dx * dx) + (dy * dy);
+        }
+
+        /// <summary>
+        /// Returns a <see cref="System.String"/> that represents this instance.
+        /// </summary>
+        /// <returns>
+        /// A <see cref="System.String"/> that represents this instance.
+        /// </returns>
+        public override string ToString()
+        {
+            return this.x + " " + this.y;
+        }
+
+        /// <summary>
+        /// Translates a <see cref="ScreenPoint"/> by a <see cref="ScreenVector"/>.
+        /// </summary>
+        /// <param name="p1"> The point. </param>
+        /// <param name="p2"> The vector. </param>
+        /// <returns> The translated point. </returns>
+        public static ScreenPoint operator +(ScreenPoint p1, ScreenVector p2)
+        {
+            return new ScreenPoint(p1.x + p2.x, p1.y + p2.y);
+        }
+
+        /// <summary>
+        /// Subtracts a <see cref="ScreenPoint"/> from a <see cref="ScreenPoint"/>
+        /// and returns the result as a <see cref="ScreenVector"/>.
+        /// </summary>
+        /// <param name="p1"> The point on which to perform the subtraction. </param>
+        /// <param name="p2"> The point to subtract from p1. </param>
+        /// <returns> A <see cref="ScreenVector"/> structure that represents the difference between p1 and 
p2. </returns>
+        public static ScreenVector operator -(ScreenPoint p1, ScreenPoint p2)
+        {
+            return new ScreenVector(p1.x - p2.x, p1.y - p2.y);
+        }
+
+        /// <summary>
+        /// Subtracts a <see cref="ScreenVector"/> from a <see cref="ScreenPoint"/> 
+        /// and returns the result as a <see cref="ScreenPoint"/>.
+        /// </summary>
+        /// <param name="point"> The point on which to perform the subtraction. </param>
+        /// <param name="vector"> The vector to subtract from p1. </param>
+        /// <returns> A <see cref="ScreenPoint"/> that represents point translated by the negative vector. 
</returns>
+        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 --git a/oxyplot/OxyPlot/Foundation/ScreenPointHelper.cs b/oxyplot/OxyPlot/Foundation/ScreenPointHelper.cs
new file mode 100644
index 0000000..98709a0
--- /dev/null
+++ b/oxyplot/OxyPlot/Foundation/ScreenPointHelper.cs
@@ -0,0 +1,255 @@
+// 
--------------------------------------------------------------------------------------------------------------------
+// <copyright file="ScreenPointHelper.cs" company="OxyPlot">
+//   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.
+// </copyright>
+// <summary>
+//   Provides various algorithms for polygons and lines of ScreenPoint.
+// </summary>
+// 
--------------------------------------------------------------------------------------------------------------------
+namespace OxyPlot
+{
+    using System.Collections.Generic;
+
+    /// <summary>
+    /// Provides algorithms for polygons and lines of <see cref="ScreenPoint"/>.
+    /// </summary>
+    public static class ScreenPointHelper
+    {
+        /// <summary>
+        /// Finds the nearest point on the specified polyline.
+        /// </summary>
+        /// <param name="point">
+        /// The point.
+        /// </param>
+        /// <param name="points">
+        /// The points.
+        /// </param>
+        /// <returns>
+        /// The nearest point.
+        /// </returns>
+        public static ScreenPoint FindNearestPointOnPolyline(ScreenPoint point, IList<ScreenPoint> 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;
+        }
+
+        /// <summary>
+        /// Finds the point on line.
+        /// </summary>
+        /// <param name="p">
+        /// The point.
+        /// </param>
+        /// <param name="p1">
+        /// The first point on the line.
+        /// </param>
+        /// <param name="p2">
+        /// The second point on the line.
+        /// </param>
+        /// <returns>
+        /// The nearest point on the line.
+        /// </returns>
+        /// <remarks>
+        /// See <a href="http://paulbourke.net/geometry/pointlineplane/";>Bourke</a>.
+        /// </remarks>
+        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));
+        }
+
+        /// <summary>
+        /// Finds the nearest point on line.
+        /// </summary>
+        /// <param name="p">
+        /// The point.
+        /// </param>
+        /// <param name="p1">
+        /// The start point on the line.
+        /// </param>
+        /// <param name="p2">
+        /// The end point on the line.
+        /// </param>
+        /// <returns>
+        /// The relative position of the nearest point.
+        /// </returns>
+        /// <remarks>
+        /// See <a href="http://paulbourke.net/geometry/pointlineplane/";>Bourke</a>.
+        /// </remarks>
+        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;
+        }
+
+        /// <summary>
+        /// Determines whether the specified point is in the specified polygon.
+        /// </summary>
+        /// <param name="p">
+        /// The point.
+        /// </param>
+        /// <param name="pts">
+        /// The polygon points.
+        /// </param>
+        /// <returns>
+        /// <c>true</c> if the point is in the polygon; otherwise, <c>false</c>.
+        /// </returns>
+        public static bool IsPointInPolygon(ScreenPoint p, IList<ScreenPoint> 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;
+        }
+
+        /// <summary>
+        /// Resamples the points with the specified point distance limit.
+        /// </summary>
+        /// <param name="allPoints">
+        /// All points.
+        /// </param>
+        /// <param name="minimumDistance">
+        /// The minimum squared distance.
+        /// </param>
+        /// <returns>
+        /// List of resampled points.
+        /// </returns>
+        public static IList<ScreenPoint> ResamplePoints(IList<ScreenPoint> allPoints, double minimumDistance)
+        {
+            double minimumSquaredDistance = minimumDistance * minimumDistance;
+            int n = allPoints.Count;
+            var result = new List<ScreenPoint>(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;
+        }
+
+        /// <summary>
+        /// Gets the centroid of the specified polygon.
+        /// </summary>
+        /// <param name="points">
+        /// The points.
+        /// </param>
+        /// <returns>
+        /// The centroid.
+        /// </returns>
+        public static ScreenPoint GetCentroid(IList<ScreenPoint> 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 --git a/oxyplot/OxyPlot/Foundation/ScreenVector.cs b/oxyplot/OxyPlot/Foundation/ScreenVector.cs
new file mode 100644
index 0000000..ac82932
--- /dev/null
+++ b/oxyplot/OxyPlot/Foundation/ScreenVector.cs
@@ -0,0 +1,155 @@
+// 
--------------------------------------------------------------------------------------------------------------------
+// <copyright file="ScreenVector.cs" company="OxyPlot">
+//   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.
+// </copyright>
+// <summary>
+//   Represents a vector defined in the screen coordinate system.
+// </summary>
+// 
--------------------------------------------------------------------------------------------------------------------
+namespace OxyPlot
+{
+    using System;
+
+    /// <summary>
+    /// Represents a vector defined in the screen coordinate system.
+    /// </summary>
+    public struct ScreenVector
+    {
+        /// <summary>
+        /// The x-coordinate.
+        /// </summary>
+        internal double x;
+
+        /// <summary>
+        /// The y-coordinate.
+        /// </summary>
+        internal double y;
+
+        /// <summary>
+        /// Initializes a new instance of the <see cref="ScreenVector"/> structure.
+        /// </summary>
+        /// <param name="x">
+        /// The x-coordinate.
+        /// </param>
+        /// <param name="y">
+        /// The y-coordinate.
+        /// </param>
+        public ScreenVector(double x, double y)
+        {
+            this.x = x;
+            this.y = y;
+        }
+
+        /// <summary>
+        /// Gets the length.
+        /// </summary>
+        public double Length
+        {
+            get
+            {
+                return Math.Sqrt((this.x * this.x) + (this.y * this.y));
+            }
+        }
+
+        /// <summary>
+        /// Gets the length squared.
+        /// </summary>
+        public double LengthSquared
+        {
+            get
+            {
+                return (this.x * this.x) + (this.y * this.y);
+            }
+        }
+
+        /// <summary>
+        /// Gets or sets the x-coordinate.
+        /// </summary>
+        /// <value> The x-coordinate. </value>
+        public double X
+        {
+            get
+            {
+                return this.x;
+            }
+
+            set
+            {
+                this.x = value;
+            }
+        }
+
+        /// <summary>
+        /// Gets or sets the y-coordinate.
+        /// </summary>
+        /// <value> The y-coordinate. </value>
+        public double Y
+        {
+            get
+            {
+                return this.y;
+            }
+
+            set
+            {
+                this.y = value;
+            }
+        }
+
+        /// <summary>
+        /// Normalizes this vector.
+        /// </summary>
+        public void Normalize()
+        {
+            double l = Math.Sqrt((this.x * this.x) + (this.y * this.y));
+            if (l > 0)
+            {
+                this.x /= l;
+                this.y /= l;
+            }
+        }
+
+        /// <summary>
+        /// Returns a <see cref="System.String"/> that represents this instance.
+        /// </summary>
+        /// <returns>
+        /// A <see cref="System.String"/> that represents this instance.
+        /// </returns>
+        public override string ToString()
+        {
+            return this.x + " " + this.y;
+        }
+
+        /// <summary>
+        /// Implements the operator *.
+        /// </summary>
+        /// <param name="v"> The vector. </param>
+        /// <param name="d"> The multiplication factor. </param>
+        /// <returns> The result of the operator. </returns>
+        public static ScreenVector operator *(ScreenVector v, double d)
+        {
+            return new ScreenVector(v.x * d, v.y * d);
+        }
+    }
+}
\ No newline at end of file
diff --git a/oxyplot/OxyPlot/Foundation/Size.cs b/oxyplot/OxyPlot/Foundation/Size.cs
new file mode 100644
index 0000000..05bac70
--- /dev/null
+++ b/oxyplot/OxyPlot/Foundation/Size.cs
@@ -0,0 +1,43 @@
+// 
--------------------------------------------------------------------------------------------------------------------
+// <copyright file="Size.cs" company="OxyPlot">
+//   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.
+// </copyright>
+// 
--------------------------------------------------------------------------------------------------------------------
+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 --git a/oxyplot/OxyPlot/Foundation/StreamExtensions.cs b/oxyplot/OxyPlot/Foundation/StreamExtensions.cs
new file mode 100644
index 0000000..b1f2141
--- /dev/null
+++ b/oxyplot/OxyPlot/Foundation/StreamExtensions.cs
@@ -0,0 +1,25 @@
+namespace OxyPlot
+{
+    using System.IO;
+
+    /// <summary>
+    /// Implements <see cref="Stream"/> extension methods.
+    /// </summary>
+    public static class StreamExtensions
+    {
+        /// <summary>
+        /// Copies to the specified stream.
+        /// </summary>
+        /// <param name="input">The input stream.</param>
+        /// <param name="output">The output stream.</param>
+        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 --git a/oxyplot/OxyPlot/Foundation/StringHelper.cs b/oxyplot/OxyPlot/Foundation/StringHelper.cs
new file mode 100644
index 0000000..1d6fa44
--- /dev/null
+++ b/oxyplot/OxyPlot/Foundation/StringHelper.cs
@@ -0,0 +1,169 @@
+// 
--------------------------------------------------------------------------------------------------------------------
+// <copyright file="StringHelper.cs" company="OxyPlot">
+//   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.
+// </copyright>
+// <summary>
+//   Provides support for string formatting.
+// </summary>
+// 
--------------------------------------------------------------------------------------------------------------------
+namespace OxyPlot
+{
+    using System;
+    using System.Collections;
+    using System.Text;
+    using System.Text.RegularExpressions;
+
+    /// <summary>
+    /// Provides extended string formatting functionality.
+    /// </summary>
+    public static class StringHelper
+    {
+        /// <summary>
+        /// The formatting expression.
+        /// </summary>
+        private static readonly Regex FormattingExpression = new 
Regex("{(?<Property>.+?)(?<Format>\\:.*?)?}");
+
+        /// <summary>
+        /// Replaces the format items in the specified string.
+        /// </summary>
+        /// <param name="provider">
+        /// The culture specific format provider.
+        /// </param>
+        /// <param name="formatString">
+        /// The format string.
+        /// </param>
+        /// <param name="item">
+        /// The item.
+        /// </param>
+        /// <param name="values">
+        /// The values.
+        /// </param>
+        /// <remarks>
+        /// 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.
+        /// </remarks>
+        /// <returns>
+        /// The formatted string.
+        /// </returns>
+        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;
+        }
+
+        /// <summary>
+        /// Creates a valid file name.
+        /// </summary>
+        /// <param name="title">
+        /// The title.
+        /// </param>
+        /// <param name="extension">
+        /// The extension.
+        /// </param>
+        /// <returns>
+        /// A file name.
+        /// </returns>
+        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;
+        }
+
+        /// <summary>
+        /// Creates a string from a collection of items.
+        /// </summary>
+        /// <param name="provider">
+        /// The provider.
+        /// </param>
+        /// <param name="items">
+        /// The items.
+        /// </param>
+        /// <param name="formatstring">
+        /// The format string to apply to each item.
+        /// </param>
+        /// <param name="separator">
+        /// The separator.
+        /// </param>
+        /// <returns>
+        /// The collection as a string.
+        /// </returns>
+        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 --git a/oxyplot/OxyPlot/Foundation/SutherlandHodgmanClipping.cs 
b/oxyplot/OxyPlot/Foundation/SutherlandHodgmanClipping.cs
new file mode 100644
index 0000000..b6ef5c0
--- /dev/null
+++ b/oxyplot/OxyPlot/Foundation/SutherlandHodgmanClipping.cs
@@ -0,0 +1,233 @@
+// 
--------------------------------------------------------------------------------------------------------------------
+// <copyright file="SutherlandHodgmanClipping.cs" company="OxyPlot">
+//   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.
+// </copyright>
+// <summary>
+//   Polygon clipping by the sutherland-hodgman algortihm.
+// </summary>
+// 
--------------------------------------------------------------------------------------------------------------------
+namespace OxyPlot
+{
+    using System;
+    using System.Collections.Generic;
+
+    /// <summary>
+    /// Provides polygon clipping by the Sutherland-Hodgman algortihm.
+    /// </summary>
+    public static class SutherlandHodgmanClipping
+    {
+        /// <summary>
+        /// The rectangle edge.
+        /// </summary>
+        private enum RectangleEdge
+        {
+            /// <summary>
+            /// The left.
+            /// </summary>
+            Left,
+
+            /// <summary>
+            /// The right.
+            /// </summary>
+            Right,
+
+            /// <summary>
+            /// The top.
+            /// </summary>
+            Top,
+
+            /// <summary>
+            /// The bottom.
+            /// </summary>
+            Bottom
+        }
+
+        /// <summary>
+        /// The Sutherland-Hodgman polygon clipping algorithm.
+        /// </summary>
+        /// <remarks>
+        /// See http://ezekiel.vancouver.wsu.edu/~cs442/lectures/clip/clip/index.html
+        /// </remarks>
+        /// <param name="bounds">
+        /// The bounds.
+        /// </param>
+        /// <param name="v">
+        /// The polygon points.
+        /// </param>
+        /// <returns>
+        /// The clipped points.
+        /// </returns>
+        public static List<ScreenPoint> ClipPolygon(OxyRect bounds, IList<ScreenPoint> v)
+        {
+            List<ScreenPoint> p1 = ClipOneAxis(bounds, RectangleEdge.Left, v);
+            List<ScreenPoint> p2 = ClipOneAxis(bounds, RectangleEdge.Right, p1);
+            List<ScreenPoint> p3 = ClipOneAxis(bounds, RectangleEdge.Top, p2);
+            return ClipOneAxis(bounds, RectangleEdge.Bottom, p3);
+        }
+
+        /// <summary>
+        /// Clips to one axis.
+        /// </summary>
+        /// <param name="bounds">
+        /// The bounds.
+        /// </param>
+        /// <param name="edge">
+        /// The edge.
+        /// </param>
+        /// <param name="v">
+        /// The points of the polygon.
+        /// </param>
+        /// <returns>
+        /// The clipped points.
+        /// </returns>
+        private static List<ScreenPoint> ClipOneAxis(OxyRect bounds, RectangleEdge edge, IList<ScreenPoint> 
v)
+        {
+            if (v.Count == 0)
+            {
+                return new List<ScreenPoint>();
+            }
+
+            var polygon = new List<ScreenPoint>(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;
+        }
+
+        /// <summary>
+        /// Determines whether the specified point is inside the edge/bounds.
+        /// </summary>
+        /// <param name="bounds">The bounds.</param>
+        /// <param name="edge">The edge to test.</param>
+        /// <param name="p">The point.</param>
+        /// <returns>
+        ///  <c>true</c> if the specified point is inside; otherwise, <c>false</c>.
+        /// </returns>
+        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");
+            }
+        }
+
+        /// <summary>
+        /// Fines the edge interception.
+        /// </summary>
+        /// <param name="bounds">The bounds.</param>
+        /// <param name="edge">The edge.</param>
+        /// <param name="a">The first point.</param>
+        /// <param name="b">The second point.</param>
+        /// <returns>The interception.</returns>
+        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 --git a/oxyplot/OxyPlot/Foundation/VerticalAlignment.cs b/oxyplot/OxyPlot/Foundation/VerticalAlignment.cs
new file mode 100644
index 0000000..135be4e
--- /dev/null
+++ b/oxyplot/OxyPlot/Foundation/VerticalAlignment.cs
@@ -0,0 +1,52 @@
+// 
--------------------------------------------------------------------------------------------------------------------
+// <copyright file="VerticalAlignment.cs" company="OxyPlot">
+//   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.
+// </copyright>
+// <summary>
+//   Vertical text alignment.
+// </summary>
+// 
--------------------------------------------------------------------------------------------------------------------
+namespace OxyPlot
+{
+    /// <summary>
+    /// Specifies the vertical alignment.
+    /// </summary>
+    public enum VerticalAlignment
+    {
+        /// <summary>
+        /// Aligned at the top.
+        /// </summary>
+        Top = -1,
+
+        /// <summary>
+        /// Aligned in the middle.
+        /// </summary>
+        Middle = 0,
+
+        /// <summary>
+        /// Aligned at the bottom.
+        /// </summary>
+        Bottom = 1
+    }
+}
\ No newline at end of file
diff --git a/oxyplot/OxyPlot/Foundation/XmlWriterBase.cs b/oxyplot/OxyPlot/Foundation/XmlWriterBase.cs
new file mode 100644
index 0000000..72e0e38
--- /dev/null
+++ b/oxyplot/OxyPlot/Foundation/XmlWriterBase.cs
@@ -0,0 +1,233 @@
+// 
--------------------------------------------------------------------------------------------------------------------
+// <copyright file="XmlWriterBase.cs" company="OxyPlot">
+//   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.
+// </copyright>
+// <summary>
+//   Abstract base class for exporters that write xml.
+// </summary>
+// 
--------------------------------------------------------------------------------------------------------------------
+namespace OxyPlot
+{
+    using System;
+    using System.IO;
+    using System.Text;
+    using System.Xml;
+
+    /// <summary>
+    /// Provides an abstract base class for exporters that write xml.
+    /// </summary>
+    public abstract class XmlWriterBase : IDisposable
+    {
+        /// <summary>
+        /// The xml writer.
+        /// </summary>
+        private XmlWriter w;
+
+        /// <summary>
+        /// The disposed flag.
+        /// </summary>
+        private bool disposed;
+
+        /// <summary>
+        /// Initializes a new instance of the <see cref = "XmlWriterBase" /> class.
+        /// </summary>
+        protected XmlWriterBase()
+        {
+        }
+
+        /// <summary>
+        /// Initializes a new instance of the <see cref="XmlWriterBase"/> class.
+        /// </summary>
+        /// <param name="stream">
+        /// The stream.
+        /// </param>
+        protected XmlWriterBase(Stream stream)
+        {
+            this.w = XmlWriter.Create(stream, new XmlWriterSettings { Indent = true, Encoding = 
Encoding.UTF8 });
+        }
+
+        /// <summary>
+        /// Closes this instance.
+        /// </summary>
+        public virtual void Close()
+        {
+        }
+
+        /// <summary>
+        /// Performs application-defined tasks associated with freeing, releasing, or resetting unmanaged 
resources.
+        /// </summary>
+        public void Dispose()
+        {
+            this.Dispose(true);
+            GC.SuppressFinalize(this);
+        }
+
+        /// <summary>
+        /// Flushes this instance.
+        /// </summary>
+        public void Flush()
+        {
+            this.w.Flush();
+        }
+
+        /// <summary>
+        /// The write attribute string.
+        /// </summary>
+        /// <param name="name">
+        /// The name.
+        /// </param>
+        /// <param name="value">
+        /// The value.
+        /// </param>
+        protected void WriteAttributeString(string name, string value)
+        {
+            this.w.WriteAttributeString(name, value);
+        }
+
+        /// <summary>
+        /// The write doc type.
+        /// </summary>
+        /// <param name="name">
+        /// The name.
+        /// </param>
+        /// <param name="pubid">
+        /// The pubid.
+        /// </param>
+        /// <param name="sysid">
+        /// The sysid.
+        /// </param>
+        /// <param name="subset">
+        /// The subset.
+        /// </param>
+        protected void WriteDocType(string name, string pubid, string sysid, string subset)
+        {
+            this.w.WriteDocType(name, pubid, sysid, subset);
+        }
+
+        /// <summary>
+        /// The write element string.
+        /// </summary>
+        /// <param name="name">
+        /// The name.
+        /// </param>
+        /// <param name="text">
+        /// The text.
+        /// </param>
+        protected void WriteElementString(string name, string text)
+        {
+            this.w.WriteElementString(name, text);
+        }
+
+        /// <summary>
+        /// The write end document.
+        /// </summary>
+        protected void WriteEndDocument()
+        {
+            this.w.WriteEndDocument();
+        }
+
+        /// <summary>
+        /// The write end element.
+        /// </summary>
+        protected void WriteEndElement()
+        {
+            this.w.WriteEndElement();
+        }
+
+        /// <summary>
+        /// The write raw.
+        /// </summary>
+        /// <param name="text">
+        /// The text.
+        /// </param>
+        protected void WriteRaw(string text)
+        {
+            this.w.WriteRaw(text);
+        }
+
+        /// <summary>
+        /// The write start document.
+        /// </summary>
+        /// <param name="standalone">
+        /// The standalone.
+        /// </param>
+        protected void WriteStartDocument(bool standalone)
+        {
+            this.w.WriteStartDocument(standalone);
+        }
+
+        /// <summary>
+        /// The write start element.
+        /// </summary>
+        /// <param name="name">
+        /// The name.
+        /// </param>
+        protected void WriteStartElement(string name)
+        {
+            this.w.WriteStartElement(name);
+        }
+
+        /// <summary>
+        /// The write start element.
+        /// </summary>
+        /// <param name="name">
+        /// The name.
+        /// </param>
+        /// <param name="ns">
+        /// The ns.
+        /// </param>
+        protected void WriteStartElement(string name, string ns)
+        {
+            this.w.WriteStartElement(name, ns);
+        }
+
+        /// <summary>
+        /// The write string.
+        /// </summary>
+        /// <param name="text">
+        /// The text.
+        /// </param>
+        protected void WriteString(string text)
+        {
+            this.w.WriteString(text);
+        }
+
+        /// <summary>
+        /// Releases unmanaged and - optionally - managed resources
+        /// </summary>
+        /// <param name="disposing"><c>true</c> to release both managed and unmanaged resources; 
<c>false</c> to release only unmanaged resources.</param>
+        private void Dispose(bool disposing)
+        {
+            if (!this.disposed)
+            {
+                if (disposing)
+                {
+                    this.Close();
+                }
+            }
+
+            this.disposed = true;
+        }
+    }
+}
\ No newline at end of file
diff --git a/oxyplot/OxyPlot/LibraryDoc.cs b/oxyplot/OxyPlot/LibraryDoc.cs
new file mode 100644
index 0000000..03caac4
--- /dev/null
+++ b/oxyplot/OxyPlot/LibraryDoc.cs
@@ -0,0 +1,37 @@
+// 
--------------------------------------------------------------------------------------------------------------------
+// <copyright file="LibraryDoc.cs" company="OxyPlot">
+//   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.
+// </copyright>
+// 
--------------------------------------------------------------------------------------------------------------------
+
+namespace OxyPlot
+{
+    /// <summary>
+    /// The OxyPlot solution provides plotting functionality on many platforms.
+    /// </summary>
+    [System.Runtime.CompilerServices.CompilerGenerated]
+    internal class LibraryDoc
+    {
+    }
+}
\ No newline at end of file
diff --git a/oxyplot/OxyPlot/Manipulators/CursorType.cs b/oxyplot/OxyPlot/Manipulators/CursorType.cs
new file mode 100644
index 0000000..188aa50
--- /dev/null
+++ b/oxyplot/OxyPlot/Manipulators/CursorType.cs
@@ -0,0 +1,62 @@
+// 
--------------------------------------------------------------------------------------------------------------------
+// <copyright file="CursorType.cs" company="OxyPlot">
+//   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.
+// </copyright>
+// <summary>
+//   Specifies the cursor type.
+// </summary>
+// 
--------------------------------------------------------------------------------------------------------------------
+namespace OxyPlot
+{
+    /// <summary>
+    /// Specifies the cursor type.
+    /// </summary>
+    public enum CursorType
+    {
+        /// <summary>
+        /// The default cursor
+        /// </summary>
+        Default = 0,
+
+        /// <summary>
+        /// The pan cursor
+        /// </summary>
+        Pan,
+
+        /// <summary>
+        /// The zoom rectangle cursor
+        /// </summary>
+        ZoomRectangle,
+
+        /// <summary>
+        /// The horizontal zoom cursor
+        /// </summary>
+        ZoomHorizontal,
+
+        /// <summary>
+        /// The vertical zoom cursor
+        /// </summary>
+        ZoomVertical
+    }
+}
\ No newline at end of file
diff --git a/oxyplot/OxyPlot/Manipulators/IPlotControl.cs b/oxyplot/OxyPlot/Manipulators/IPlotControl.cs
new file mode 100644
index 0000000..2f9cb90
--- /dev/null
+++ b/oxyplot/OxyPlot/Manipulators/IPlotControl.cs
@@ -0,0 +1,176 @@
+// 
--------------------------------------------------------------------------------------------------------------------
+// <copyright file="IPlotControl.cs" company="OxyPlot">
+//   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.
+// </copyright>
+// <summary>
+//   Interface for Plot controls.
+// </summary>
+// 
--------------------------------------------------------------------------------------------------------------------
+namespace OxyPlot
+{
+    using OxyPlot.Annotations;
+    using OxyPlot.Axes;
+    using OxyPlot.Series;
+
+    /// <summary>
+    /// Defines functionality in the Plot controls.
+    /// </summary>
+    public interface IPlotControl
+    {
+        /// <summary>
+        /// Gets the actual model.
+        /// </summary>
+        /// <value>The actual model.</value>
+        PlotModel ActualModel { get; }
+
+        /// <summary>
+        /// Gets the axes from a point.
+        /// </summary>
+        /// <param name="pt">
+        /// The point.
+        /// </param>
+        /// <param name="xaxis">
+        /// The x-axis.
+        /// </param>
+        /// <param name="yaxis">
+        /// The y-axis.
+        /// </param>
+        void GetAxesFromPoint(ScreenPoint pt, out Axis xaxis, out Axis yaxis);
+
+        /// <summary>
+        /// Gets the series from point.
+        /// </summary>
+        /// <param name="pt">
+        /// The point (screen coordinates).
+        /// </param>
+        /// <param name="limit">
+        /// The maximum allowed distance.
+        /// </param>
+        /// <returns>
+        /// The series.
+        /// </returns>
+        Series.Series GetSeriesFromPoint(ScreenPoint pt, double limit = 100);
+
+        /// <summary>
+        /// Hides the tracker.
+        /// </summary>
+        void HideTracker();
+
+        /// <summary>
+        /// Hides the zoom rectangle.
+        /// </summary>
+        void HideZoomRectangle();
+
+        /// <summary>
+        /// Invalidate the plot (not blocking the UI thread)
+        /// </summary>
+        /// <param name="updateData">
+        /// if set to <c>true</c>, all data collections will be updated.
+        /// </param>
+        void InvalidatePlot(bool updateData = true);
+
+        /// <summary>
+        /// Pans the specified axis.
+        /// </summary>
+        /// <param name="axis">
+        /// The axis.
+        /// </param>
+        /// <param name="ppt">
+        /// The previous point (screen coordinates).
+        /// </param>
+        /// <param name="cpt">
+        /// The current point (screen coordinates).
+        /// </param>
+        void Pan(Axis axis, ScreenPoint ppt, ScreenPoint cpt);
+
+        /// <summary>
+        /// Refresh the plot immediately (blocking UI thread)
+        /// </summary>
+        /// <param name="updateData">
+        /// if set to <c>true</c>, all data collections will be updated.
+        /// </param>
+        void RefreshPlot(bool updateData = true);
+
+        /// <summary>
+        /// Resets the specified axis.
+        /// </summary>
+        /// <param name="axis">
+        /// The axis.
+        /// </param>
+        void Reset(Axis axis);
+
+        /// <summary>
+        /// Sets the cursor type.
+        /// </summary>
+        /// <param name="cursorType">
+        /// The cursor type.
+        /// </param>
+        void SetCursorType(CursorType cursorType);
+
+        /// <summary>
+        /// Shows the tracker.
+        /// </summary>
+        /// <param name="trackerHitResult">
+        /// The tracker data.
+        /// </param>
+        void ShowTracker(TrackerHitResult trackerHitResult);
+
+        /// <summary>
+        /// Shows the zoom rectangle.
+        /// </summary>
+        /// <param name="r">
+        /// The rectangle.
+        /// </param>
+        void ShowZoomRectangle(OxyRect r);
+
+        /// <summary>
+        /// Zooms the specified axis to the specified values.
+        /// </summary>
+        /// <param name="axis">
+        /// The axis.
+        /// </param>
+        /// <param name="p1">
+        /// The new minimum value.
+        /// </param>
+        /// <param name="p2">
+        /// The new maximum value.
+        /// </param>
+        void Zoom(Axis axis, double p1, double p2);
+
+        /// <summary>
+        /// Zooms at the specified position.
+        /// </summary>
+        /// <param name="axis">
+        /// The axis.
+        /// </param>
+        /// <param name="factor">
+        /// The zoom factor.
+        /// </param>
+        /// <param name="x">
+        /// The position to zoom at.
+        /// </param>
+        void ZoomAt(Axis axis, double factor, double x);
+
+    }
+}
\ No newline at end of file
diff --git a/oxyplot/OxyPlot/Manipulators/ManipulationEventArgs.cs 
b/oxyplot/OxyPlot/Manipulators/ManipulationEventArgs.cs
new file mode 100644
index 0000000..caef43e
--- /dev/null
+++ b/oxyplot/OxyPlot/Manipulators/ManipulationEventArgs.cs
@@ -0,0 +1,67 @@
+// 
--------------------------------------------------------------------------------------------------------------------
+// <copyright file="ManipulationEventArgs.cs" company="OxyPlot">
+//   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.
+// </copyright>
+// <summary>
+//   Provides data for the manipulation events.
+// </summary>
+// 
--------------------------------------------------------------------------------------------------------------------
+namespace OxyPlot
+{
+    /// <summary>
+    /// Provides data for the manipulation events.
+    /// </summary>
+    public class ManipulationEventArgs
+    {
+        /// <summary>
+        /// Initializes a new instance of the <see cref="ManipulationEventArgs"/> class.
+        /// </summary>
+        /// <param name="currentPosition">
+        /// The current position.
+        /// </param>
+        public ManipulationEventArgs(ScreenPoint currentPosition)
+        {
+            this.CurrentPosition = currentPosition;
+        }
+
+        /// <summary>
+        /// Gets the current position.
+        /// </summary>
+        /// <value>The current position.</value>
+        public ScreenPoint CurrentPosition { get; private set; }
+
+        /// <summary>
+        /// Gets or sets the X scaling factor.
+        /// </summary>
+        /// <value>The scale value.</value>
+        public double ScaleX { get; set; }
+
+        /// <summary>
+        /// Gets or sets the Y scaling factor.
+        /// </summary>
+        /// <value>The scale value.</value>
+        public double ScaleY { get; set; }
+
+    }
+}
\ No newline at end of file
diff --git a/oxyplot/OxyPlot/Manipulators/ManipulatorBase.cs b/oxyplot/OxyPlot/Manipulators/ManipulatorBase.cs
new file mode 100644
index 0000000..13cfbb8
--- /dev/null
+++ b/oxyplot/OxyPlot/Manipulators/ManipulatorBase.cs
@@ -0,0 +1,151 @@
+// 
--------------------------------------------------------------------------------------------------------------------
+// <copyright file="ManipulatorBase.cs" company="OxyPlot">
+//   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.
+// </copyright>
+// <summary>
+//   The manipulator base.
+// </summary>
+// 
--------------------------------------------------------------------------------------------------------------------
+namespace OxyPlot
+{
+    using OxyPlot.Axes;
+
+    /// <summary>
+    /// Provides an absract base class for plot control manipulators.
+    /// </summary>
+    public class ManipulatorBase
+    {
+        /// <summary>
+        /// Initializes a new instance of the <see cref="ManipulatorBase"/> class.
+        /// </summary>
+        /// <param name="plotControl">
+        /// The plot control.
+        /// </param>
+        protected ManipulatorBase(IPlotControl plotControl)
+        {
+            this.PlotControl = plotControl;
+        }
+
+        /// <summary>
+        /// Gets the first position of the manipulation.
+        /// </summary>
+        public ScreenPoint StartPosition { get; private set; }
+
+        /// <summary>
+        /// Gets the plot control.
+        /// </summary>
+        protected IPlotControl PlotControl { get; private set; }
+
+        /// <summary>
+        /// Gets or sets the X axis.
+        /// </summary>
+        /// <value>The X axis.</value>
+        protected Axis XAxis { get; set; }
+
+        /// <summary>
+        /// Gets or sets the Y axis.
+        /// </summary>
+        /// <value>The Y axis.</value>
+        protected Axis YAxis { get; set; }
+
+        /// <summary>
+        /// Occurs when a manipulation is complete.
+        /// </summary>
+        /// <param name="e">
+        /// The <see cref="OxyPlot.ManipulationEventArgs"/> instance containing the event data.
+        /// </param>
+        public virtual void Completed(ManipulationEventArgs e)
+        {
+            this.PlotControl.SetCursorType(CursorType.Default);
+        }
+
+        /// <summary>
+        /// Occurs when the input device changes position during a manipulation.
+        /// </summary>
+        /// <param name="e">
+        /// The <see cref="OxyPlot.ManipulationEventArgs"/> instance containing the event data.
+        /// </param>
+        public virtual void Delta(ManipulationEventArgs e)
+        {
+        }
+
+        /// <summary>
+        /// Gets the cursor for the manipulation.
+        /// </summary>
+        /// <returns>
+        /// The cursor.
+        /// </returns>
+        public virtual CursorType GetCursorType()
+        {
+            return CursorType.Default;
+        }
+
+        /// <summary>
+        /// Occurs when an input device begins a manipulation on the plot.
+        /// </summary>
+        /// <param name="e">
+        /// The <see cref="OxyPlot.ManipulationEventArgs"/> instance containing the event data.
+        /// </param>
+        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());
+        }
+
+        /// <summary>
+        /// Transforms a point from screen coordinates to data coordinates.
+        /// </summary>
+        /// <param name="x">
+        /// The x coordinate.
+        /// </param>
+        /// <param name="y">
+        /// The y coordinate.
+        /// </param>
+        /// <returns>
+        /// A data point.
+        /// </returns>
+        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 --git a/oxyplot/OxyPlot/Manipulators/PanManipulator.cs b/oxyplot/OxyPlot/Manipulators/PanManipulator.cs
new file mode 100644
index 0000000..6d13df7
--- /dev/null
+++ b/oxyplot/OxyPlot/Manipulators/PanManipulator.cs
@@ -0,0 +1,100 @@
+// 
--------------------------------------------------------------------------------------------------------------------
+// <copyright file="PanManipulator.cs" company="OxyPlot">
+//   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.
+// </copyright>
+// <summary>
+//   The pan manipulator.
+// </summary>
+// 
--------------------------------------------------------------------------------------------------------------------
+namespace OxyPlot
+{
+    /// <summary>
+    /// Provides a plot control manipulator for panning functionality.
+    /// </summary>
+    public class PanManipulator : ManipulatorBase
+    {
+        /// <summary>
+        /// Initializes a new instance of the <see cref="PanManipulator"/> class.
+        /// </summary>
+        /// <param name="plotControl">
+        /// The plot control.
+        /// </param>
+        public PanManipulator(IPlotControl plotControl)
+            : base(plotControl)
+        {
+        }
+
+        /// <summary>
+        /// Gets or sets the previous position.
+        /// </summary>
+        private ScreenPoint PreviousPosition { get; set; }
+
+        /// <summary>
+        /// Occurs when the input device changes position during a manipulation.
+        /// </summary>
+        /// <param name="e">
+        /// The <see cref="OxyPlot.ManipulationEventArgs"/> instance containing the event data.
+        /// </param>
+        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;
+        }
+
+        /// <summary>
+        /// Gets the cursor for the manipulation.
+        /// </summary>
+        /// <returns>
+        /// The cursor.
+        /// </returns>
+        public override CursorType GetCursorType()
+        {
+            return CursorType.Pan;
+        }
+
+        /// <summary>
+        /// Occurs when an input device begins a manipulation on the plot.
+        /// </summary>
+        /// <param name="e">
+        /// The <see cref="OxyPlot.ManipulationEventArgs"/> instance containing the event data.
+        /// </param>
+        public override void Started(ManipulationEventArgs e)
+        {
+            base.Started(e);
+            this.PreviousPosition = e.CurrentPosition;
+        }
+
+    }
+}
\ No newline at end of file
diff --git a/oxyplot/OxyPlot/Manipulators/ResetManipulator.cs 
b/oxyplot/OxyPlot/Manipulators/ResetManipulator.cs
new file mode 100644
index 0000000..de4657a
--- /dev/null
+++ b/oxyplot/OxyPlot/Manipulators/ResetManipulator.cs
@@ -0,0 +1,71 @@
+// 
--------------------------------------------------------------------------------------------------------------------
+// <copyright file="ResetManipulator.cs" company="OxyPlot">
+//   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.
+// </copyright>
+// <summary>
+//   The reset manipulator.
+// </summary>
+// 
--------------------------------------------------------------------------------------------------------------------
+namespace OxyPlot
+{
+    /// <summary>
+    /// Provides a plot control manipulator for reset functionality.
+    /// </summary>
+    public class ResetManipulator : ManipulatorBase
+    {
+        /// <summary>
+        /// Initializes a new instance of the <see cref="ResetManipulator"/> class.
+        /// </summary>
+        /// <param name="plotControl">
+        /// The plot control.
+        /// </param>
+        public ResetManipulator(IPlotControl plotControl)
+            : base(plotControl)
+        {
+        }
+
+        /// <summary>
+        /// Occurs when an input device begins a manipulation on the plot.
+        /// </summary>
+        /// <param name="e">
+        /// The <see cref="OxyPlot.ManipulationEventArgs"/> instance containing the event data.
+        /// </param>
+        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 --git a/oxyplot/OxyPlot/Manipulators/TrackerHitResult.cs 
b/oxyplot/OxyPlot/Manipulators/TrackerHitResult.cs
new file mode 100644
index 0000000..77d5088
--- /dev/null
+++ b/oxyplot/OxyPlot/Manipulators/TrackerHitResult.cs
@@ -0,0 +1,162 @@
+// 
--------------------------------------------------------------------------------------------------------------------
+// <copyright file="TrackerHitResult.cs" company="OxyPlot">
+//   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.
+// </copyright>
+// <summary>
+//   Provides a data container for a tracker hit result.
+// </summary>
+// 
--------------------------------------------------------------------------------------------------------------------
+namespace OxyPlot
+{
+    using OxyPlot.Series;
+
+    /// <summary>
+    /// Provides a data container for a tracker hit result.
+    /// </summary>
+    /// <remarks>
+    /// 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.
+    /// </remarks>
+    public class TrackerHitResult
+    {
+        /// <summary>
+        /// The default format string.
+        /// </summary>
+        private const string DefaultFormatString = "{0}\n{1}: {2}\n{3}: {4}";
+
+        /// <summary>
+        /// Initializes a new instance of the <see cref="TrackerHitResult"/> class.
+        /// </summary>
+        /// <param name="series">The series.</param>
+        /// <param name="dp">The data point.</param>
+        /// <param name="sp">The screen point.</param>
+        /// <param name="item">The item.</param>
+        /// <param name="index">The index.</param>
+        /// <param name="text">The text.</param>
+        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;
+            }
+        }
+
+        /// <summary>
+        /// Gets or sets the nearest or interpolated data point.
+        /// </summary>
+        public IDataPoint DataPoint { get; set; }
+
+        /// <summary>
+        /// 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.
+        /// </summary>
+        public object Item { get; set; }
+
+        /// <summary>
+        /// Gets or sets the index for the Item.
+        /// </summary>
+        public double Index { get; set; }
+
+        /// <summary>
+        /// Gets or sets the horizontal/vertical line extents.
+        /// </summary>
+        public OxyRect LineExtents { get; set; }
+
+        /// <summary>
+        /// Gets or sets the plot model.
+        /// </summary>
+        public PlotModel PlotModel { get; set; }
+
+        /// <summary>
+        /// Gets or sets the position in screen coordinates.
+        /// </summary>
+        public ScreenPoint Position { get; set; }
+
+        /// <summary>
+        /// Gets or sets the series that is being tracked.
+        /// </summary>
+        public Series.Series Series { get; set; }
+
+        /// <summary>
+        /// Gets or sets the text shown in the tracker.
+        /// </summary>
+        public string Text { get; set; }
+
+        /// <summary>
+        /// Gets or sets the X axis.
+        /// </summary>
+        public Axes.Axis XAxis { get; set; }
+
+        /// <summary>
+        /// Gets or sets the Y axis.
+        /// </summary>
+        public Axes.Axis YAxis { get; set; }
+
+        /// <summary>
+        /// Returns a <see cref="System.String"/> that represents this instance.
+        /// </summary>
+        /// <returns>
+        /// A <see cref="System.String"/> that represents this instance.
+        /// </returns>
+        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 --git a/oxyplot/OxyPlot/Manipulators/TrackerManipulator.cs 
b/oxyplot/OxyPlot/Manipulators/TrackerManipulator.cs
new file mode 100644
index 0000000..de1b402
--- /dev/null
+++ b/oxyplot/OxyPlot/Manipulators/TrackerManipulator.cs
@@ -0,0 +1,186 @@
+// 
--------------------------------------------------------------------------------------------------------------------
+// <copyright file="TrackerManipulator.cs" company="OxyPlot">
+//   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.
+// </copyright>
+// <summary>
+//   The tracker manipulator.
+// </summary>
+// 
--------------------------------------------------------------------------------------------------------------------
+namespace OxyPlot
+{
+    using OxyPlot.Series;
+
+    /// <summary>
+    /// Provides a plot control manipulator for tracker functionality.
+    /// </summary>
+    public class TrackerManipulator : ManipulatorBase
+    {
+        /// <summary>
+        /// The current series.
+        /// </summary>
+        private ITrackableSeries currentSeries;
+
+        /// <summary>
+        /// Initializes a new instance of the <see cref="TrackerManipulator"/> class.
+        /// </summary>
+        /// <param name="plotControl">
+        /// The plot control.
+        /// </param>
+        public TrackerManipulator(IPlotControl plotControl)
+            : base(plotControl)
+        {
+            this.Snap = true;
+            this.PointsOnly = false;
+        }
+
+        /// <summary>
+        /// Gets or sets a value indicating whether to show tracker on points only (not interpolating).
+        /// </summary>
+        public bool PointsOnly { get; set; }
+
+        /// <summary>
+        /// Gets or sets a value indicating whether to snap to the nearest point.
+        /// </summary>
+        public bool Snap { get; set; }
+
+        /// <summary>
+        /// Occurs when a manipulation is complete.
+        /// </summary>
+        /// <param name="e">
+        /// The <see cref="OxyPlot.ManipulationEventArgs"/> instance containing the event data.
+        /// </param>
+        public override void Completed(ManipulationEventArgs e)
+        {
+            base.Completed(e);
+
+            if (this.currentSeries == null)
+            {
+                return;
+            }
+
+            this.currentSeries = null;
+            this.PlotControl.HideTracker();
+        }
+
+        /// <summary>
+        /// Occurs when the input device changes position during a manipulation.
+        /// </summary>
+        /// <param name="e">
+        /// The <see cref="OxyPlot.ManipulationEventArgs"/> instance containing the event data.
+        /// </param>
+        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);
+            }
+        }
+
+        /// <summary>
+        /// Gets the cursor for the manipulation.
+        /// </summary>
+        /// <returns>
+        /// The cursor.
+        /// </returns>
+        public override CursorType GetCursorType()
+        {
+            return CursorType.Default;
+        }
+
+        /// <summary>
+        /// Occurs when an input device begins a manipulation on the plot.
+        /// </summary>
+        /// <param name="e">
+        /// The <see cref="OxyPlot.ManipulationEventArgs"/> instance containing the event data.
+        /// </param>
+        public override void Started(ManipulationEventArgs e)
+        {
+            base.Started(e);
+            this.currentSeries = this.PlotControl.GetSeriesFromPoint(e.CurrentPosition);
+            this.Delta(e);
+        }
+
+        /// <summary>
+        /// Gets the nearest tracker hit.
+        /// </summary>
+        /// <param name="s">
+        /// The series.
+        /// </param>
+        /// <param name="point">
+        /// The point.
+        /// </param>
+        /// <param name="snap">
+        /// Snap to points.
+        /// </param>
+        /// <param name="pointsOnly">
+        /// Check points only (no interpolation).
+        /// </param>
+        /// <returns>
+        /// A tracker hit result.
+        /// </returns>
+        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 --git a/oxyplot/OxyPlot/Manipulators/ZoomManipulator.cs b/oxyplot/OxyPlot/Manipulators/ZoomManipulator.cs
new file mode 100644
index 0000000..4fb9f01
--- /dev/null
+++ b/oxyplot/OxyPlot/Manipulators/ZoomManipulator.cs
@@ -0,0 +1,72 @@
+// 
--------------------------------------------------------------------------------------------------------------------
+// <copyright file="ZoomManipulator.cs" company="OxyPlot">
+//   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.
+// </copyright>
+// <summary>
+//   The zoom manipulator.
+// </summary>
+// 
--------------------------------------------------------------------------------------------------------------------
+namespace OxyPlot
+{
+    /// <summary>
+    /// Provides a plot control manipulator for zoom functionality.
+    /// </summary>
+    public class ZoomManipulator : ManipulatorBase
+    {
+        /// <summary>
+        /// Initializes a new instance of the <see cref="ZoomManipulator"/> class.
+        /// </summary>
+        /// <param name="plotControl">
+        /// The plot control.
+        /// </param>
+        public ZoomManipulator(IPlotControl plotControl)
+            : base(plotControl)
+        {
+        }
+
+        /// <summary>
+        /// Occurs when the input device changes position during a manipulation.
+        /// </summary>
+        /// <param name="e">The <see cref="OxyPlot.ManipulationEventArgs"/> instance containing the event 
data.</param>
+        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 --git a/oxyplot/OxyPlot/Manipulators/ZoomRectangleManipulator.cs 
b/oxyplot/OxyPlot/Manipulators/ZoomRectangleManipulator.cs
new file mode 100644
index 0000000..4c74e5a
--- /dev/null
+++ b/oxyplot/OxyPlot/Manipulators/ZoomRectangleManipulator.cs
@@ -0,0 +1,154 @@
+// 
--------------------------------------------------------------------------------------------------------------------
+// <copyright file="ZoomRectangleManipulator.cs" company="OxyPlot">
+//   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.
+// </copyright>
+// <summary>
+//   The zoom manipulator.
+// </summary>
+// 
--------------------------------------------------------------------------------------------------------------------
+namespace OxyPlot
+{
+    using System;
+
+    /// <summary>
+    /// Provides a plot control manipulator for zoom by rectangle functionality.
+    /// </summary>
+    public class ZoomRectangleManipulator : ManipulatorBase
+    {
+        /// <summary>
+        /// Initializes a new instance of the <see cref="ZoomRectangleManipulator"/> class.
+        /// </summary>
+        /// <param name="plotControl">
+        /// The plot control.
+        /// </param>
+        public ZoomRectangleManipulator(IPlotControl plotControl)
+            : base(plotControl)
+        {
+        }
+
+        /// <summary>
+        /// Gets or sets the zoom rectangle.
+        /// </summary>
+        private OxyRect ZoomRectangle { get; set; }
+
+        /// <summary>
+        /// Occurs when a manipulation is complete.
+        /// </summary>
+        /// <param name="e">
+        /// The <see cref="OxyPlot.ManipulationEventArgs"/> instance containing the event data.
+        /// </param>
+        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();
+            }
+        }
+
+        /// <summary>
+        /// Occurs when the input device changes position during a manipulation.
+        /// </summary>
+        /// <param name="e">
+        /// The <see cref="OxyPlot.ManipulationEventArgs"/> instance containing the event data.
+        /// </param>
+        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);
+        }
+
+        /// <summary>
+        /// Gets the cursor for the manipulation.
+        /// </summary>
+        /// <returns>
+        /// The cursor.
+        /// </returns>
+        public override CursorType GetCursorType()
+        {
+            if (this.XAxis == null)
+            {
+                return CursorType.ZoomVertical;
+            }
+
+            if (this.YAxis == null)
+            {
+                return CursorType.ZoomHorizontal;
+            }
+
+            return CursorType.ZoomRectangle;
+        }
+
+        /// <summary>
+        /// Occurs when an input device begins a manipulation on the plot.
+        /// </summary>
+        /// <param name="e">
+        /// The <see cref="OxyPlot.ManipulationEventArgs"/> instance containing the event data.
+        /// </param>
+        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 --git a/oxyplot/OxyPlot/Manipulators/ZoomStepManipulator.cs 
b/oxyplot/OxyPlot/Manipulators/ZoomStepManipulator.cs
new file mode 100644
index 0000000..57e32f7
--- /dev/null
+++ b/oxyplot/OxyPlot/Manipulators/ZoomStepManipulator.cs
@@ -0,0 +1,106 @@
+// 
--------------------------------------------------------------------------------------------------------------------
+// <copyright file="ZoomStepManipulator.cs" company="OxyPlot">
+//   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.
+// </copyright>
+// <summary>
+//   The step manipulator.
+// </summary>
+// 
--------------------------------------------------------------------------------------------------------------------
+namespace OxyPlot
+{
+    /// <summary>
+    /// Provides a plot control manipulator for stepwise zoom functionality.
+    /// </summary>
+    public class ZoomStepManipulator : ManipulatorBase
+    {
+        /// <summary>
+        /// Initializes a new instance of the <see cref="ZoomStepManipulator"/> class.
+        /// </summary>
+        /// <param name="plotControl">
+        /// The plot control.
+        /// </param>
+        /// <param name="step">
+        /// The step.
+        /// </param>
+        /// <param name="fineControl">
+        /// The fine Control.
+        /// </param>
+        public ZoomStepManipulator(IPlotControl plotControl, double step, bool fineControl)
+            : base(plotControl)
+        {
+            this.Step = step;
+            this.FineControl = fineControl;
+        }
+
+        /// <summary>
+        /// Gets or sets a value indicating whether FineControl.
+        /// </summary>
+        public bool FineControl { get; set; }
+
+        /// <summary>
+        /// Gets or sets Step.
+        /// </summary>
+        public double Step { get; set; }
+
+        /// <summary>
+        /// The started.
+        /// </summary>
+        /// <param name="e">
+        /// The e.
+        /// </param>
+        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 --git a/oxyplot/OxyPlot/MouseActions/MouseAction.cs b/oxyplot/OxyPlot/MouseActions/MouseAction.cs
new file mode 100644
index 0000000..0115a42
--- /dev/null
+++ b/oxyplot/OxyPlot/MouseActions/MouseAction.cs
@@ -0,0 +1,54 @@
+// 
--------------------------------------------------------------------------------------------------------------------
+// <copyright file="MouseAction.cs" company="OxyPlot">
+//   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.
+// </copyright>
+// 
--------------------------------------------------------------------------------------------------------------------
+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 --git a/oxyplot/OxyPlot/MouseActions/SliderAction.cs b/oxyplot/OxyPlot/MouseActions/SliderAction.cs
new file mode 100644
index 0000000..c885313
--- /dev/null
+++ b/oxyplot/OxyPlot/MouseActions/SliderAction.cs
@@ -0,0 +1,106 @@
+// 
--------------------------------------------------------------------------------------------------------------------
+// <copyright file="SliderAction.cs" company="OxyPlot">
+//   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.
+// </copyright>
+// 
--------------------------------------------------------------------------------------------------------------------
+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 --git a/oxyplot/OxyPlot/NamespaceDoc.cs b/oxyplot/OxyPlot/NamespaceDoc.cs
new file mode 100644
index 0000000..ee5c6a4
--- /dev/null
+++ b/oxyplot/OxyPlot/NamespaceDoc.cs
@@ -0,0 +1,37 @@
+// 
--------------------------------------------------------------------------------------------------------------------
+// <copyright file="NamespaceDoc.cs" company="OxyPlot">
+//   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.
+// </copyright>
+// 
--------------------------------------------------------------------------------------------------------------------
+
+namespace OxyPlot
+{
+    /// <summary>
+    /// The OxyPlot namespace contains the platform independent classes of the library.
+    /// </summary>
+    [System.Runtime.CompilerServices.CompilerGenerated]
+    internal class NamespaceDoc
+    {
+    }
+}
\ No newline at end of file
diff --git a/oxyplot/OxyPlot/OxyPlot.csproj b/oxyplot/OxyPlot/OxyPlot.csproj
new file mode 100644
index 0000000..9a37c52
--- /dev/null
+++ b/oxyplot/OxyPlot/OxyPlot.csproj
@@ -0,0 +1,230 @@
+<?xml version="1.0" encoding="utf-8"?>
+<Project ToolsVersion="4.0" DefaultTargets="Build" 
xmlns="http://schemas.microsoft.com/developer/msbuild/2003";>
+  <Import Project="$(MSBuildExtensionsPath)\$(MSBuildToolsVersion)\Microsoft.Common.props" 
Condition="Exists('$(MSBuildExtensionsPath)\$(MSBuildToolsVersion)\Microsoft.Common.props')" />
+  <PropertyGroup>
+    <MinimumVisualStudioVersion>10.0</MinimumVisualStudioVersion>
+    <Configuration Condition=" '$(Configuration)' == '' ">Debug</Configuration>
+    <Platform Condition=" '$(Platform)' == '' ">AnyCPU</Platform>
+    <ProjectGuid>{7A0B35C0-DD17-4964-8E9A-44D6CECDC692}</ProjectGuid>
+    <OutputType>Library</OutputType>
+    <AppDesignerFolder>Properties</AppDesignerFolder>
+    <RootNamespace>OxyPlot</RootNamespace>
+    <AssemblyName>OxyPlot</AssemblyName>
+    <TargetFrameworkVersion>v4.0</TargetFrameworkVersion>
+    <TargetFrameworkProfile>Profile2</TargetFrameworkProfile>
+    <FileAlignment>512</FileAlignment>
+    
<ProjectTypeGuids>{786C830F-07A1-408B-BD7F-6EE04809D6DB};{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}</ProjectTypeGuids>
+  </PropertyGroup>
+  <PropertyGroup Condition=" '$(Configuration)|$(Platform)' == 'Debug|AnyCPU' ">
+    <DebugSymbols>true</DebugSymbols>
+    <DebugType>full</DebugType>
+    <Optimize>false</Optimize>
+    <OutputPath>bin\Debug\</OutputPath>
+    <DefineConstants>TRACE;DEBUG;PCL</DefineConstants>
+    <ErrorReport>prompt</ErrorReport>
+    <WarningLevel>4</WarningLevel>
+  </PropertyGroup>
+  <PropertyGroup Condition=" '$(Configuration)|$(Platform)' == 'Release|AnyCPU' ">
+    <DebugType>pdbonly</DebugType>
+    <Optimize>true</Optimize>
+    <OutputPath>..\..\Output\PCL\</OutputPath>
+    <DefineConstants>TRACE;PCL</DefineConstants>
+    <ErrorReport>prompt</ErrorReport>
+    <WarningLevel>4</WarningLevel>
+    <DocumentationFile>..\..\Output\PCL\OxyPlot.xml</DocumentationFile>
+  </PropertyGroup>
+  <PropertyGroup>
+    <SignAssembly>true</SignAssembly>
+  </PropertyGroup>
+  <PropertyGroup>
+    <AssemblyOriginatorKeyFile>OxyPlot.snk</AssemblyOriginatorKeyFile>
+  </PropertyGroup>
+  <ItemGroup>
+    <Compile Include="..\GlobalAssemblyInfo.cs">
+      <Link>Properties\GlobalAssemblyInfo.cs</Link>
+    </Compile>
+    <Compile Include="Annotations\Annotation.cs" />
+    <Compile Include="Annotations\AnnotationLayer.cs" />
+    <Compile Include="Annotations\ArrowAnnotation.cs" />
+    <Compile Include="Annotations\EllipseAnnotation.cs" />
+    <Compile Include="Annotations\ImageAnnotation.cs" />
+    <Compile Include="Annotations\TileMapAnnotation.cs" />
+    <Compile Include="Foundation\PlotLength.cs" />
+    <Compile Include="Foundation\PlotLengthUnit.cs" />
+    <Compile Include="Annotations\RectangleAnnotation.cs" />
+    <Compile Include="Annotations\TextAnnotation.cs" />
+    <Compile Include="Annotations\PolygonAnnotation.cs" />
+    <Compile Include="Annotations\LineAnnotation.cs" />
+    <Compile Include="Annotations\LineAnnotationType.cs" />
+    <Compile Include="Annotations\TextualAnnotation.cs" />
+    <Compile Include="Axes\AngleAxis.cs" />
+    <Compile Include="Axes\Axis.cs" />
+    <Compile Include="Axes\AxisChangedEventArgs.cs" />
+    <Compile Include="Axes\AxisChangeTypes.cs" />
+    <Compile Include="Axes\AxisLayer.cs" />
+    <Compile Include="Axes\AxisPosition.cs" />
+    <Compile Include="Axes\CategoryAxis.cs" />
+    <Compile Include="Axes\ColorAxis.cs" />
+    <Compile Include="Axes\DateTimeAxis.cs" />
+    <Compile Include="Axes\DateTimeIntervalType.cs" />
+    <Compile Include="Axes\LinearAxis.cs" />
+    <Compile Include="Axes\MagnitudeAxis.cs" />
+    <Compile Include="Axes\TickStyle.cs" />
+    <Compile Include="Axes\TimeSpanAxis.cs" />
+    <Compile Include="Foundation\CodeGenerator\CodeGenerationAttribute.cs" />
+    <Compile Include="Foundation\CodeGenerator\CodeGenerator.cs" />
+    <Compile Include="Foundation\CodeGenerator\CodeGeneratorStringExtensions.cs" />
+    <Compile Include="Foundation\CodeGenerator\ICodeGenerating.cs" />
+    <Compile Include="Foundation\ListFiller.cs" />
+    <Compile Include="Foundation\OxyPalette.cs" />
+    <Compile Include="Foundation\OxyPalettes.cs" />
+    <Compile Include="Foundation\PngEncoder.cs" />
+    <Compile Include="Foundation\ScreenVector.cs" />
+    <Compile Include="Foundation\StreamExtensions.cs" />
+    <Compile Include="Foundation\StringHelper.cs" />
+    <Compile Include="Foundation\DoubleExtensions.cs" />
+    <Compile Include="Foundation\FractionHelper.cs" />
+    <Compile Include="Foundation\ArrayHelper.cs" />
+    <Compile Include="Foundation\IDataPoint.cs" />
+    <Compile Include="Foundation\ReflectionHelper.cs" />
+    <Compile Include="Foundation\ScreenPointHelper.cs" />
+    <Compile Include="Manipulators\ZoomManipulator.cs" />
+    <Compile Include="Manipulators\ZoomStepManipulator.cs" />
+    <Compile Include="Manipulators\ResetManipulator.cs" />
+    <Compile Include="Manipulators\ManipulationEventArgs.cs" />
+    <Compile Include="Manipulators\TrackerManipulator.cs" />
+    <Compile Include="Manipulators\ZoomRectangleManipulator.cs" />
+    <Compile Include="Manipulators\ManipulatorBase.cs" />
+    <Compile Include="Manipulators\CursorType.cs" />
+    <Compile Include="Manipulators\PanManipulator.cs" />
+    <Compile Include="Manipulators\TrackerHitResult.cs" />
+    <Compile Include="LibraryDoc.cs" />
+    <Compile Include="NamespaceDoc.cs" />
+    <Compile Include="PlotModel\HitTestResult.cs" />
+    <Compile Include="Foundation\OxyImage.cs" />
+    <Compile Include="Reporting\NamespaceDoc.cs" />
+    <Compile Include="Series\BarSeries\BarItem.cs" />
+    <Compile Include="Series\BarSeries\BarItemBase.cs" />
+    <Compile Include="Series\BarSeries\BarSeriesBase{T}.cs" />
+    <Compile Include="Series\BarSeries\CategorizedItem.cs" />
+    <Compile Include="Series\BarSeries\CategorizedSeries.cs" />
+    <Compile Include="Series\BarSeries\ErrorColumnItem.cs" />
+    <Compile Include="Series\BarSeries\ColumnItem.cs" />
+    <Compile Include="Series\BarSeries\ErrorColumnSeries.cs" />
+    <Compile Include="Series\BarSeries\IStackableSeries.cs" />
+    <Compile Include="Series\BoxPlotItem.cs" />
+    <Compile Include="Series\BoxPlotSeries.cs" />
+    <Compile Include="Foundation\IDataPointProvider.cs" />
+    <Compile Include="Series\HeatMapSeries.cs" />
+    <Compile Include="Series\LineLegendPosition.cs" />
+    <Compile Include="Svg\SvgExporter.cs" />
+    <Compile Include="PlotModel\PlotModel.MouseEvents.cs" />
+    <Compile Include="PlotModel\OxyMouseButton.cs" />
+    <Compile Include="PlotModel\OxyMouseEventArgs.cs" />
+    <Compile Include="PlotModel\PlotElement.cs" />
+    <Compile Include="PlotModel\PlotModel.Legends.cs" />
+    <Compile Include="Foundation\CanonicalSplineHelper.cs" />
+    <Compile Include="Foundation\FontWeights.cs" />
+    <Compile Include="Foundation\OxyThickness.cs" />
+    <Compile Include="Foundation\ScreenPoint.cs" />
+    <Compile Include="Foundation\OxyRect.cs" />
+    <Compile Include="Foundation\OxySize.cs" />
+    <Compile Include="Foundation\SutherlandHodgmanClipping.cs" />
+    <Compile Include="Manipulators\IPlotControl.cs" />
+    <Compile Include="PlotModel\PlotModel.Rendering.cs" />
+    <Compile Include="PlotModel\SelectablePlotElement.cs" />
+    <Compile Include="PlotModel\UIPlotElement.cs" />
+    <Compile Include="Render\AxisRendererBase.cs" />
+    <Compile Include="Foundation\CohenSutherlandClipping.cs" />
+    <Compile Include="Render\AngleAxisRenderer.cs" />
+    <Compile Include="Foundation\HorizontalAlignment.cs" />
+    <Compile Include="Render\MagnitudeAxisRenderer.cs" />
+    <Compile Include="Render\MathRenderingExtensions.cs" />
+    <Compile Include="Foundation\OxyPenLineJoin.cs" />
+    <Compile Include="Render\RenderContextBase.cs" />
+    <Compile Include="Render\RenderingExtensions.cs" />
+    <Compile Include="Render\HorizontalAndVerticalAxisRenderer.cs" />
+    <Compile Include="Render\IRenderContext.cs" />
+    <Compile Include="Foundation\VerticalAlignment.cs" />
+    <Compile Include="Reporting\ReportWriters\WikiReportWriter.cs" />
+    <Compile Include="Reporting\ReportWriters\HtmlReportWriter.cs" />
+    <Compile Include="Reporting\ReportWriters\IReportWriter.cs" />
+    <Compile Include="Reporting\ReportWriters\StringExtensions.cs" />
+    <Compile Include="Reporting\ReportWriters\TextReportWriter.cs" />
+    <Compile Include="Reporting\Report\ItemsTable.cs" />
+    <Compile Include="Reporting\Report\ParagraphStyle.cs" />
+    <Compile Include="Reporting\Report\ReportStyle.cs" />
+    <Compile Include="Reporting\Report\TableOfContents.cs" />
+    <Compile Include="Reporting\Report\DrawingFigure.cs" />
+    <Compile Include="Reporting\Report\Equation.cs" />
+    <Compile Include="Reporting\Report\Figure.cs" />
+    <Compile Include="Reporting\Report\Header.cs" />
+    <Compile Include="Reporting\Report\HeaderHelper.cs" />
+    <Compile Include="Reporting\Report\Image.cs" />
+    <Compile Include="Reporting\Report\Paragraph.cs" />
+    <Compile Include="Reporting\Report\PlotFigure.cs" />
+    <Compile Include="Reporting\Report\PropertyTable.cs" />
+    <Compile Include="Reporting\Report\Report.cs" />
+    <Compile Include="Reporting\Report\ReportItem.cs" />
+    <Compile Include="Reporting\Report\ReportSection.cs" />
+    <Compile Include="Reporting\Report\Table.cs" />
+    <Compile Include="Reporting\Report\ItemsTableField.cs" />
+    <Compile Include="Series\AreaSeries.cs" />
+    <Compile Include="Foundation\OxyPen.cs" />
+    <Compile Include="Foundation\LineStyleHelper.cs" />
+    <Compile Include="Foundation\DataPoint.cs" />
+    <Compile Include="Series\BarSeries\LabelPlacement.cs" />
+    <Compile Include="Series\CandleStickSeries.cs" />
+    <Compile Include="Foundation\Conrec.cs" />
+    <Compile Include="Series\ContourSeries.cs" />
+    <Compile Include="Series\BarSeries\ColumnSeries.cs" />
+    <Compile Include="Series\BarSeries\BarSeries.cs" />
+    <Compile Include="Series\BarSeries\BarSeriesBase.cs" />
+    <Compile Include="Series\BarSeries\IntervalBarItem.cs" />
+    <Compile Include="Series\BarSeries\RectangleBarItem.cs" />
+    <Compile Include="Series\BarSeries\RectangleBarSeries.cs" />
+    <Compile Include="Series\BarSeries\IntervalBarSeries.cs" />
+    <Compile Include="Series\BarSeries\TornadoBarItem.cs" />
+    <Compile Include="Series\BarSeries\TornadoBarSeries.cs" />
+    <Compile Include="Series\ItemsSeries.cs" />
+    <Compile Include="Series\DataPointSeries.cs" />
+    <Compile Include="Series\HighLowItem.cs" />
+    <Compile Include="Series\HighLowSeries.cs" />
+    <Compile Include="Series\ScatterPoint.cs" />
+    <Compile Include="Series\Series.cs" />
+    <Compile Include="Series\StemSeries.cs" />
+    <Compile Include="Series\StairStepSeries.cs" />
+    <Compile Include="Series\ITrackableSeries.cs" />
+    <Compile Include="Series\ScatterSeries.cs" />
+    <Compile Include="Series\TwoColorLineSeries.cs" />
+    <Compile Include="Series\XYAxisSeries.cs" />
+    <Compile Include="Series\PieSeries.cs" />
+    <Compile Include="Series\FunctionSeries.cs" />
+    <Compile Include="Series\PieSlice.cs" />
+    <Compile Include="Svg\SvgRenderContext.cs" />
+    <Compile Include="Svg\SvgWriter.cs" />
+    <Compile Include="Foundation\OxyColor.cs" />
+    <Compile Include="Foundation\OxyColors.cs" />
+    <Compile Include="Series\LineSeries.cs" />
+    <Compile Include="Foundation\LineStyle.cs" />
+    <Compile Include="Axes\LogarithmicAxis.cs" />
+    <Compile Include="Foundation\MarkerType.cs" />
+    <Compile Include="PlotModel\PlotModel.cs" />
+    <Compile Include="Properties\AssemblyInfo.cs" />
+    <Compile Include="Foundation\XmlWriterBase.cs" />
+  </ItemGroup>
+  <ItemGroup>
+    <None Include="ClassDiagrams\Series.cd" />
+    <None Include="ClassDiagrams\PlotModel.cd" />
+    <None Include="ClassDiagrams\Reporting.cd" />
+    <None Include="OxyPlot.snk" />
+  </ItemGroup>
+  <Import 
Project="$(MSBuildExtensionsPath32)\Microsoft\Portable\$(TargetFrameworkVersion)\Microsoft.Portable.CSharp.targets"
 />
+  <!-- To modify your build process, add your task inside one of the targets below and uncomment it. 
+       Other similar extension points exist, see Microsoft.Common.targets.
+  <Target Name="BeforeBuild">
+  </Target>
+  <Target Name="AfterBuild">
+  </Target>
+  -->
+</Project>
\ No newline at end of file
diff --git a/oxyplot/OxyPlot/OxyPlot.csproj.DotSettings b/oxyplot/OxyPlot/OxyPlot.csproj.DotSettings
new file mode 100644
index 0000000..ea950d1
--- /dev/null
+++ b/oxyplot/OxyPlot/OxyPlot.csproj.DotSettings
@@ -0,0 +1,15 @@
+<wpf:ResourceDictionary xml:space="preserve" xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"; 
xmlns:s="clr-namespace:System;assembly=mscorlib" xmlns:ss="urn:shemas-jetbrains-com:settings-storage-xaml" 
xmlns:wpf="http://schemas.microsoft.com/winfx/2006/xaml/presentation";>
+       <s:Boolean 
x:Key="/Default/CodeInspection/NamespaceProvider/NamespaceFoldersToSkip/=Annotations/@EntryIndexedValue">False</s:Boolean>
+       <s:Boolean 
x:Key="/Default/CodeInspection/NamespaceProvider/NamespaceFoldersToSkip/=Axes/@EntryIndexedValue">False</s:Boolean>
+       <s:Boolean 
x:Key="/Default/CodeInspection/NamespaceProvider/NamespaceFoldersToSkip/=ClassDiagrams/@EntryIndexedValue">True</s:Boolean>
+       <s:Boolean 
x:Key="/Default/CodeInspection/NamespaceProvider/NamespaceFoldersToSkip/=Foundation_005CCodeGenerator/@EntryIndexedValue">True</s:Boolean>
+       <s:Boolean 
x:Key="/Default/CodeInspection/NamespaceProvider/NamespaceFoldersToSkip/=Foundation/@EntryIndexedValue">True</s:Boolean>
+       <s:Boolean 
x:Key="/Default/CodeInspection/NamespaceProvider/NamespaceFoldersToSkip/=Manipulators/@EntryIndexedValue">True</s:Boolean>
+       <s:Boolean 
x:Key="/Default/CodeInspection/NamespaceProvider/NamespaceFoldersToSkip/=PlotModel/@EntryIndexedValue">True</s:Boolean>
+       <s:Boolean 
x:Key="/Default/CodeInspection/NamespaceProvider/NamespaceFoldersToSkip/=Render/@EntryIndexedValue">True</s:Boolean>
+       <s:Boolean 
x:Key="/Default/CodeInspection/NamespaceProvider/NamespaceFoldersToSkip/=Reporting_005CReport/@EntryIndexedValue">True</s:Boolean>
+       <s:Boolean 
x:Key="/Default/CodeInspection/NamespaceProvider/NamespaceFoldersToSkip/=Reporting_005CReportWriters/@EntryIndexedValue">True</s:Boolean>
+       <s:Boolean 
x:Key="/Default/CodeInspection/NamespaceProvider/NamespaceFoldersToSkip/=Reporting/@EntryIndexedValue">True</s:Boolean>
+       <s:Boolean 
x:Key="/Default/CodeInspection/NamespaceProvider/NamespaceFoldersToSkip/=Series/@EntryIndexedValue">False</s:Boolean>
+       <s:Boolean 
x:Key="/Default/CodeInspection/NamespaceProvider/NamespaceFoldersToSkip/=Series_005CBarSeries/@EntryIndexedValue">True</s:Boolean>
+       <s:Boolean 
x:Key="/Default/CodeInspection/NamespaceProvider/NamespaceFoldersToSkip/=Svg/@EntryIndexedValue">True</s:Boolean></wpf:ResourceDictionary>
\ No newline at end of file
diff --git a/oxyplot/OxyPlot/OxyPlot.csproj.ReSharper b/oxyplot/OxyPlot/OxyPlot.csproj.ReSharper
new file mode 100644
index 0000000..6f40c87
--- /dev/null
+++ b/oxyplot/OxyPlot/OxyPlot.csproj.ReSharper
@@ -0,0 +1,16 @@
+<Configuration>
+  <NamespaceFolders>
+    <SkipFolder>87F519B8-5A2F-48C6-AD53-C5F13A82EA6B/d:Annotations</SkipFolder>
+    <SkipFolder>87F519B8-5A2F-48C6-AD53-C5F13A82EA6B/d:Axes</SkipFolder>
+    <SkipFolder>87F519B8-5A2F-48C6-AD53-C5F13A82EA6B/d:ClassDiagrams</SkipFolder>
+    <SkipFolder>87F519B8-5A2F-48C6-AD53-C5F13A82EA6B/d:Foundation/d:CodeGenerator</SkipFolder>
+    <SkipFolder>87F519B8-5A2F-48C6-AD53-C5F13A82EA6B/d:Foundation</SkipFolder>
+    <SkipFolder>87F519B8-5A2F-48C6-AD53-C5F13A82EA6B/d:PlotModel</SkipFolder>
+    <SkipFolder>87F519B8-5A2F-48C6-AD53-C5F13A82EA6B/d:Render</SkipFolder>
+    <SkipFolder>87F519B8-5A2F-48C6-AD53-C5F13A82EA6B/d:Reporting/d:Report</SkipFolder>
+    <SkipFolder>87F519B8-5A2F-48C6-AD53-C5F13A82EA6B/d:Reporting/d:ReportWriters</SkipFolder>
+    <SkipFolder>87F519B8-5A2F-48C6-AD53-C5F13A82EA6B/d:Reporting</SkipFolder>
+    <SkipFolder>87F519B8-5A2F-48C6-AD53-C5F13A82EA6B/d:Series</SkipFolder>
+    <SkipFolder>87F519B8-5A2F-48C6-AD53-C5F13A82EA6B/d:Svg</SkipFolder>
+  </NamespaceFolders>
+</Configuration>
\ No newline at end of file
diff --git a/oxyplot/OxyPlot/OxyPlot.snk b/oxyplot/OxyPlot/OxyPlot.snk
new file mode 100644
index 0000000..3299564
Binary files /dev/null and b/oxyplot/OxyPlot/OxyPlot.snk differ
diff --git a/oxyplot/OxyPlot/OxyPlotMT.csproj b/oxyplot/OxyPlot/OxyPlotMT.csproj
new file mode 100644
index 0000000..1038ae0
--- /dev/null
+++ b/oxyplot/OxyPlot/OxyPlotMT.csproj
@@ -0,0 +1,229 @@
+<?xml version="1.0" encoding="utf-8"?>
+<Project ToolsVersion="4.0" DefaultTargets="Build" 
xmlns="http://schemas.microsoft.com/developer/msbuild/2003";>
+  <PropertyGroup>
+    <Configuration Condition=" '$(Configuration)' == '' ">Debug</Configuration>
+    <Platform Condition=" '$(Platform)' == '' ">AnyCPU</Platform>
+    <ProductVersion>10.0.0</ProductVersion>
+    <SchemaVersion>2.0</SchemaVersion>
+    <ProjectGuid>{A9B53EF9-88CE-4934-8C8F-236ECEEA676D}</ProjectGuid>
+    
<ProjectTypeGuids>{6BC8ED88-2882-458C-8E55-DFD12B67127B};{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}</ProjectTypeGuids>
+    <OutputType>Library</OutputType>
+    <AppDesignerFolder>Properties</AppDesignerFolder>
+    <RootNamespace>OxyPlot</RootNamespace>
+    <AssemblyName>OxyPlot</AssemblyName>
+    <!--<TargetFrameworkProfile>Client</TargetFrameworkProfile>-->
+  </PropertyGroup>
+  <PropertyGroup Condition=" '$(Configuration)|$(Platform)' == 'Debug|AnyCPU' ">
+    <DebugSymbols>True</DebugSymbols>
+    <DebugType>full</DebugType>
+    <Optimize>False</Optimize>
+    <OutputPath>bin\Debug\MT\</OutputPath>
+    <IntermediateOutputPath>obj\Debug\MT\</IntermediateOutputPath>
+    <DefineConstants>DEBUG;TRACE;MONO</DefineConstants>
+    <ErrorReport>prompt</ErrorReport>
+    <WarningLevel>4</WarningLevel>
+  </PropertyGroup>
+  <PropertyGroup Condition=" '$(Configuration)|$(Platform)' == 'Release|AnyCPU' ">
+    <DebugType>pdbonly</DebugType>
+    <Optimize>True</Optimize>
+    <OutputPath>..\..\Output\MT\</OutputPath>
+    <IntermediateOutputPath>obj\Release\MT\</IntermediateOutputPath>
+    <DefineConstants>TRACE</DefineConstants>
+    <ErrorReport>prompt</ErrorReport>
+    <WarningLevel>4</WarningLevel>
+    <DocumentationFile>..\..\Output\MT\OxyPlot.XML</DocumentationFile>
+  </PropertyGroup>
+  <ItemGroup>
+    <Reference Include="System" />
+    <Reference Include="System.Core" />
+    <Reference Include="System.Xml" />
+  </ItemGroup>
+  <ItemGroup>
+    <Compile Include="..\GlobalAssemblyInfo.cs">
+      <Link>Properties\GlobalAssemblyInfo.cs</Link>
+    </Compile>
+    <Compile Include="Annotations\Annotation.cs" />
+    <Compile Include="Annotations\AnnotationLayer.cs" />
+    <Compile Include="Annotations\ArrowAnnotation.cs" />
+    <Compile Include="Annotations\EllipseAnnotation.cs" />
+    <Compile Include="Annotations\ImageAnnotation.cs" />
+    <Compile Include="Annotations\TileMapAnnotation.cs" />
+    <Compile Include="Foundation\PlotLength.cs" />
+    <Compile Include="Foundation\PlotLengthUnit.cs" />
+    <Compile Include="Annotations\RectangleAnnotation.cs" />
+    <Compile Include="Annotations\TextAnnotation.cs" />
+    <Compile Include="Annotations\PolygonAnnotation.cs" />
+    <Compile Include="Annotations\LineAnnotation.cs" />
+    <Compile Include="Annotations\LineAnnotationType.cs" />
+    <Compile Include="Annotations\TextualAnnotation.cs" />
+    <Compile Include="Axes\AngleAxis.cs" />
+    <Compile Include="Axes\Axis.cs" />
+    <Compile Include="Axes\AxisChangedEventArgs.cs" />
+    <Compile Include="Axes\AxisChangeTypes.cs" />
+    <Compile Include="Axes\AxisLayer.cs" />
+    <Compile Include="Axes\AxisPosition.cs" />
+    <Compile Include="Axes\CategoryAxis.cs" />
+    <Compile Include="Axes\ColorAxis.cs" />
+    <Compile Include="Axes\DateTimeAxis.cs" />
+    <Compile Include="Axes\DateTimeIntervalType.cs" />
+    <Compile Include="Axes\LinearAxis.cs" />
+    <Compile Include="Axes\MagnitudeAxis.cs" />
+    <Compile Include="Axes\TickStyle.cs" />
+    <Compile Include="Axes\TimeSpanAxis.cs" />
+    <Compile Include="Foundation\CodeGenerator\CodeGenerationAttribute.cs" />
+    <Compile Include="Foundation\CodeGenerator\CodeGenerator.cs" />
+    <Compile Include="Foundation\CodeGenerator\CodeGeneratorStringExtensions.cs" />
+    <Compile Include="Foundation\CodeGenerator\ICodeGenerating.cs" />
+    <Compile Include="Foundation\ListFiller.cs" />
+    <Compile Include="Foundation\OxyPalette.cs" />
+    <Compile Include="Foundation\OxyPalettes.cs" />
+    <Compile Include="Foundation\PngEncoder.cs" />
+    <Compile Include="Foundation\ScreenVector.cs" />
+    <Compile Include="Foundation\StreamExtensions.cs" />
+    <Compile Include="Foundation\StringHelper.cs" />
+    <Compile Include="Foundation\DoubleExtensions.cs" />
+    <Compile Include="Foundation\FractionHelper.cs" />
+    <Compile Include="Foundation\ArrayHelper.cs" />
+    <Compile Include="Foundation\IDataPoint.cs" />
+    <Compile Include="Foundation\ReflectionHelper.cs" />
+    <Compile Include="Foundation\ScreenPointHelper.cs" />
+    <Compile Include="Manipulators\ZoomManipulator.cs" />
+    <Compile Include="Manipulators\ZoomStepManipulator.cs" />
+    <Compile Include="Manipulators\ResetManipulator.cs" />
+    <Compile Include="Manipulators\ManipulationEventArgs.cs" />
+    <Compile Include="Manipulators\TrackerManipulator.cs" />
+    <Compile Include="Manipulators\ZoomRectangleManipulator.cs" />
+    <Compile Include="Manipulators\ManipulatorBase.cs" />
+    <Compile Include="Manipulators\CursorType.cs" />
+    <Compile Include="Manipulators\PanManipulator.cs" />
+    <Compile Include="Manipulators\TrackerHitResult.cs" />
+    <Compile Include="LibraryDoc.cs" />
+    <Compile Include="NamespaceDoc.cs" />
+    <Compile Include="PlotModel\HitTestResult.cs" />
+    <Compile Include="Foundation\OxyImage.cs" />
+    <Compile Include="Reporting\NamespaceDoc.cs" />
+    <Compile Include="Series\BarSeries\BarItem.cs" />
+    <Compile Include="Series\BarSeries\BarItemBase.cs" />
+    <Compile Include="Series\BarSeries\BarSeriesBase{T}.cs" />
+    <Compile Include="Series\BarSeries\CategorizedItem.cs" />
+    <Compile Include="Series\BarSeries\CategorizedSeries.cs" />
+    <Compile Include="Series\BarSeries\ErrorColumnItem.cs" />
+    <Compile Include="Series\BarSeries\ColumnItem.cs" />
+    <Compile Include="Series\BarSeries\ErrorColumnSeries.cs" />
+    <Compile Include="Series\BarSeries\IStackableSeries.cs" />
+    <Compile Include="Series\BoxPlotItem.cs" />
+    <Compile Include="Series\BoxPlotSeries.cs" />
+    <Compile Include="Foundation\IDataPointProvider.cs" />
+    <Compile Include="Series\HeatMapSeries.cs" />
+    <Compile Include="Series\LineLegendPosition.cs" />
+    <Compile Include="Svg\SvgExporter.cs" />
+    <Compile Include="PlotModel\PlotModel.MouseEvents.cs" />
+    <Compile Include="PlotModel\OxyMouseButton.cs" />
+    <Compile Include="PlotModel\OxyMouseEventArgs.cs" />
+    <Compile Include="PlotModel\PlotElement.cs" />
+    <Compile Include="PlotModel\PlotModel.Legends.cs" />
+    <Compile Include="Foundation\CanonicalSplineHelper.cs" />
+    <Compile Include="Foundation\FontWeights.cs" />
+    <Compile Include="Foundation\OxyThickness.cs" />
+    <Compile Include="Foundation\ScreenPoint.cs" />
+    <Compile Include="Foundation\OxyRect.cs" />
+    <Compile Include="Foundation\OxySize.cs" />
+    <Compile Include="Foundation\SutherlandHodgmanClipping.cs" />
+    <Compile Include="Manipulators\IPlotControl.cs" />
+    <Compile Include="PlotModel\PlotModel.Rendering.cs" />
+    <Compile Include="PlotModel\SelectablePlotElement.cs" />
+    <Compile Include="PlotModel\UIPlotElement.cs" />
+    <Compile Include="Render\AxisRendererBase.cs" />
+    <Compile Include="Foundation\CohenSutherlandClipping.cs" />
+    <Compile Include="Render\AngleAxisRenderer.cs" />
+    <Compile Include="Foundation\HorizontalAlignment.cs" />
+    <Compile Include="Render\MagnitudeAxisRenderer.cs" />
+    <Compile Include="Render\MathRenderingExtensions.cs" />
+    <Compile Include="Foundation\OxyPenLineJoin.cs" />
+    <Compile Include="Render\RenderContextBase.cs" />
+    <Compile Include="Render\RenderingExtensions.cs" />
+    <Compile Include="Render\HorizontalAndVerticalAxisRenderer.cs" />
+    <Compile Include="Render\IRenderContext.cs" />
+    <Compile Include="Foundation\VerticalAlignment.cs" />
+    <Compile Include="Reporting\ReportWriters\WikiReportWriter.cs" />
+    <Compile Include="Reporting\ReportWriters\HtmlReportWriter.cs" />
+    <Compile Include="Reporting\ReportWriters\IReportWriter.cs" />
+    <Compile Include="Reporting\ReportWriters\StringExtensions.cs" />
+    <Compile Include="Reporting\ReportWriters\TextReportWriter.cs" />
+    <Compile Include="Reporting\Report\ItemsTable.cs" />
+    <Compile Include="Reporting\Report\ParagraphStyle.cs" />
+    <Compile Include="Reporting\Report\ReportStyle.cs" />
+    <Compile Include="Reporting\Report\TableOfContents.cs" />
+    <Compile Include="Reporting\Report\DrawingFigure.cs" />
+    <Compile Include="Reporting\Report\Equation.cs" />
+    <Compile Include="Reporting\Report\Figure.cs" />
+    <Compile Include="Reporting\Report\Header.cs" />
+    <Compile Include="Reporting\Report\HeaderHelper.cs" />
+    <Compile Include="Reporting\Report\Image.cs" />
+    <Compile Include="Reporting\Report\Paragraph.cs" />
+    <Compile Include="Reporting\Report\PlotFigure.cs" />
+    <Compile Include="Reporting\Report\PropertyTable.cs" />
+    <Compile Include="Reporting\Report\Report.cs" />
+    <Compile Include="Reporting\Report\ReportItem.cs" />
+    <Compile Include="Reporting\Report\ReportSection.cs" />
+    <Compile Include="Reporting\Report\Table.cs" />
+    <Compile Include="Reporting\Report\ItemsTableField.cs" />
+    <Compile Include="Series\AreaSeries.cs" />
+    <Compile Include="Foundation\OxyPen.cs" />
+    <Compile Include="Foundation\LineStyleHelper.cs" />
+    <Compile Include="Foundation\DataPoint.cs" />
+    <Compile Include="Series\BarSeries\LabelPlacement.cs" />
+    <Compile Include="Series\CandleStickSeries.cs" />
+    <Compile Include="Foundation\Conrec.cs" />
+    <Compile Include="Series\ContourSeries.cs" />
+    <Compile Include="Series\BarSeries\ColumnSeries.cs" />
+    <Compile Include="Series\BarSeries\BarSeries.cs" />
+    <Compile Include="Series\BarSeries\BarSeriesBase.cs" />
+    <Compile Include="Series\BarSeries\IntervalBarItem.cs" />
+    <Compile Include="Series\BarSeries\RectangleBarItem.cs" />
+    <Compile Include="Series\BarSeries\RectangleBarSeries.cs" />
+    <Compile Include="Series\BarSeries\IntervalBarSeries.cs" />
+    <Compile Include="Series\BarSeries\TornadoBarItem.cs" />
+    <Compile Include="Series\BarSeries\TornadoBarSeries.cs" />
+    <Compile Include="Series\ItemsSeries.cs" />
+    <Compile Include="Series\DataPointSeries.cs" />
+    <Compile Include="Series\HighLowItem.cs" />
+    <Compile Include="Series\HighLowSeries.cs" />
+    <Compile Include="Series\ScatterPoint.cs" />
+    <Compile Include="Series\Series.cs" />
+    <Compile Include="Series\StemSeries.cs" />
+    <Compile Include="Series\StairStepSeries.cs" />
+    <Compile Include="Series\ITrackableSeries.cs" />
+    <Compile Include="Series\ScatterSeries.cs" />
+    <Compile Include="Series\TwoColorLineSeries.cs" />
+    <Compile Include="Series\XYAxisSeries.cs" />
+    <Compile Include="Series\PieSeries.cs" />
+    <Compile Include="Series\FunctionSeries.cs" />
+    <Compile Include="Series\PieSlice.cs" />
+    <Compile Include="Svg\SvgRenderContext.cs" />
+    <Compile Include="Svg\SvgWriter.cs" />
+    <Compile Include="Foundation\OxyColor.cs" />
+    <Compile Include="Foundation\OxyColors.cs" />
+    <Compile Include="Series\LineSeries.cs" />
+    <Compile Include="Foundation\LineStyle.cs" />
+    <Compile Include="Axes\LogarithmicAxis.cs" />
+    <Compile Include="Foundation\MarkerType.cs" />
+    <Compile Include="PlotModel\PlotModel.cs" />
+    <Compile Include="Properties\AssemblyInfo.cs" />
+    <Compile Include="Foundation\XmlWriterBase.cs" />
+  </ItemGroup>
+  <ItemGroup>
+    <None Include="ClassDiagrams\Series.cd" />
+    <None Include="ClassDiagrams\PlotModel.cd" />
+    <None Include="ClassDiagrams\Reporting.cd" />
+    <None Include="OxyPlot.snk" />
+  </ItemGroup>
+  <Import Project="$(MSBuildToolsPath)\Microsoft.CSharp.targets" />
+  <!-- To modify your build process, add your task inside one of the targets below and uncomment it. 
+       Other similar extension points exist, see Microsoft.Common.targets.
+  <Target Name="BeforeBuild">
+  </Target>
+  <Target Name="AfterBuild">
+  </Target>
+  -->
+</Project>
\ No newline at end of file
diff --git a/oxyplot/OxyPlot/OxyPlotMfA.csproj b/oxyplot/OxyPlot/OxyPlotMfA.csproj
new file mode 100644
index 0000000..b5321a3
--- /dev/null
+++ b/oxyplot/OxyPlot/OxyPlotMfA.csproj
@@ -0,0 +1,238 @@
+<?xml version="1.0" encoding="utf-8"?>
+<Project ToolsVersion="4.0" DefaultTargets="Build" 
xmlns="http://schemas.microsoft.com/developer/msbuild/2003";>
+  <PropertyGroup>
+    <Configuration Condition=" '$(Configuration)' == '' ">Debug</Configuration>
+    <Platform Condition=" '$(Platform)' == '' ">AnyCPU</Platform>
+    <ProjectGuid>{08A91765-2C9D-4D2B-B56D-FAE62AB204CC}</ProjectGuid>
+    
<ProjectTypeGuids>{EFBA0AD7-5A72-4C68-AF49-83D382785DCF};{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}</ProjectTypeGuids>
+    <OutputType>Library</OutputType>
+    <AppDesignerFolder>Properties</AppDesignerFolder>
+    <RootNamespace>OxyPlot</RootNamespace>
+    <AssemblyName>OxyPlotMfA</AssemblyName>
+    <FileAlignment>512</FileAlignment>
+    <GenerateSerializationAssemblies>Off</GenerateSerializationAssemblies>
+    <AndroidSupportedAbis>armeabi</AndroidSupportedAbis>
+    <AndroidStoreUncompressedFileExtensions />
+    <MandroidI18n />
+  </PropertyGroup>
+  <PropertyGroup Condition=" '$(Configuration)|$(Platform)' == 'Debug|AnyCPU' ">
+    <DebugSymbols>true</DebugSymbols>
+    <DebugType>full</DebugType>
+    <Optimize>false</Optimize>
+    <OutputPath>bin\Debug\MfA\</OutputPath>
+    <IntermediateOutputPath>obj\Debug\MfA\</IntermediateOutputPath>
+    <DefineConstants>TRACE;DEBUG;MONO</DefineConstants>
+    <ErrorReport>prompt</ErrorReport>
+    <WarningLevel>4</WarningLevel>
+  </PropertyGroup>
+  <PropertyGroup Condition=" '$(Configuration)|$(Platform)' == 'Release|AnyCPU' ">
+    <DebugType>pdbonly</DebugType>
+    <Optimize>true</Optimize>
+    <OutputPath>..\..\Output\Android</OutputPath>
+    <IntermediateOutputPath>obj\Release\MfA\</IntermediateOutputPath>
+    <DefineConstants>TRACE;MONO</DefineConstants>
+    <ErrorReport>prompt</ErrorReport>
+    <WarningLevel>4</WarningLevel>
+    <DocumentationFile>..\..\Output\Android\OxyPlot.XML</DocumentationFile>
+  </PropertyGroup>
+  <PropertyGroup>
+    <SignAssembly>true</SignAssembly>
+  </PropertyGroup>
+  <PropertyGroup>
+    <AssemblyOriginatorKeyFile>OxyPlot.snk</AssemblyOriginatorKeyFile>
+  </PropertyGroup>
+  <ItemGroup>
+    <Reference Include="mscorlib" />
+    <Reference Include="System" />
+    <Reference Include="System.Core" />
+    <Reference Include="System.Xml" />
+  </ItemGroup>
+  <ItemGroup>
+    <Compile Include="..\GlobalAssemblyInfo.cs">
+      <Link>Properties\GlobalAssemblyInfo.cs</Link>
+    </Compile>
+    <Compile Include="Annotations\Annotation.cs" />
+    <Compile Include="Annotations\AnnotationLayer.cs" />
+    <Compile Include="Annotations\ArrowAnnotation.cs" />
+    <Compile Include="Annotations\EllipseAnnotation.cs" />
+    <Compile Include="Annotations\ImageAnnotation.cs" />
+    <Compile Include="Annotations\TileMapAnnotation.cs" />
+    <Compile Include="Foundation\PlotLength.cs" />
+    <Compile Include="Foundation\PlotLengthUnit.cs" />
+    <Compile Include="Annotations\RectangleAnnotation.cs" />
+    <Compile Include="Annotations\TextAnnotation.cs" />
+    <Compile Include="Annotations\PolygonAnnotation.cs" />
+    <Compile Include="Annotations\LineAnnotation.cs" />
+    <Compile Include="Annotations\LineAnnotationType.cs" />
+    <Compile Include="Annotations\TextualAnnotation.cs" />
+    <Compile Include="Axes\AngleAxis.cs" />
+    <Compile Include="Axes\Axis.cs" />
+    <Compile Include="Axes\AxisChangedEventArgs.cs" />
+    <Compile Include="Axes\AxisChangeTypes.cs" />
+    <Compile Include="Axes\AxisLayer.cs" />
+    <Compile Include="Axes\AxisPosition.cs" />
+    <Compile Include="Axes\CategoryAxis.cs" />
+    <Compile Include="Axes\ColorAxis.cs" />
+    <Compile Include="Axes\DateTimeAxis.cs" />
+    <Compile Include="Axes\DateTimeIntervalType.cs" />
+    <Compile Include="Axes\LinearAxis.cs" />
+    <Compile Include="Axes\MagnitudeAxis.cs" />
+    <Compile Include="Axes\TickStyle.cs" />
+    <Compile Include="Axes\TimeSpanAxis.cs" />
+    <Compile Include="Foundation\CodeGenerator\CodeGenerationAttribute.cs" />
+    <Compile Include="Foundation\CodeGenerator\CodeGenerator.cs" />
+    <Compile Include="Foundation\CodeGenerator\CodeGeneratorStringExtensions.cs" />
+    <Compile Include="Foundation\CodeGenerator\ICodeGenerating.cs" />
+    <Compile Include="Foundation\ListFiller.cs" />
+    <Compile Include="Foundation\OxyPalette.cs" />
+    <Compile Include="Foundation\OxyPalettes.cs" />
+    <Compile Include="Foundation\PngEncoder.cs" />
+    <Compile Include="Foundation\ScreenVector.cs" />
+    <Compile Include="Foundation\StreamExtensions.cs" />
+    <Compile Include="Foundation\StringHelper.cs" />
+    <Compile Include="Foundation\DoubleExtensions.cs" />
+    <Compile Include="Foundation\FractionHelper.cs" />
+    <Compile Include="Foundation\ArrayHelper.cs" />
+    <Compile Include="Foundation\IDataPoint.cs" />
+    <Compile Include="Foundation\ReflectionHelper.cs" />
+    <Compile Include="Foundation\ScreenPointHelper.cs" />
+    <Compile Include="Manipulators\ZoomManipulator.cs" />
+    <Compile Include="Manipulators\ZoomStepManipulator.cs" />
+    <Compile Include="Manipulators\ResetManipulator.cs" />
+    <Compile Include="Manipulators\ManipulationEventArgs.cs" />
+    <Compile Include="Manipulators\TrackerManipulator.cs" />
+    <Compile Include="Manipulators\ZoomRectangleManipulator.cs" />
+    <Compile Include="Manipulators\ManipulatorBase.cs" />
+    <Compile Include="Manipulators\CursorType.cs" />
+    <Compile Include="Manipulators\PanManipulator.cs" />
+    <Compile Include="Manipulators\TrackerHitResult.cs" />
+    <Compile Include="LibraryDoc.cs" />
+    <Compile Include="NamespaceDoc.cs" />
+    <Compile Include="PlotModel\HitTestResult.cs" />
+    <Compile Include="Foundation\OxyImage.cs" />
+    <Compile Include="Reporting\NamespaceDoc.cs" />
+    <Compile Include="Series\BarSeries\BarItem.cs" />
+    <Compile Include="Series\BarSeries\BarItemBase.cs" />
+    <Compile Include="Series\BarSeries\BarSeriesBase{T}.cs" />
+    <Compile Include="Series\BarSeries\CategorizedItem.cs" />
+    <Compile Include="Series\BarSeries\CategorizedSeries.cs" />
+    <Compile Include="Series\BarSeries\ErrorColumnItem.cs" />
+    <Compile Include="Series\BarSeries\ColumnItem.cs" />
+    <Compile Include="Series\BarSeries\ErrorColumnSeries.cs" />
+    <Compile Include="Series\BarSeries\IStackableSeries.cs" />
+    <Compile Include="Series\BoxPlotItem.cs" />
+    <Compile Include="Series\BoxPlotSeries.cs" />
+    <Compile Include="Foundation\IDataPointProvider.cs" />
+    <Compile Include="Series\HeatMapSeries.cs" />
+    <Compile Include="Series\LineLegendPosition.cs" />
+    <Compile Include="Svg\SvgExporter.cs" />
+    <Compile Include="PlotModel\PlotModel.MouseEvents.cs" />
+    <Compile Include="PlotModel\OxyMouseButton.cs" />
+    <Compile Include="PlotModel\OxyMouseEventArgs.cs" />
+    <Compile Include="PlotModel\PlotElement.cs" />
+    <Compile Include="PlotModel\PlotModel.Legends.cs" />
+    <Compile Include="Foundation\CanonicalSplineHelper.cs" />
+    <Compile Include="Foundation\FontWeights.cs" />
+    <Compile Include="Foundation\OxyThickness.cs" />
+    <Compile Include="Foundation\ScreenPoint.cs" />
+    <Compile Include="Foundation\OxyRect.cs" />
+    <Compile Include="Foundation\OxySize.cs" />
+    <Compile Include="Foundation\SutherlandHodgmanClipping.cs" />
+    <Compile Include="Manipulators\IPlotControl.cs" />
+    <Compile Include="PlotModel\PlotModel.Rendering.cs" />
+    <Compile Include="PlotModel\SelectablePlotElement.cs" />
+    <Compile Include="PlotModel\UIPlotElement.cs" />
+    <Compile Include="Render\AxisRendererBase.cs" />
+    <Compile Include="Foundation\CohenSutherlandClipping.cs" />
+    <Compile Include="Render\AngleAxisRenderer.cs" />
+    <Compile Include="Foundation\HorizontalAlignment.cs" />
+    <Compile Include="Render\MagnitudeAxisRenderer.cs" />
+    <Compile Include="Render\MathRenderingExtensions.cs" />
+    <Compile Include="Foundation\OxyPenLineJoin.cs" />
+    <Compile Include="Render\RenderContextBase.cs" />
+    <Compile Include="Render\RenderingExtensions.cs" />
+    <Compile Include="Render\HorizontalAndVerticalAxisRenderer.cs" />
+    <Compile Include="Render\IRenderContext.cs" />
+    <Compile Include="Foundation\VerticalAlignment.cs" />
+    <Compile Include="Reporting\ReportWriters\WikiReportWriter.cs" />
+    <Compile Include="Reporting\ReportWriters\HtmlReportWriter.cs" />
+    <Compile Include="Reporting\ReportWriters\IReportWriter.cs" />
+    <Compile Include="Reporting\ReportWriters\StringExtensions.cs" />
+    <Compile Include="Reporting\ReportWriters\TextReportWriter.cs" />
+    <Compile Include="Reporting\Report\ItemsTable.cs" />
+    <Compile Include="Reporting\Report\ParagraphStyle.cs" />
+    <Compile Include="Reporting\Report\ReportStyle.cs" />
+    <Compile Include="Reporting\Report\TableOfContents.cs" />
+    <Compile Include="Reporting\Report\DrawingFigure.cs" />
+    <Compile Include="Reporting\Report\Equation.cs" />
+    <Compile Include="Reporting\Report\Figure.cs" />
+    <Compile Include="Reporting\Report\Header.cs" />
+    <Compile Include="Reporting\Report\HeaderHelper.cs" />
+    <Compile Include="Reporting\Report\Image.cs" />
+    <Compile Include="Reporting\Report\Paragraph.cs" />
+    <Compile Include="Reporting\Report\PlotFigure.cs" />
+    <Compile Include="Reporting\Report\PropertyTable.cs" />
+    <Compile Include="Reporting\Report\Report.cs" />
+    <Compile Include="Reporting\Report\ReportItem.cs" />
+    <Compile Include="Reporting\Report\ReportSection.cs" />
+    <Compile Include="Reporting\Report\Table.cs" />
+    <Compile Include="Reporting\Report\ItemsTableField.cs" />
+    <Compile Include="Series\AreaSeries.cs" />
+    <Compile Include="Foundation\OxyPen.cs" />
+    <Compile Include="Foundation\LineStyleHelper.cs" />
+    <Compile Include="Foundation\DataPoint.cs" />
+    <Compile Include="Series\BarSeries\LabelPlacement.cs" />
+    <Compile Include="Series\CandleStickSeries.cs" />
+    <Compile Include="Foundation\Conrec.cs" />
+    <Compile Include="Series\ContourSeries.cs" />
+    <Compile Include="Series\BarSeries\ColumnSeries.cs" />
+    <Compile Include="Series\BarSeries\BarSeries.cs" />
+    <Compile Include="Series\BarSeries\BarSeriesBase.cs" />
+    <Compile Include="Series\BarSeries\IntervalBarItem.cs" />
+    <Compile Include="Series\BarSeries\RectangleBarItem.cs" />
+    <Compile Include="Series\BarSeries\RectangleBarSeries.cs" />
+    <Compile Include="Series\BarSeries\IntervalBarSeries.cs" />
+    <Compile Include="Series\BarSeries\TornadoBarItem.cs" />
+    <Compile Include="Series\BarSeries\TornadoBarSeries.cs" />
+    <Compile Include="Series\ItemsSeries.cs" />
+    <Compile Include="Series\DataPointSeries.cs" />
+    <Compile Include="Series\HighLowItem.cs" />
+    <Compile Include="Series\HighLowSeries.cs" />
+    <Compile Include="Series\ScatterPoint.cs" />
+    <Compile Include="Series\Series.cs" />
+    <Compile Include="Series\StemSeries.cs" />
+    <Compile Include="Series\StairStepSeries.cs" />
+    <Compile Include="Series\ITrackableSeries.cs" />
+    <Compile Include="Series\ScatterSeries.cs" />
+    <Compile Include="Series\TwoColorLineSeries.cs" />
+    <Compile Include="Series\XYAxisSeries.cs" />
+    <Compile Include="Series\PieSeries.cs" />
+    <Compile Include="Series\FunctionSeries.cs" />
+    <Compile Include="Series\PieSlice.cs" />
+    <Compile Include="Svg\SvgRenderContext.cs" />
+    <Compile Include="Svg\SvgWriter.cs" />
+    <Compile Include="Foundation\OxyColor.cs" />
+    <Compile Include="Foundation\OxyColors.cs" />
+    <Compile Include="Series\LineSeries.cs" />
+    <Compile Include="Foundation\LineStyle.cs" />
+    <Compile Include="Axes\LogarithmicAxis.cs" />
+    <Compile Include="Foundation\MarkerType.cs" />
+    <Compile Include="PlotModel\PlotModel.cs" />
+    <Compile Include="Properties\AssemblyInfo.cs" />
+    <Compile Include="Foundation\XmlWriterBase.cs" />
+  </ItemGroup>
+  <ItemGroup>
+    <None Include="ClassDiagrams\Series.cd" />
+    <None Include="ClassDiagrams\PlotModel.cd" />
+    <None Include="ClassDiagrams\Reporting.cd" />
+    <None Include="OxyPlot.snk" />
+  </ItemGroup>
+  <Import Project="$(MSBuildExtensionsPath)\Novell\Novell.MonoDroid.CSharp.targets" />
+  <!-- To modify your build process, add your task inside one of the targets below and uncomment it. 
+       Other similar extension points exist, see Microsoft.Common.targets.
+  <Target Name="BeforeBuild">
+  </Target>
+  <Target Name="AfterBuild">
+  </Target>
+  -->
+</Project>
\ No newline at end of file
diff --git a/oxyplot/OxyPlot/OxyPlot_NET40x.csproj b/oxyplot/OxyPlot/OxyPlot_NET40x.csproj
new file mode 100644
index 0000000..e36231d
--- /dev/null
+++ b/oxyplot/OxyPlot/OxyPlot_NET40x.csproj
@@ -0,0 +1,237 @@
+<?xml version="1.0" encoding="utf-8"?>
+<Project ToolsVersion="4.0" DefaultTargets="Build" 
xmlns="http://schemas.microsoft.com/developer/msbuild/2003";>
+  <Import Project="$(MSBuildExtensionsPath)\$(MSBuildToolsVersion)\Microsoft.Common.props" 
Condition="Exists('$(MSBuildExtensionsPath)\$(MSBuildToolsVersion)\Microsoft.Common.props')" />
+  <PropertyGroup>
+    <Configuration Condition=" '$(Configuration)' == '' ">Debug</Configuration>
+    <Platform Condition=" '$(Platform)' == '' ">AnyCPU</Platform>
+    <ProjectGuid>{BCC43E58-E473-403E-A84D-63FEDC723040}</ProjectGuid>
+    <OutputType>Library</OutputType>
+    <AppDesignerFolder>Properties</AppDesignerFolder>
+    <RootNamespace>OxyPlot</RootNamespace>
+    <AssemblyName>OxyPlot</AssemblyName>
+    <TargetFrameworkVersion>v4.0</TargetFrameworkVersion>
+    <FileAlignment>512</FileAlignment>
+    <TargetFrameworkProfile>Client</TargetFrameworkProfile>
+  </PropertyGroup>
+  <PropertyGroup Condition=" '$(Configuration)|$(Platform)' == 'Debug|AnyCPU' ">
+    <DebugSymbols>true</DebugSymbols>
+    <DebugType>full</DebugType>
+    <Optimize>false</Optimize>
+    <OutputPath>bin\Debug\</OutputPath>
+    <DefineConstants>DEBUG;TRACE</DefineConstants>
+    <ErrorReport>prompt</ErrorReport>
+    <WarningLevel>4</WarningLevel>
+  </PropertyGroup>
+  <PropertyGroup Condition=" '$(Configuration)|$(Platform)' == 'Release|AnyCPU' ">
+    <DebugType>pdbonly</DebugType>
+    <Optimize>true</Optimize>
+    <OutputPath>..\..\Output\NET40x\</OutputPath>
+    <DefineConstants>TRACE</DefineConstants>
+    <ErrorReport>prompt</ErrorReport>
+    <WarningLevel>4</WarningLevel>
+    <DocumentationFile>..\..\Output\NET40x\OxyPlot.XML</DocumentationFile>
+  </PropertyGroup>
+  <PropertyGroup>
+    <SignAssembly>true</SignAssembly>
+  </PropertyGroup>
+  <PropertyGroup>
+    <AssemblyOriginatorKeyFile>OxyPlot.snk</AssemblyOriginatorKeyFile>
+  </PropertyGroup>
+  <ItemGroup>
+    <Reference Include="System" />
+    <Reference Include="System.Core" />
+    <Reference Include="System.Xml.Linq" />
+    <Reference Include="System.Data.DataSetExtensions" />
+    <Reference Include="Microsoft.CSharp" />
+    <Reference Include="System.Data" />
+    <Reference Include="System.Xml" />
+  </ItemGroup>
+  <ItemGroup>
+    <Compile Include="..\GlobalAssemblyInfo.cs">
+      <Link>Properties\GlobalAssemblyInfo.cs</Link>
+    </Compile>
+    <Compile Include="Annotations\Annotation.cs" />
+    <Compile Include="Annotations\AnnotationLayer.cs" />
+    <Compile Include="Annotations\ArrowAnnotation.cs" />
+    <Compile Include="Annotations\EllipseAnnotation.cs" />
+    <Compile Include="Annotations\ImageAnnotation.cs" />
+    <Compile Include="Annotations\TileMapAnnotation.cs" />
+    <Compile Include="Foundation\PlotLength.cs" />
+    <Compile Include="Foundation\PlotLengthUnit.cs" />
+    <Compile Include="Annotations\RectangleAnnotation.cs" />
+    <Compile Include="Annotations\TextAnnotation.cs" />
+    <Compile Include="Annotations\PolygonAnnotation.cs" />
+    <Compile Include="Annotations\LineAnnotation.cs" />
+    <Compile Include="Annotations\LineAnnotationType.cs" />
+    <Compile Include="Annotations\TextualAnnotation.cs" />
+    <Compile Include="Axes\AngleAxis.cs" />
+    <Compile Include="Axes\Axis.cs" />
+    <Compile Include="Axes\AxisChangedEventArgs.cs" />
+    <Compile Include="Axes\AxisChangeTypes.cs" />
+    <Compile Include="Axes\AxisLayer.cs" />
+    <Compile Include="Axes\AxisPosition.cs" />
+    <Compile Include="Axes\CategoryAxis.cs" />
+    <Compile Include="Axes\ColorAxis.cs" />
+    <Compile Include="Axes\DateTimeAxis.cs" />
+    <Compile Include="Axes\DateTimeIntervalType.cs" />
+    <Compile Include="Axes\LinearAxis.cs" />
+    <Compile Include="Axes\MagnitudeAxis.cs" />
+    <Compile Include="Axes\TickStyle.cs" />
+    <Compile Include="Axes\TimeSpanAxis.cs" />
+    <Compile Include="Foundation\CodeGenerator\CodeGenerationAttribute.cs" />
+    <Compile Include="Foundation\CodeGenerator\CodeGenerator.cs" />
+    <Compile Include="Foundation\CodeGenerator\CodeGeneratorStringExtensions.cs" />
+    <Compile Include="Foundation\CodeGenerator\ICodeGenerating.cs" />
+    <Compile Include="Foundation\ListFiller.cs" />
+    <Compile Include="Foundation\OxyPalette.cs" />
+    <Compile Include="Foundation\OxyPalettes.cs" />
+    <Compile Include="Foundation\PngEncoder.cs" />
+    <Compile Include="Foundation\ScreenVector.cs" />
+    <Compile Include="Foundation\StreamExtensions.cs" />
+    <Compile Include="Foundation\StringHelper.cs" />
+    <Compile Include="Foundation\DoubleExtensions.cs" />
+    <Compile Include="Foundation\FractionHelper.cs" />
+    <Compile Include="Foundation\ArrayHelper.cs" />
+    <Compile Include="Foundation\IDataPoint.cs" />
+    <Compile Include="Foundation\ReflectionHelper.cs" />
+    <Compile Include="Foundation\ScreenPointHelper.cs" />
+    <Compile Include="Manipulators\ZoomManipulator.cs" />
+    <Compile Include="Manipulators\ZoomStepManipulator.cs" />
+    <Compile Include="Manipulators\ResetManipulator.cs" />
+    <Compile Include="Manipulators\ManipulationEventArgs.cs" />
+    <Compile Include="Manipulators\TrackerManipulator.cs" />
+    <Compile Include="Manipulators\ZoomRectangleManipulator.cs" />
+    <Compile Include="Manipulators\ManipulatorBase.cs" />
+    <Compile Include="Manipulators\CursorType.cs" />
+    <Compile Include="Manipulators\PanManipulator.cs" />
+    <Compile Include="Manipulators\TrackerHitResult.cs" />
+    <Compile Include="LibraryDoc.cs" />
+    <Compile Include="NamespaceDoc.cs" />
+    <Compile Include="PlotModel\HitTestResult.cs" />
+    <Compile Include="Foundation\OxyImage.cs" />
+    <Compile Include="Reporting\NamespaceDoc.cs" />
+    <Compile Include="Series\BarSeries\BarItem.cs" />
+    <Compile Include="Series\BarSeries\BarItemBase.cs" />
+    <Compile Include="Series\BarSeries\BarSeriesBase{T}.cs" />
+    <Compile Include="Series\BarSeries\CategorizedItem.cs" />
+    <Compile Include="Series\BarSeries\CategorizedSeries.cs" />
+    <Compile Include="Series\BarSeries\ErrorColumnItem.cs" />
+    <Compile Include="Series\BarSeries\ColumnItem.cs" />
+    <Compile Include="Series\BarSeries\ErrorColumnSeries.cs" />
+    <Compile Include="Series\BarSeries\IStackableSeries.cs" />
+    <Compile Include="Series\BoxPlotItem.cs" />
+    <Compile Include="Series\BoxPlotSeries.cs" />
+    <Compile Include="Foundation\IDataPointProvider.cs" />
+    <Compile Include="Series\HeatMapSeries.cs" />
+    <Compile Include="Series\LineLegendPosition.cs" />
+    <Compile Include="Svg\SvgExporter.cs" />
+    <Compile Include="PlotModel\PlotModel.MouseEvents.cs" />
+    <Compile Include="PlotModel\OxyMouseButton.cs" />
+    <Compile Include="PlotModel\OxyMouseEventArgs.cs" />
+    <Compile Include="PlotModel\PlotElement.cs" />
+    <Compile Include="PlotModel\PlotModel.Legends.cs" />
+    <Compile Include="Foundation\CanonicalSplineHelper.cs" />
+    <Compile Include="Foundation\FontWeights.cs" />
+    <Compile Include="Foundation\OxyThickness.cs" />
+    <Compile Include="Foundation\ScreenPoint.cs" />
+    <Compile Include="Foundation\OxyRect.cs" />
+    <Compile Include="Foundation\OxySize.cs" />
+    <Compile Include="Foundation\SutherlandHodgmanClipping.cs" />
+    <Compile Include="Manipulators\IPlotControl.cs" />
+    <Compile Include="PlotModel\PlotModel.Rendering.cs" />
+    <Compile Include="PlotModel\SelectablePlotElement.cs" />
+    <Compile Include="PlotModel\UIPlotElement.cs" />
+    <Compile Include="Render\AxisRendererBase.cs" />
+    <Compile Include="Foundation\CohenSutherlandClipping.cs" />
+    <Compile Include="Render\AngleAxisRenderer.cs" />
+    <Compile Include="Foundation\HorizontalAlignment.cs" />
+    <Compile Include="Render\MagnitudeAxisRenderer.cs" />
+    <Compile Include="Render\MathRenderingExtensions.cs" />
+    <Compile Include="Foundation\OxyPenLineJoin.cs" />
+    <Compile Include="Render\RenderContextBase.cs" />
+    <Compile Include="Render\RenderingExtensions.cs" />
+    <Compile Include="Render\HorizontalAndVerticalAxisRenderer.cs" />
+    <Compile Include="Render\IRenderContext.cs" />
+    <Compile Include="Foundation\VerticalAlignment.cs" />
+    <Compile Include="Reporting\ReportWriters\WikiReportWriter.cs" />
+    <Compile Include="Reporting\ReportWriters\HtmlReportWriter.cs" />
+    <Compile Include="Reporting\ReportWriters\IReportWriter.cs" />
+    <Compile Include="Reporting\ReportWriters\StringExtensions.cs" />
+    <Compile Include="Reporting\ReportWriters\TextReportWriter.cs" />
+    <Compile Include="Reporting\Report\ItemsTable.cs" />
+    <Compile Include="Reporting\Report\ParagraphStyle.cs" />
+    <Compile Include="Reporting\Report\ReportStyle.cs" />
+    <Compile Include="Reporting\Report\TableOfContents.cs" />
+    <Compile Include="Reporting\Report\DrawingFigure.cs" />
+    <Compile Include="Reporting\Report\Equation.cs" />
+    <Compile Include="Reporting\Report\Figure.cs" />
+    <Compile Include="Reporting\Report\Header.cs" />
+    <Compile Include="Reporting\Report\HeaderHelper.cs" />
+    <Compile Include="Reporting\Report\Image.cs" />
+    <Compile Include="Reporting\Report\Paragraph.cs" />
+    <Compile Include="Reporting\Report\PlotFigure.cs" />
+    <Compile Include="Reporting\Report\PropertyTable.cs" />
+    <Compile Include="Reporting\Report\Report.cs" />
+    <Compile Include="Reporting\Report\ReportItem.cs" />
+    <Compile Include="Reporting\Report\ReportSection.cs" />
+    <Compile Include="Reporting\Report\Table.cs" />
+    <Compile Include="Reporting\Report\ItemsTableField.cs" />
+    <Compile Include="Series\AreaSeries.cs" />
+    <Compile Include="Foundation\OxyPen.cs" />
+    <Compile Include="Foundation\LineStyleHelper.cs" />
+    <Compile Include="Foundation\DataPoint.cs" />
+    <Compile Include="Series\BarSeries\LabelPlacement.cs" />
+    <Compile Include="Series\CandleStickSeries.cs" />
+    <Compile Include="Foundation\Conrec.cs" />
+    <Compile Include="Series\ContourSeries.cs" />
+    <Compile Include="Series\BarSeries\ColumnSeries.cs" />
+    <Compile Include="Series\BarSeries\BarSeries.cs" />
+    <Compile Include="Series\BarSeries\BarSeriesBase.cs" />
+    <Compile Include="Series\BarSeries\IntervalBarItem.cs" />
+    <Compile Include="Series\BarSeries\RectangleBarItem.cs" />
+    <Compile Include="Series\BarSeries\RectangleBarSeries.cs" />
+    <Compile Include="Series\BarSeries\IntervalBarSeries.cs" />
+    <Compile Include="Series\BarSeries\TornadoBarItem.cs" />
+    <Compile Include="Series\BarSeries\TornadoBarSeries.cs" />
+    <Compile Include="Series\ItemsSeries.cs" />
+    <Compile Include="Series\DataPointSeries.cs" />
+    <Compile Include="Series\HighLowItem.cs" />
+    <Compile Include="Series\HighLowSeries.cs" />
+    <Compile Include="Series\ScatterPoint.cs" />
+    <Compile Include="Series\Series.cs" />
+    <Compile Include="Series\StemSeries.cs" />
+    <Compile Include="Series\StairStepSeries.cs" />
+    <Compile Include="Series\ITrackableSeries.cs" />
+    <Compile Include="Series\ScatterSeries.cs" />
+    <Compile Include="Series\TwoColorLineSeries.cs" />
+    <Compile Include="Series\XYAxisSeries.cs" />
+    <Compile Include="Series\PieSeries.cs" />
+    <Compile Include="Series\FunctionSeries.cs" />
+    <Compile Include="Series\PieSlice.cs" />
+    <Compile Include="Svg\SvgRenderContext.cs" />
+    <Compile Include="Svg\SvgWriter.cs" />
+    <Compile Include="Foundation\OxyColor.cs" />
+    <Compile Include="Foundation\OxyColors.cs" />
+    <Compile Include="Series\LineSeries.cs" />
+    <Compile Include="Foundation\LineStyle.cs" />
+    <Compile Include="Axes\LogarithmicAxis.cs" />
+    <Compile Include="Foundation\MarkerType.cs" />
+    <Compile Include="PlotModel\PlotModel.cs" />
+    <Compile Include="Properties\AssemblyInfo.cs" />
+    <Compile Include="Foundation\XmlWriterBase.cs" />
+  </ItemGroup>
+  <ItemGroup>
+    <None Include="ClassDiagrams\Series.cd" />
+    <None Include="ClassDiagrams\PlotModel.cd" />
+    <None Include="ClassDiagrams\Reporting.cd" />
+    <None Include="OxyPlot.snk" />
+  </ItemGroup>
+  <Import Project="$(MSBuildToolsPath)\Microsoft.CSharp.targets" />
+  <!-- To modify your build process, add your task inside one of the targets below and uncomment it. 
+       Other similar extension points exist, see Microsoft.Common.targets.
+  <Target Name="BeforeBuild">
+  </Target>
+  <Target Name="AfterBuild">
+  </Target>
+  -->
+</Project>
\ No newline at end of file
diff --git a/oxyplot/OxyPlot/PlotModel/HitTestResult.cs b/oxyplot/OxyPlot/PlotModel/HitTestResult.cs
new file mode 100644
index 0000000..23cf0e0
--- /dev/null
+++ b/oxyplot/OxyPlot/PlotModel/HitTestResult.cs
@@ -0,0 +1,79 @@
+// 
--------------------------------------------------------------------------------------------------------------------
+// <copyright file="HitTestResult.cs" company="OxyPlot">
+//   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.
+// </copyright>
+// <summary>
+//   Represents a hit test result.
+// </summary>
+// 
--------------------------------------------------------------------------------------------------------------------
+namespace OxyPlot
+{
+    /// <summary>
+    /// Represents a hit test result.
+    /// </summary>
+    public class HitTestResult
+    {
+        /// <summary>
+        /// Initializes a new instance of the <see cref="HitTestResult"/> class.
+        /// </summary>
+        public HitTestResult()
+        {
+        }
+
+        /// <summary>
+        /// Initializes a new instance of the <see cref="HitTestResult"/> class.
+        /// </summary>
+        /// <param name="nhp">The nearest hit point.</param>
+        /// <param name="item">The item.</param>
+        /// <param name="index">The index.</param>
+        public HitTestResult(ScreenPoint nhp, object item = null, double index = 0)
+        {
+            this.NearestHitPoint = nhp;
+            this.Item = item;
+            this.Index = index;
+        }
+
+        /// <summary>
+        /// Gets or sets the index of the hit (if available).
+        /// </summary>
+        /// <value> The index. </value>
+        /// <remarks>
+        /// If the hit was in the middle between point 1 and 2, index = 1.5.
+        /// </remarks>
+        public double Index { get; set; }
+
+        /// <summary>
+        /// Gets or sets the item of the hit.
+        /// </summary>
+        /// <value> The item. </value>
+        public object Item { get; set; }
+
+        /// <summary>
+        /// Gets or sets the position of the nearest hit point.
+        /// </summary>
+        /// <value> The nearest hit point. </value>
+        public ScreenPoint NearestHitPoint { get; set; }
+
+    }
+}
\ No newline at end of file
diff --git a/oxyplot/OxyPlot/PlotModel/OxyMouseButton.cs b/oxyplot/OxyPlot/PlotModel/OxyMouseButton.cs
new file mode 100644
index 0000000..7143f3f
--- /dev/null
+++ b/oxyplot/OxyPlot/PlotModel/OxyMouseButton.cs
@@ -0,0 +1,67 @@
+// 
--------------------------------------------------------------------------------------------------------------------
+// <copyright file="OxyMouseButton.cs" company="OxyPlot">
+//   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.
+// </copyright>
+// <summary>
+//   The mouse buttons.
+// </summary>
+// 
--------------------------------------------------------------------------------------------------------------------
+namespace OxyPlot
+{
+    /// <summary>
+    /// Specifies constants that define which mouse button was pressed.
+    /// </summary>
+    public enum OxyMouseButton
+    {
+        /// <summary>
+        /// No mouse button.
+        /// </summary>
+        None = 0,
+
+        /// <summary>
+        /// The left mouse button.
+        /// </summary>
+        Left = 1,
+
+        /// <summary>
+        /// The middle mouse button.
+        /// </summary>
+        Middle = 2,
+
+        /// <summary>
+        /// The right mouse button.
+        /// </summary>
+        Right = 3,
+
+        /// <summary>
+        /// The first extended mouse button.
+        /// </summary>
+        XButton1 = 4,
+
+        /// <summary>
+        /// The second extended mouse button.
+        /// </summary>
+        XButton2 = 5,
+    }
+}
\ No newline at end of file
diff --git a/oxyplot/OxyPlot/PlotModel/OxyMouseEventArgs.cs b/oxyplot/OxyPlot/PlotModel/OxyMouseEventArgs.cs
new file mode 100644
index 0000000..87b6ba8
--- /dev/null
+++ b/oxyplot/OxyPlot/PlotModel/OxyMouseEventArgs.cs
@@ -0,0 +1,87 @@
+// 
--------------------------------------------------------------------------------------------------------------------
+// <copyright file="OxyMouseEventArgs.cs" company="OxyPlot">
+//   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.
+// </copyright>
+// <summary>
+//   Represents event arguments for 3D mouse events events.
+// </summary>
+// 
--------------------------------------------------------------------------------------------------------------------
+namespace OxyPlot
+{
+    using System;
+
+    /// <summary>
+    /// Provides data for the mouse events.
+    /// </summary>
+    public class OxyMouseEventArgs : EventArgs
+    {
+        /// <summary>
+        /// Gets or sets the mouse button that has changed.
+        /// </summary>
+        public OxyMouseButton ChangedButton { get; set; }
+
+        /// <summary>
+        /// Gets or sets the click count.
+        /// </summary>
+        /// <value> The click count. </value>
+        public int ClickCount { get; set; }
+
+        /// <summary>
+        /// Gets or sets a value indicating whether Handled.
+        /// </summary>
+        public bool Handled { get; set; }
+
+        /// <summary>
+        /// Gets or sets a value indicating whether the alt key was pressed when the event was raised.
+        /// </summary>
+        public bool IsAltDown { get; set; }
+
+        /// <summary>
+        /// Gets or sets a value indicating whether the control key was pressed when the event was raised.
+        /// </summary>
+        public bool IsControlDown { get; set; }
+
+        /// <summary>
+        /// Gets or sets a value indicating whether the shift key was pressed when the event was raised.
+        /// </summary>
+        public bool IsShiftDown { get; set; }
+
+        /// <summary>
+        /// Gets or sets the hit test result.
+        /// </summary>
+        public HitTestResult HitTestResult { get; set; }
+
+        /// <summary>
+        /// Gets or sets the plot control.
+        /// </summary>
+        /// <value> The plot control. </value>
+        public IPlotControl PlotControl { get; set; }
+
+        /// <summary>
+        /// Gets or sets the position.
+        /// </summary>
+        public ScreenPoint Position { get; set; }
+
+    }
+}
\ No newline at end of file
diff --git a/oxyplot/OxyPlot/PlotModel/PlotElement.cs b/oxyplot/OxyPlot/PlotModel/PlotElement.cs
new file mode 100644
index 0000000..694cff2
--- /dev/null
+++ b/oxyplot/OxyPlot/PlotModel/PlotElement.cs
@@ -0,0 +1,142 @@
+// 
--------------------------------------------------------------------------------------------------------------------
+// <copyright file="PlotElement.cs" company="OxyPlot">
+//   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.
+// </copyright>
+// <summary>
+//   Abstract base class for all plottable elements (Axes, Annotations, Series).
+// </summary>
+// 
--------------------------------------------------------------------------------------------------------------------
+namespace OxyPlot
+{
+    using System;
+
+    /// <summary>
+    /// Provides an abstract base class for elements contained in a <see cref="PlotModel"/>.
+    /// </summary>
+    public abstract class PlotElement
+    {
+        /// <summary>
+        /// Initializes a new instance of the <see cref="PlotElement"/> class.
+        /// </summary>
+        protected PlotElement()
+        {
+            this.Font = null;
+            this.FontSize = double.NaN;
+            this.FontWeight = FontWeights.Normal;
+        }
+
+        /// <summary>
+        /// Gets or sets the font.
+        /// </summary>
+        /// <value> The font. </value>
+        /// <remarks>
+        /// If the value is null, the parent PlotModel's DefaultFont will be used.
+        /// </remarks>
+        public string Font { get; set; }
+
+        /// <summary>
+        /// Gets or sets the size of the font.
+        /// </summary>
+        /// <value> The size of the font. </value>
+        /// <remarks>
+        /// If the value is NaN, the parent PlotModel's DefaultFontSize will be used.
+        /// </remarks>
+        public double FontSize { get; set; }
+
+        /// <summary>
+        /// Gets or sets the font weight.
+        /// </summary>
+        /// <value> The font weight. </value>
+        public double FontWeight { get; set; }
+
+        /// <summary>
+        /// Gets the parent plot model.
+        /// </summary>
+        public PlotModel PlotModel { get; internal set; }
+
+        /// <summary>
+        /// Gets or sets an arbitrary object value that can be used to store custom information about this 
plot element.
+        /// </summary>
+        /// <value> The intended value. This property has no default value. </value>
+        /// <remarks>
+        /// 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.
+        /// </remarks>
+        public object Tag { get; set; }
+
+        /// <summary>
+        /// Gets or sets the color of the text.
+        /// </summary>
+        /// <value> The color of the text. </value>
+        /// <remarks>
+        /// If the value is null, the TextColor of the parent PlotModel will be used.
+        /// </remarks>
+        public OxyColor TextColor { get; set; }
+
+        /// <summary>
+        /// Gets the actual font.
+        /// </summary>
+        protected internal string ActualFont
+        {
+            get
+            {
+                return this.Font ?? this.PlotModel.DefaultFont;
+            }
+        }
+
+        /// <summary>
+        /// Gets the actual size of the font.
+        /// </summary>
+        /// <value> The actual size of the font. </value>
+        protected internal double ActualFontSize
+        {
+            get
+            {
+                return !double.IsNaN(this.FontSize) ? this.FontSize : this.PlotModel.DefaultFontSize;
+            }
+        }
+
+        /// <summary>
+        /// Gets the actual font weight.
+        /// </summary>
+        protected internal double ActualFontWeight
+        {
+            get
+            {
+                return this.FontWeight;
+            }
+        }
+
+        /// <summary>
+        /// Gets the actual color of the text.
+        /// </summary>
+        /// <value> The actual color of the text. </value>
+        protected internal OxyColor ActualTextColor
+        {
+            get
+            {
+                return this.TextColor ?? this.PlotModel.TextColor;
+            }
+        }
+    }
+}
\ No newline at end of file
diff --git a/oxyplot/OxyPlot/PlotModel/PlotModel.Legends.cs b/oxyplot/OxyPlot/PlotModel/PlotModel.Legends.cs
new file mode 100644
index 0000000..58c1667
--- /dev/null
+++ b/oxyplot/OxyPlot/PlotModel/PlotModel.Legends.cs
@@ -0,0 +1,507 @@
+// 
--------------------------------------------------------------------------------------------------------------------
+// <copyright file="PlotModel.Legends.cs" company="OxyPlot">
+//   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.
+// </copyright>
+// <summary>
+//   Partial PlotModel class - this file contains methods related to the series legends.
+// </summary>
+// 
--------------------------------------------------------------------------------------------------------------------
+namespace OxyPlot
+{
+    using System;
+    using System.Collections.Generic;
+    using System.Linq;
+
+    using OxyPlot.Series;
+
+    public partial class PlotModel
+    {
+        /// <summary>
+        /// Makes the LegendOrientation property safe.
+        /// </summary>
+        /// <remarks>
+        /// If Legend is positioned left or right, force it to vertical orientation
+        /// </remarks>
+        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;
+            }
+        }
+
+        /// <summary>
+        /// Gets the rectangle of the legend box.
+        /// </summary>
+        /// <param name="legendSize">Size of the legend box.</param>
+        /// <returns>A rectangle.</returns>
+        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);
+        }
+
+        /// <summary>
+        /// Renders the legend for the specified series.
+        /// </summary>
+        /// <param name="rc">
+        /// The render context.
+        /// </param>
+        /// <param name="s">
+        /// The series.
+        /// </param>
+        /// <param name="rect">
+        /// The position and size of the legend.
+        /// </param>
+        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);
+        }
+
+        /// <summary>
+        /// Measures the legends.
+        /// </summary>
+        /// <param name="rc">
+        /// The render context.
+        /// </param>
+        /// <param name="availableSize">
+        /// The available size for the legend box.
+        /// </param>
+        /// <returns>
+        /// The size of the legend box.
+        /// </returns>
+        private OxySize MeasureLegends(IRenderContext rc, OxySize availableSize)
+        {
+            return this.RenderOrMeasureLegends(rc, new OxyRect(0, 0, availableSize.Width, 
availableSize.Height), true);
+        }
+
+        /// <summary>
+        /// Renders or measures the legends.
+        /// </summary>
+        /// <param name="rc">
+        /// The render context.
+        /// </param>
+        /// <param name="rect">
+        /// The rectangle.
+        /// </param>
+        private void RenderLegends(IRenderContext rc, OxyRect rect)
+        {
+            this.RenderOrMeasureLegends(rc, rect);
+        }
+
+        /// <summary>
+        /// Renders or measures the legends.
+        /// </summary>
+        /// <param name="rc">
+        /// The render context.
+        /// </param>
+        /// <param name="rect">
+        /// Provides the available size if measuring, otherwise it provides the position and size of the 
legend.
+        /// </param>
+        /// <param name="measureOnly">
+        /// Specify if the size of the legend box should be measured only (not rendered).
+        /// </param>
+        /// <returns>
+        /// The size of the legend box.
+        /// </returns>
+        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<Series.Series, OxyRect>();
+            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 --git a/oxyplot/OxyPlot/PlotModel/PlotModel.MouseEvents.cs 
b/oxyplot/OxyPlot/PlotModel/PlotModel.MouseEvents.cs
new file mode 100644
index 0000000..2442abc
--- /dev/null
+++ b/oxyplot/OxyPlot/PlotModel/PlotModel.MouseEvents.cs
@@ -0,0 +1,202 @@
+// 
--------------------------------------------------------------------------------------------------------------------
+// <copyright file="PlotModel.MouseEvents.cs" company="OxyPlot">
+//   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.
+// </copyright>
+// <summary>
+//   Partial PlotModel class - this file contains mouse events and handlers.
+// </summary>
+// 
--------------------------------------------------------------------------------------------------------------------
+namespace OxyPlot
+{
+    using System;
+    using System.Linq;
+
+    public partial class PlotModel
+    {
+        /// <summary>
+        /// The mouse hit tolerance.
+        /// </summary>
+        private const double MouseHitTolerance = 10;
+
+        /// <summary>
+        /// The current mouse events element.
+        /// </summary>
+        private UIPlotElement currentMouseEventElement;
+
+        /// <summary>
+        /// Occurs when a mouse button is pressed down on the model.
+        /// </summary>
+        public event EventHandler<OxyMouseEventArgs> MouseDown;
+
+        /// <summary>
+        /// Occurs when the mouse is moved on the plot element (only occurs after MouseDown).
+        /// </summary>
+        public event EventHandler<OxyMouseEventArgs> MouseMove;
+
+        /// <summary>
+        /// Occurs when the mouse button is released on the plot element.
+        /// </summary>
+        public event EventHandler<OxyMouseEventArgs> MouseUp;
+
+        /// <summary>
+        /// Handles the mouse down event.
+        /// </summary>
+        /// <param name="sender">
+        /// The sender.
+        /// </param>
+        /// <param name="e">
+        /// The <see cref="OxyPlot.OxyMouseEventArgs"/> instance containing the event data.
+        /// </param>
+        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);
+            }
+        }
+
+        /// <summary>
+        /// Handles the mouse move event.
+        /// </summary>
+        /// <param name="sender">
+        /// The sender.
+        /// </param>
+        /// <param name="e">
+        /// The <see cref="OxyPlot.OxyMouseEventArgs"/> instance containing the event data.
+        /// </param>
+        public void HandleMouseMove(object sender, OxyMouseEventArgs e)
+        {
+            if (this.currentMouseEventElement != null)
+            {
+                this.currentMouseEventElement.OnMouseMove(sender, e);
+            }
+
+            if (!e.Handled)
+            {
+                this.OnMouseMove(sender, e);
+            }
+        }
+
+        /// <summary>
+        /// Handles the mouse up event.
+        /// </summary>
+        /// <param name="sender">
+        /// The sender.
+        /// </param>
+        /// <param name="e">
+        /// The <see cref="OxyPlot.OxyMouseEventArgs"/> instance containing the event data.
+        /// </param>
+        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);
+            }
+        }
+
+        /// <summary>
+        /// Raises the <see cref="MouseDown"/> event.
+        /// </summary>
+        /// <param name="sender">
+        /// The sender.
+        /// </param>
+        /// <param name="e">
+        /// The <see cref="OxyMouseEventArgs"/> instance containing the event data.
+        /// </param>
+        protected virtual void OnMouseDown(object sender, OxyMouseEventArgs e)
+        {
+            if (this.MouseDown != null && !e.Handled)
+            {
+                this.MouseDown(sender, e);
+            }
+        }
+
+        /// <summary>
+        /// Raises the <see cref="MouseMove"/> event.
+        /// </summary>
+        /// <param name="sender">
+        /// The sender.
+        /// </param>
+        /// <param name="e">
+        /// The <see cref="OxyMouseEventArgs"/> instance containing the event data.
+        /// </param>
+        protected virtual void OnMouseMove(object sender, OxyMouseEventArgs e)
+        {
+            if (this.MouseMove != null)
+            {
+                this.MouseMove(sender, e);
+            }
+        }
+
+        /// <summary>
+        /// Raises the <see cref="MouseUp"/> event.
+        /// </summary>
+        /// <param name="sender">
+        /// The sender.
+        /// </param>
+        /// <param name="e">
+        /// The <see cref="OxyMouseEventArgs"/> instance containing the event data.
+        /// </param>
+        protected virtual void OnMouseUp(object sender, OxyMouseEventArgs e)
+        {
+            if (this.MouseUp != null)
+            {
+                this.MouseUp(sender, e);
+            }
+        }
+
+    }
+}
\ No newline at end of file
diff --git a/oxyplot/OxyPlot/PlotModel/PlotModel.Rendering.cs 
b/oxyplot/OxyPlot/PlotModel/PlotModel.Rendering.cs
new file mode 100644
index 0000000..2ea205e
--- /dev/null
+++ b/oxyplot/OxyPlot/PlotModel/PlotModel.Rendering.cs
@@ -0,0 +1,481 @@
+// 
--------------------------------------------------------------------------------------------------------------------
+// <copyright file="PlotModel.Rendering.cs" company="OxyPlot">
+//   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.
+// </copyright>
+// <summary>
+//   Partial PlotModel class - this file contains rendering methods.
+// </summary>
+// 
--------------------------------------------------------------------------------------------------------------------
+namespace OxyPlot
+{
+    using System;
+    using System.Collections.Generic;
+    using System.Linq;
+
+    using OxyPlot.Annotations;
+    using OxyPlot.Axes;
+    using OxyPlot.Series;
+
+    public partial class PlotModel
+    {
+        /// <summary>
+        /// Renders the plot with the specified rendering context.
+        /// </summary>
+        /// <param name="rc">The rendering context.</param>
+        /// <param name="width">The width.</param>
+        /// <param name="height">The height.</param>
+        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);
+                }
+            }
+        }
+
+        /// <summary>
+        /// Calculates the maximum size of the specified axes.
+        /// </summary>
+        /// <param name="rc">
+        /// The render context.
+        /// </param>
+        /// <param name="axesOfPositionTier">
+        /// The axes of position tier.
+        /// </param>
+        /// <returns>
+        /// The maximum size.
+        /// </returns>
+        private static double MaxSizeOfPositionTier(IRenderContext rc, IEnumerable<Axis> 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;
+        }
+
+        /// <summary>
+        /// Adjust the plot margins.
+        /// </summary>
+        /// <param name="rc">
+        /// The render context.
+        /// </param>
+        /// <returns>
+        /// The adjust plot margins.
+        /// </returns>
+        private bool AdjustPlotMargins(IRenderContext rc)
+        {
+            bool isAdjusted = false;
+            var newPlotMargins = new Dictionary<AxisPosition, double>
+                {
+                    { 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;
+        }
+
+        /// <summary>
+        /// Measures the size of the title and subtitle.
+        /// </summary>
+        /// <param name="rc">
+        /// The rendering context.
+        /// </param>
+        /// <returns>
+        /// Size of the titles.
+        /// </returns>
+        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);
+        }
+
+        /// <summary>
+        /// Renders the annotations.
+        /// </summary>
+        /// <param name="rc">
+        /// The render context.
+        /// </param>
+        /// <param name="layer">
+        /// The layer.
+        /// </param>
+        private void RenderAnnotations(IRenderContext rc, AnnotationLayer layer)
+        {
+            foreach (var a in this.Annotations.Where(a => a.Layer == layer))
+            {
+                a.Render(rc, this);
+            }
+        }
+
+        /// <summary>
+        /// Renders the axes.
+        /// </summary>
+        /// <param name="rc">
+        /// The render context.
+        /// </param>
+        /// <param name="layer">
+        /// The layer.
+        /// </param>
+        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);
+                    }
+                }
+            }
+        }
+
+        /// <summary>
+        /// Renders the series backgrounds.
+        /// </summary>
+        /// <param name="rc">
+        /// The render context.
+        /// </param>
+        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);
+            }
+        }
+
+        /// <summary>
+        /// Renders the border around the plot area.
+        /// </summary>
+        /// <remarks>
+        /// The border will only by rendered if there are axes in the plot.
+        /// </remarks>
+        /// <param name="rc">
+        /// The render context.
+        /// </param>
+        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);
+            }
+        }
+
+        /// <summary>
+        /// Renders the series.
+        /// </summary>
+        /// <param name="rc">
+        /// The render context.
+        /// </param>
+        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);
+            }
+        }
+
+        /// <summary>
+        /// Renders the title and subtitle.
+        /// </summary>
+        /// <param name="rc">
+        /// The render context.
+        /// </param>
+        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);
+            }
+        }
+
+        /// <summary>
+        /// Calculates the plot area (subtract padding, title size and outside legends)
+        /// </summary>
+        /// <param name="rc">
+        /// The rendering context.
+        /// </param>
+        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 --git a/oxyplot/OxyPlot/PlotModel/PlotModel.cs b/oxyplot/OxyPlot/PlotModel/PlotModel.cs
new file mode 100644
index 0000000..08effd7
--- /dev/null
+++ b/oxyplot/OxyPlot/PlotModel/PlotModel.cs
@@ -0,0 +1,1485 @@
+// 
--------------------------------------------------------------------------------------------------------------------
+// <copyright file="PlotModel.cs" company="OxyPlot">
+//   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.
+// </copyright>
+// <summary>
+//   Plot coordinate system type
+// </summary>
+// 
--------------------------------------------------------------------------------------------------------------------
+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;
+
+    /// <summary>
+    /// Specifies the coordinate system type.
+    /// </summary>
+    public enum PlotType
+    {
+        /// <summary>
+        /// XY coordinate system - two perpendicular axes
+        /// </summary>
+        XY,
+
+        /// <summary>
+        /// Cartesian coordinate system - perpendicular axes with the same scaling.
+        /// </summary>
+        /// <remarks>
+        /// See http://en.wikipedia.org/wiki/Cartesian_coordinate_system
+        /// </remarks>
+        Cartesian,
+
+        /// <summary>
+        /// Polar coordinate system - with radial and angular axes 
+        /// </summary>
+        /// <remarks>
+        /// See http://en.wikipedia.org/wiki/Polar_coordinate_system
+        /// </remarks>
+        Polar
+    }
+
+    /// <summary>
+    /// Specifies the placement of the legend box.
+    /// </summary>
+    public enum LegendPlacement
+    {
+        /// <summary>
+        /// Place the legends inside the plot area.
+        /// </summary>
+        Inside,
+
+        /// <summary>
+        /// Place the legends outside the plot area.
+        /// </summary>
+        Outside
+    }
+
+    /// <summary>
+    /// Specifies the position of the legend box.
+    /// </summary>
+    public enum LegendPosition
+    {
+        /// <summary>
+        /// Place the legend box in the top-left corner.
+        /// </summary>
+        TopLeft,
+
+        /// <summary>
+        /// Place the legend box centered at the top.
+        /// </summary>
+        TopCenter,
+
+        /// <summary>
+        ///  Place the legend box in the top-right corner.
+        /// </summary>
+        TopRight,
+
+        /// <summary>
+        ///  Place the legend box in the bottom-left corner.
+        /// </summary>
+        BottomLeft,
+
+        /// <summary>
+        /// Place the legend box centered at the bottom.
+        /// </summary>
+        BottomCenter,
+
+        /// <summary>
+        ///  Place the legend box in the bottom-right corner.
+        /// </summary>
+        BottomRight,
+
+        /// <summary>
+        /// Place the legend box in the left-top corner.
+        /// </summary>
+        LeftTop,
+
+        /// <summary>
+        /// Place the legend box centered at the left.
+        /// </summary>
+        LeftMiddle,
+
+        /// <summary>
+        /// Place the legend box in the left-bottom corner.
+        /// </summary>
+        LeftBottom,
+
+        /// <summary>
+        /// Place the legend box in the right-top corner.
+        /// </summary>
+        RightTop,
+
+        /// <summary>
+        /// Place the legend box centered at the right.
+        /// </summary>
+        RightMiddle,
+
+        /// <summary>
+        /// Place the legend box in the right-bottom corner.
+        /// </summary>
+        RightBottom
+    }
+
+    /// <summary>
+    /// Specifies the orientation of the items in the legend box.
+    /// </summary>
+    public enum LegendOrientation
+    {
+        /// <summary>
+        /// Orient the items horizontally.
+        /// </summary>
+        Horizontal,
+
+        /// <summary>
+        /// Orient the items vertically.
+        /// </summary>
+        Vertical
+    }
+
+    /// <summary>
+    /// Specifies the item order of the legends.
+    /// </summary>
+    public enum LegendItemOrder
+    {
+        /// <summary>
+        /// Render the items in the normal order.
+        /// </summary>
+        Normal,
+
+        /// <summary>
+        /// Render the items in the reverse order.
+        /// </summary>
+        Reverse
+    }
+
+    /// <summary>
+    /// Specifies the placement of the legend symbols.
+    /// </summary>
+    public enum LegendSymbolPlacement
+    {
+        /// <summary>
+        /// Render symbols to the left of the labels.
+        /// </summary>
+        Left,
+
+        /// <summary>
+        /// Render symbols to the right of the labels.
+        /// </summary>
+        Right
+    }
+
+    /// <summary>
+    /// Represents a plot (including axes, series and annotations).
+    /// </summary>
+    public partial class PlotModel
+    {
+        /// <summary>
+        /// The default selection color.
+        /// </summary>
+        internal static readonly OxyColor DefaultSelectionColor = OxyColors.Yellow;
+
+        /// <summary>
+        /// The default font.
+        /// </summary>
+        private const string PrivateDefaultFont = "Segoe UI";
+
+        /// <summary>
+        /// The current color index.
+        /// </summary>
+        private int currentColorIndex;
+
+        /// <summary>
+        /// Initializes a new instance of the <see cref="PlotModel" /> class.
+        /// </summary>
+        public PlotModel()
+        {
+            this.Axes = new Collection<Axis>();
+            this.Series = new Collection<OxyPlot.Series.Series>();
+            this.Annotations = new Collection<Annotation>();
+
+            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>
+            {
+                    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;
+        }
+
+        /// <summary>
+        /// Initializes a new instance of the <see cref="PlotModel"/> class.
+        /// </summary>
+        /// <param name="title">
+        /// The title.
+        /// </param>
+        /// <param name="subtitle">
+        /// The subtitle.
+        /// </param>
+        public PlotModel(string title, string subtitle = null)
+            : this()
+        {
+            this.Title = title;
+            this.Subtitle = subtitle;
+        }
+
+        /// <summary>
+        /// The synchronization root object.
+        /// </summary>
+        private object syncRoot = new object();
+
+        /// <summary>
+        /// Gets an object that can be used to synchronize access to the PlotModel.
+        /// </summary>
+        /// <value>The sync root.</value>
+        public object SyncRoot { get { return this.syncRoot; } }
+
+        /// <summary>
+        /// Occurs when the plot has been updated.
+        /// </summary>
+        public event EventHandler Updated;
+
+        /// <summary>
+        /// Occurs when the plot is about to be updated.
+        /// </summary>
+        public event EventHandler Updating;
+
+        /// <summary>
+        /// Gets or sets the default font.
+        /// </summary>
+        /// <value> The default font. </value>
+        /// <remarks>
+        /// This font is used for text on axes, series, legends and plot titles unless other fonts are 
specified.
+        /// </remarks>
+        public string DefaultFont { get; set; }
+
+        /// <summary>
+        /// Gets or sets the default size of the fonts.
+        /// </summary>
+        /// <value>
+        /// The default size of the font.
+        /// </value>
+        public double DefaultFontSize { get; set; }
+
+        /// <summary>
+        /// Gets the actual culture.
+        /// </summary>
+        public CultureInfo ActualCulture
+        {
+            get
+            {
+                return this.Culture ?? CultureInfo.CurrentCulture;
+            }
+        }
+
+        /// <summary>
+        /// Gets the actual plot margins.
+        /// </summary>
+        /// <value> The actual plot margins. </value>
+        public OxyThickness ActualPlotMargins { get; private set; }
+
+        /// <summary>
+        /// Gets the plot control that renders this plot.
+        /// </summary>
+        /// <remarks>
+        /// Only one PlotControl can render the plot at the same time.
+        /// </remarks>
+        /// <value>The plot control.</value>
+        public IPlotControl PlotControl { get; private set; }
+
+        /// <summary>
+        /// Gets or sets the annotations.
+        /// </summary>
+        /// <value> The annotations. </value>
+        public Collection<Annotation> Annotations { get; set; }
+
+        /// <summary>
+        /// Gets or sets a value indicating whether to auto adjust plot margins.
+        /// </summary>
+        public bool AutoAdjustPlotMargins { get; set; }
+
+        /// <summary>
+        /// Gets or sets the axes.
+        /// </summary>
+        /// <value> The axes. </value>
+        public Collection<Axis> Axes { get; set; }
+
+        /// <summary>
+        /// Gets or sets the color of the background of the plot.
+        /// </summary>
+        public OxyColor Background { get; set; }
+
+        /// <summary>
+        /// Gets or sets the culture.
+        /// </summary>
+        /// <value> The culture. </value>
+        public CultureInfo Culture { get; set; }
+
+        /// <summary>
+        /// Gets or sets the default colors.
+        /// </summary>
+        /// <value> The default colors. </value>
+        public IList<OxyColor> DefaultColors { get; set; }
+
+        /// <summary>
+        /// Gets or sets a value indicating whether the legend is visible. The titles of the series must be 
set to use the legend.
+        /// </summary>
+        public bool IsLegendVisible { get; set; }
+
+        /// <summary>
+        /// Gets the legend area.
+        /// </summary>
+        /// <value> The legend area. </value>
+        public OxyRect LegendArea { get; private set; }
+
+        /// <summary>
+        /// Gets or sets the background color of the legend. Use null for no background.
+        /// </summary>
+        /// <value> The legend background. </value>
+        public OxyColor LegendBackground { get; set; }
+
+        /// <summary>
+        /// Gets or sets the border color of the legend.
+        /// </summary>
+        /// <value> The legend border. </value>
+        public OxyColor LegendBorder { get; set; }
+
+        /// <summary>
+        /// Gets or sets the thickness of the legend border. Use 0 for no border.
+        /// </summary>
+        /// <value> The legend border thickness. </value>
+        public double LegendBorderThickness { get; set; }
+
+        /// <summary>
+        /// Gets or sets the legend column spacing.
+        /// </summary>
+        /// <value> The legend column spacing. </value>
+        public double LegendColumnSpacing { get; set; }
+
+        /// <summary>
+        /// Gets or sets the legend font.
+        /// </summary>
+        /// <value> The legend font. </value>
+        public string LegendFont { get; set; }
+
+        /// <summary>
+        /// Gets or sets the size of the legend font.
+        /// </summary>
+        /// <value> The size of the legend font. </value>
+        public double LegendFontSize { get; set; }
+
+        /// <summary>
+        /// Gets or sets the color of the legend text.
+        /// </summary>
+        /// <value>
+        /// The color of the legend text.
+        /// </value>
+        /// <remarks>
+        /// If this value is null, the TextColor will be used.
+        /// </remarks>
+        public OxyColor LegendTextColor { get; set; }
+
+        /// <summary>
+        /// Gets or sets the legend font weight.
+        /// </summary>
+        /// <value> The legend font weight. </value>
+        public double LegendFontWeight { get; set; }
+
+        /// <summary>
+        /// Gets or sets the legend item alignment.
+        /// </summary>
+        /// <value> The legend item alignment. </value>
+        public HorizontalAlignment LegendItemAlignment { get; set; }
+
+        /// <summary>
+        /// Gets or sets the legend item order.
+        /// </summary>
+        /// <value> The legend item order. </value>
+        public LegendItemOrder LegendItemOrder { get; set; }
+
+        /// <summary>
+        /// Gets or sets the legend spacing.
+        /// </summary>
+        /// <value> The legend spacing. </value>
+        public double LegendItemSpacing { get; set; }
+
+        /// <summary>
+        /// Gets or sets the legend margin.
+        /// </summary>
+        /// <value> The legend margin. </value>
+        public double LegendMargin { get; set; }
+
+        /// <summary>
+        /// Gets or sets the max width of the legend.
+        /// </summary>
+        /// <value>The max width of the legend.</value>
+        public double LegendMaxWidth { get; set; }
+
+        /// <summary>
+        /// Gets or sets the legend orientation.
+        /// </summary>
+        /// <value> The legend orientation. </value>
+        public LegendOrientation LegendOrientation { get; set; }
+
+        /// <summary>
+        /// Gets or sets the legend padding.
+        /// </summary>
+        /// <value> The legend padding. </value>
+        public double LegendPadding { get; set; }
+
+        /// <summary>
+        /// Gets or sets the legend placement.
+        /// </summary>
+        /// <value> The legend placement. </value>
+        public LegendPlacement LegendPlacement { get; set; }
+
+        /// <summary>
+        /// Gets or sets the legend position.
+        /// </summary>
+        /// <value> The legend position. </value>
+        public LegendPosition LegendPosition { get; set; }
+
+        /// <summary>
+        /// Gets or sets the length of the legend symbols (the default value is 16).
+        /// </summary>
+        public double LegendSymbolLength { get; set; }
+
+        /// <summary>
+        /// Gets or sets the legend symbol margins (distance between the symbol and the text).
+        /// </summary>
+        /// <value> The legend symbol margin. </value>
+        public double LegendSymbolMargin { get; set; }
+
+        /// <summary>
+        /// Gets or sets the legend symbol placement.
+        /// </summary>
+        /// <value> The legend symbol placement. </value>
+        public LegendSymbolPlacement LegendSymbolPlacement { get; set; }
+
+        /// <summary>
+        /// Gets or sets the legend title.
+        /// </summary>
+        /// <value> The legend title. </value>
+        public string LegendTitle { get; set; }
+
+        /// <summary>
+        /// Gets or sets the color of the legend title.
+        /// </summary>
+        /// <value>
+        /// The color of the legend title.
+        /// </value>
+        /// <remarks>
+        /// If this value is null, the TextColor will be used.
+        /// </remarks>
+        public OxyColor LegendTitleColor { get; set; }
+
+        /// <summary>
+        /// Gets or sets the legend title font.
+        /// </summary>
+        /// <value> The legend title font. </value>
+        public string LegendTitleFont { get; set; }
+
+        /// <summary>
+        /// Gets or sets the size of the legend title font.
+        /// </summary>
+        /// <value> The size of the legend title font. </value>
+        public double LegendTitleFontSize { get; set; }
+
+        /// <summary>
+        /// Gets or sets the legend title font weight.
+        /// </summary>
+        /// <value> The legend title font weight. </value>
+        public double LegendTitleFontWeight { get; set; }
+
+        /// <summary>
+        /// Gets or sets the padding around the plot.
+        /// </summary>
+        /// <value> The padding. </value>
+        public OxyThickness Padding { get; set; }
+
+        /// <summary>
+        /// Gets the total width of the plot (in device units).
+        /// </summary>
+        public double Width { get; private set; }
+
+        /// <summary>
+        /// Gets the total height of the plot (in device units).
+        /// </summary>
+        public double Height { get; private set; }
+
+        /// <summary>
+        /// Gets the area including both the plot and the axes. Outside legends are rendered outside this 
rectangle.
+        /// </summary>
+        /// <value> The plot and axis area. </value>
+        public OxyRect PlotAndAxisArea { get; private set; }
+
+        /// <summary>
+        /// Gets the plot area. This area is used to draw the series (not including axes or legends).
+        /// </summary>
+        /// <value> The plot area. </value>
+        public OxyRect PlotArea { get; private set; }
+
+        /// <summary>
+        /// Gets or sets the distance between two neighbourhood tiers of the same AxisPosition.
+        /// </summary>
+        public double AxisTierDistance { get; set; }
+
+        /// <summary>
+        /// Gets or sets the color of the background of the plot area.
+        /// </summary>
+        public OxyColor PlotAreaBackground { get; set; }
+
+        /// <summary>
+        /// Gets or sets the color of the border around the plot area.
+        /// </summary>
+        /// <value> The color of the box. </value>
+        public OxyColor PlotAreaBorderColor { get; set; }
+
+        /// <summary>
+        /// Gets or sets the thickness of the border around the plot area.
+        /// </summary>
+        /// <value> The box thickness. </value>
+        public double PlotAreaBorderThickness { get; set; }
+
+        /// <summary>
+        /// 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.
+        /// </summary>
+        public OxyThickness PlotMargins { get; set; }
+
+        /// <summary>
+        /// Gets or sets the type of the coordinate system.
+        /// </summary>
+        /// <value> The type of the plot. </value>
+        public PlotType PlotType { get; set; }
+
+        /// <summary>
+        /// Gets or sets the color of the selection.
+        /// </summary>
+        /// <value>
+        /// The color of the selection.
+        /// </value>
+        public OxyColor SelectionColor { get; set; }
+
+        /// <summary>
+        /// Gets or sets the series.
+        /// </summary>
+        /// <value> The series. </value>
+        public Collection<Series.Series> Series { get; set; }
+
+        /// <summary>
+        /// Gets or sets the subtitle.
+        /// </summary>
+        /// <value> The subtitle. </value>
+        public string Subtitle { get; set; }
+
+        /// <summary>
+        /// Gets or sets the subtitle font. If this property is null, the Title font will be used.
+        /// </summary>
+        /// <value> The subtitle font. </value>
+        public string SubtitleFont { get; set; }
+
+        /// <summary>
+        /// Gets or sets the size of the subtitle font.
+        /// </summary>
+        /// <value> The size of the subtitle font. </value>
+        public double SubtitleFontSize { get; set; }
+
+        /// <summary>
+        /// Gets or sets the subtitle font weight.
+        /// </summary>
+        /// <value> The subtitle font weight. </value>
+        public double SubtitleFontWeight { get; set; }
+
+        /// <summary>
+        /// Gets or sets the default color of the text in the plot (titles, legends, annotations, axes).
+        /// </summary>
+        /// <value> The color of the text. </value>
+        public OxyColor TextColor { get; set; }
+
+        /// <summary>
+        /// Gets or sets the title.
+        /// </summary>
+        /// <value> The title. </value>
+        public string Title { get; set; }
+
+        /// <summary>
+        /// Gets or sets the color of the title.
+        /// </summary>
+        /// <value>
+        /// The color of the title.
+        /// </value>
+        /// <remarks>
+        /// If the value is null, the TextColor will be used.
+        /// </remarks>
+        public OxyColor TitleColor { get; set; }
+
+        /// <summary>
+        /// Gets or sets the color of the subtitle.
+        /// </summary>
+        /// <value>
+        /// The color of the subtitle.
+        /// </value>
+        public OxyColor SubtitleColor { get; set; }
+
+        /// <summary>
+        /// Gets the title area.
+        /// </summary>
+        /// <value> The title area. </value>
+        public OxyRect TitleArea { get; private set; }
+
+        /// <summary>
+        /// Gets or sets the title font.
+        /// </summary>
+        /// <value> The title font. </value>
+        public string TitleFont { get; set; }
+
+        /// <summary>
+        /// Gets or sets the size of the title font.
+        /// </summary>
+        /// <value> The size of the title font. </value>
+        public double TitleFontSize { get; set; }
+
+        /// <summary>
+        /// Gets or sets the title font weight.
+        /// </summary>
+        /// <value> The title font weight. </value>
+        public double TitleFontWeight { get; set; }
+
+        /// <summary>
+        /// Gets or sets the padding around the title.
+        /// </summary>
+        /// <value> The title padding. </value>
+        public double TitlePadding { get; set; }
+
+        /// <summary>
+        /// Gets the default angle axis.
+        /// </summary>
+        /// <value> The default angle axis. </value>
+        public AngleAxis DefaultAngleAxis { get; private set; }
+
+        /// <summary>
+        /// Gets the default magnitude axis.
+        /// </summary>
+        /// <value> The default magnitude axis. </value>
+        public MagnitudeAxis DefaultMagnitudeAxis { get; private set; }
+
+        /// <summary>
+        /// Gets the default X axis.
+        /// </summary>
+        /// <value> The default X axis. </value>
+        public Axis DefaultXAxis { get; private set; }
+
+        /// <summary>
+        /// Gets the default Y axis.
+        /// </summary>
+        /// <value> The default Y axis. </value>
+        public Axis DefaultYAxis { get; private set; }
+
+        /// <summary>
+        /// Gets the default color axis.
+        /// </summary>
+        /// <value> The default color axis. </value>
+        public ColorAxis DefaultColorAxis { get; private set; }
+
+        /// <summary>
+        /// Gets the actual title font.
+        /// </summary>
+        protected string ActualTitleFont
+        {
+            get
+            {
+                return this.TitleFont ?? this.DefaultFont;
+            }
+        }
+
+        /// <summary>
+        /// Gets the actual subtitle font.
+        /// </summary>
+        protected string ActualSubtitleFont
+        {
+            get
+            {
+                return this.SubtitleFont ?? this.DefaultFont;
+            }
+        }
+
+        /// <summary>
+        /// Gets the visible series.
+        /// </summary>
+        /// <value> The visible series. </value>
+        private IEnumerable<Series.Series> VisibleSeries
+        {
+            get
+            {
+                return this.Series.Where(s => s.IsVisible);
+            }
+        }
+
+        /// <summary>
+        /// Attaches this model to the specified plot control.
+        /// </summary>
+        /// <param name="plotControl">The plot control.</param>
+        /// <remarks>
+        /// 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.
+        /// </remarks>
+        public void AttachPlotControl(IPlotControl plotControl)
+        {
+            this.PlotControl = plotControl;
+        }
+
+        /// <summary>
+        /// Creates a report for the plot.
+        /// </summary>
+        /// <returns>
+        /// A report.
+        /// </returns>
+        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<ItemsTableField> { 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;
+        }
+
+        /// <summary>
+        /// Creates a text report for the plot.
+        /// </summary>
+        /// <returns>
+        /// The create text report.
+        /// </returns>
+        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();
+            }
+        }
+
+        /// <summary>
+        /// Refreshes the plot.
+        /// </summary>
+        /// <param name="updateData">Updates all data sources if set to <c>true</c>.</param>
+        public void RefreshPlot(bool updateData)
+        {
+            if (this.PlotControl == null)
+            {
+                return;
+            }
+
+            this.PlotControl.RefreshPlot(updateData);
+        }
+
+        /// <summary>
+        /// Invalidates the plot.
+        /// </summary>
+        /// <param name="updateData">Updates all data sources if set to <c>true</c>.</param>
+        public void InvalidatePlot(bool updateData)
+        {
+            if (this.PlotControl == null)
+            {
+                return;
+            }
+
+            this.PlotControl.InvalidatePlot(updateData);
+        }
+
+        /// <summary>
+        /// Gets the first axes that covers the area of the specified point.
+        /// </summary>
+        /// <param name="pt">
+        /// The point.
+        /// </param>
+        /// <param name="xaxis">
+        /// The xaxis.
+        /// </param>
+        /// <param name="yaxis">
+        /// The yaxis.
+        /// </param>
+        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;
+                                }
+                            }
+                        }
+                    }
+                }
+            }
+        }
+
+        /// <summary>
+        /// Gets the default color from the DefaultColors palette.
+        /// </summary>
+        /// <returns>
+        /// The next default color.
+        /// </returns>
+        public OxyColor GetDefaultColor()
+        {
+            return this.DefaultColors[this.currentColorIndex++ % this.DefaultColors.Count];
+        }
+
+        /// <summary>
+        /// Gets the default line style.
+        /// </summary>
+        /// <returns>
+        /// The next default line style.
+        /// </returns>
+        public LineStyle GetDefaultLineStyle()
+        {
+            return (LineStyle)((this.currentColorIndex / this.DefaultColors.Count) % (int)LineStyle.None);
+        }
+
+        /// <summary>
+        /// Gets a series from the specified point.
+        /// </summary>
+        /// <param name="point">
+        /// The point.
+        /// </param>
+        /// <param name="limit">
+        /// The limit.
+        /// </param>
+        /// <returns>
+        /// The nearest series.
+        /// </returns>
+        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;
+        }
+
+        /// <summary>
+        /// Generates C# code of the model.
+        /// </summary>
+        /// <returns>
+        /// C# code.
+        /// </returns>
+        public string ToCode()
+        {
+            var cg = new CodeGenerator(this);
+            return cg.ToCode();
+        }
+
+        /// <summary>
+        /// Returns a <see cref="System.String"/> that represents this instance.
+        /// </summary>
+        /// <returns>
+        /// A <see cref="System.String"/> that represents this instance.
+        /// </returns>
+        public override string ToString()
+        {
+            return this.Title;
+        }
+
+        /// <summary>
+        /// Create an svg model and return it as a string.
+        /// </summary>
+        /// <param name="width">The width (points).</param>
+        /// <param name="height">The height (points).</param>
+        /// <param name="isDocument">if set to <c>true</c>, the xml headers will be included (?xml and 
!DOCTYPE).</param>
+        /// <param name="textMeasurer">The text measurer.</param>
+        /// <returns>The svg string.</returns>
+        public string ToSvg(double width, double height, bool isDocument, IRenderContext textMeasurer)
+        {
+            return SvgExporter.ExportToString(this, width, height, isDocument, textMeasurer);
+        }
+
+        /// <summary>
+        /// Gets all elements of the plot model.
+        /// </summary>
+        /// <returns>An enumerator of the plot elements.</returns>
+        public IEnumerable<PlotElement> 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;
+            }
+        }
+
+        /// <summary>
+        /// 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.
+        /// </summary>
+        /// <param name="updateData">
+        /// if set to <c>true</c> , all data collections will be updated.
+        /// </param>
+        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<CategoryAxis>())
+                {
+                    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();
+            }
+        }
+
+        /// <summary>
+        /// Updates the axis transforms.
+        /// </summary>
+        public void UpdateAxisTransforms()
+        {
+            // Update the axis transforms
+            foreach (var a in this.Axes)
+            {
+                a.UpdateTransform(this.PlotArea);
+            }
+        }
+
+        /// <summary>
+        /// Gets the axis for the specified key.
+        /// </summary>
+        /// <param name="key">The key.</param>
+        /// <param name="defaultAxis">The default axis.</param>
+        /// <returns>The axis, or the defaultAxis if the key is not found.</returns>
+        public Axis GetAxisOrDefault(string key, Axis defaultAxis)
+        {
+            if (key != null)
+            {
+                return this.Axes.FirstOrDefault(a => a.Key == key) ?? defaultAxis;
+            }
+
+            return defaultAxis;
+        }
+
+        /// <summary>
+        /// Raises the Updated event.
+        /// </summary>
+        protected virtual void OnUpdated()
+        {
+            var handler = this.Updated;
+            if (handler != null)
+            {
+                var args = new EventArgs();
+                handler(this, args);
+            }
+        }
+
+        /// <summary>
+        /// Raises the Updating event.
+        /// </summary>
+        protected virtual void OnUpdating()
+        {
+            var handler = this.Updating;
+            if (handler != null)
+            {
+                var args = new EventArgs();
+                handler(this, args);
+            }
+        }
+
+        /// <summary>
+        /// Enforces the same scale on all axes.
+        /// </summary>
+        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);
+            }
+        }
+
+        /// <summary>
+        /// Updates the intervals (major and minor step values).
+        /// </summary>
+        private void UpdateIntervals()
+        {
+            // Update the intervals for all axes
+            foreach (var a in this.Axes)
+            {
+                a.UpdateIntervals(this.PlotArea);
+            }
+        }
+
+        /// <summary>
+        /// Finds and sets the default horizontal and vertical axes (the first horizontal/vertical axes in 
the Axes collection).
+        /// </summary>
+        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();
+            }
+        }
+
+        /// <summary>
+        /// Resets the default color index.
+        /// </summary>
+        private void ResetDefaultColor()
+        {
+            this.currentColorIndex = 0;
+        }
+
+        /// <summary>
+        /// Updates maximum and minimum values of the axes from values of all data series.
+        /// </summary>
+        /// <param name="isDataUpdated">
+        /// if set to <c>true</c> , the data has been updated.
+        /// </param>
+        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 --git a/oxyplot/OxyPlot/PlotModel/SelectablePlotElement.cs 
b/oxyplot/OxyPlot/PlotModel/SelectablePlotElement.cs
new file mode 100644
index 0000000..8bc8d2f
--- /dev/null
+++ b/oxyplot/OxyPlot/PlotModel/SelectablePlotElement.cs
@@ -0,0 +1,159 @@
+// 
--------------------------------------------------------------------------------------------------------------------
+// <copyright file="SelectablePlotElement.cs" company="OxyPlot">
+//   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.
+// </copyright>
+// <summary>
+//   Represents a plot element that supports selection.
+// </summary>
+// 
--------------------------------------------------------------------------------------------------------------------
+namespace OxyPlot
+{
+    using System;
+
+    /// <summary>
+    /// Provides an abstract base class for plot elements that support selection.
+    /// </summary>
+    public abstract class SelectablePlotElement : PlotElement
+    {
+        /// <summary>
+        /// The is selected.
+        /// </summary>
+        private bool isSelected;
+
+        /// <summary>
+        /// Initializes a new instance of the <see cref="SelectablePlotElement"/> class.
+        /// </summary>
+        protected SelectablePlotElement()
+        {
+            this.Selectable = true;
+            this.IsSelected = false;
+        }
+
+        /// <summary>
+        /// Occurs when the IsSelected property is changed.
+        /// </summary>
+        public event EventHandler Selected;
+
+        /// <summary>
+        /// Gets or sets the index of the selected item (or -1 if all items are selected).
+        /// </summary>
+        /// <value>
+        /// The index of the selected.
+        /// </value>
+        public int SelectedIndex { get; set; }
+
+        /// <summary>
+        /// Gets or sets a value indicating whether this plot element is selected.
+        /// </summary>
+        public bool IsSelected
+        {
+            get
+            {
+                return this.isSelected;
+            }
+
+            set
+            {
+                if (value == this.isSelected)
+                {
+                    return;
+                }
+
+                this.isSelected = value;
+                this.OnIsSelectedChanged();
+            }
+        }
+
+        /// <summary>
+        /// Gets or sets a value indicating whether this plot element can be selected.
+        /// </summary>
+        public bool Selectable { get; set; }
+
+        /// <summary>
+        /// Gets the actual selection color.
+        /// </summary>
+        /// <value> The actual selection color. </value>
+        protected OxyColor ActualSelectedColor
+        {
+            get
+            {
+                if (this.PlotModel != null)
+                {
+                    return this.PlotModel.SelectionColor ?? PlotModel.DefaultSelectionColor;
+                }
+
+                return PlotModel.DefaultSelectionColor;
+            }
+        }
+
+        /// <summary>
+        /// Gets the selection color it the element is selected, or the specified color if it is not.
+        /// </summary>
+        /// <param name="originalColor">The unselected color of the element.</param>
+        /// <param name="index">The index of the item to check (use -1 for all items).</param>
+        /// <returns>
+        /// A color.
+        /// </returns>
+        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;
+        }
+
+        /// <summary>
+        /// Gets the selection fill color it the element is selected, or the specified fill color if it is 
not.
+        /// </summary>
+        /// <param name="originalColor">The unselected fill color of the element.</param>
+        /// <param name="index">The index of the item to check (use -1 for all items).</param>
+        /// <returns>
+        /// A fill color.
+        /// </returns>
+        protected OxyColor GetSelectableFillColor(OxyColor originalColor, int index = -1)
+        {
+            return this.GetSelectableColor(originalColor, index);
+        }
+
+        /// <summary>
+        /// Raises the Selected event.
+        /// </summary>
+        protected void OnIsSelectedChanged()
+        {
+            var eh = this.Selected;
+            if (eh != null)
+            {
+                eh(this, new EventArgs());
+            }
+        }
+
+    }
+}
\ No newline at end of file
diff --git a/oxyplot/OxyPlot/PlotModel/UIPlotElement.cs b/oxyplot/OxyPlot/PlotModel/UIPlotElement.cs
new file mode 100644
index 0000000..2c8a990
--- /dev/null
+++ b/oxyplot/OxyPlot/PlotModel/UIPlotElement.cs
@@ -0,0 +1,116 @@
+// 
--------------------------------------------------------------------------------------------------------------------
+// <copyright file="UIPlotElement.cs" company="OxyPlot">
+//   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.
+// </copyright>
+// <summary>
+//   Represents a plot element that handles mouse events.
+// </summary>
+// 
--------------------------------------------------------------------------------------------------------------------
+namespace OxyPlot
+{
+    using System;
+
+    /// <summary>
+    /// Provides an abstract base class for plot elements that handle mouse events.
+    /// </summary>
+    public abstract class UIPlotElement : SelectablePlotElement
+    {
+        /// <summary>
+        /// Occurs when a mouse button is pressed down on the model.
+        /// </summary>
+        public event EventHandler<OxyMouseEventArgs> MouseDown;
+
+        /// <summary>
+        /// Occurs when the mouse is moved on the plot element (only occurs after MouseDown).
+        /// </summary>
+        public event EventHandler<OxyMouseEventArgs> MouseMove;
+
+        /// <summary>
+        /// Occurs when the mouse button is released on the plot element.
+        /// </summary>
+        public event EventHandler<OxyMouseEventArgs> MouseUp;
+
+        /// <summary>
+        /// Raises the <see cref="MouseDown"/> event.
+        /// </summary>
+        /// <param name="sender">
+        /// The sender.
+        /// </param>
+        /// <param name="e">
+        /// The <see cref="OxyMouseEventArgs"/> instance containing the event data.
+        /// </param>
+        protected internal virtual void OnMouseDown(object sender, OxyMouseEventArgs e)
+        {
+            if (this.MouseDown != null)
+            {
+                this.MouseDown(sender, e);
+            }
+        }
+
+        /// <summary>
+        /// Raises the <see cref="MouseMove"/> event.
+        /// </summary>
+        /// <param name="sender">
+        /// The sender.
+        /// </param>
+        /// <param name="e">
+        /// The <see cref="OxyMouseEventArgs"/> instance containing the event data.
+        /// </param>
+        protected internal virtual void OnMouseMove(object sender, OxyMouseEventArgs e)
+        {
+            if (this.MouseMove != null)
+            {
+                this.MouseMove(sender, e);
+            }
+        }
+
+        /// <summary>
+        /// Raises the <see cref="MouseUp"/> event.
+        /// </summary>
+        /// <param name="sender">
+        /// The sender.
+        /// </param>
+        /// <param name="e">
+        /// The <see cref="OxyMouseEventArgs"/> instance containing the event data.
+        /// </param>
+        protected internal virtual void OnMouseUp(object sender, OxyMouseEventArgs e)
+        {
+            if (this.MouseUp != null)
+            {
+                this.MouseUp(sender, e);
+            }
+        }
+
+        /// <summary>
+        /// Tests if the plot element is hit by the specified point.
+        /// </summary>
+        /// <param name="point">The point.</param>
+        /// <param name="tolerance">The tolerance.</param>
+        /// <returns>
+        /// A hit test result.
+        /// </returns>
+        protected internal abstract HitTestResult HitTest(ScreenPoint point, double tolerance);
+
+    }
+}
\ No newline at end of file
diff --git a/oxyplot/OxyPlot/Properties/AssemblyInfo.cs b/oxyplot/OxyPlot/Properties/AssemblyInfo.cs
new file mode 100644
index 0000000..d2be498
--- /dev/null
+++ b/oxyplot/OxyPlot/Properties/AssemblyInfo.cs
@@ -0,0 +1,10 @@
+// 
--------------------------------------------------------------------------------------------------------------------
+// <copyright file="AssemblyInfo.cs" company="OxyPlot">
+//   http://oxyplot.codeplex.com, license: MIT
+// </copyright>
+// 
--------------------------------------------------------------------------------------------------------------------
+
+using System.Reflection;
+
+[assembly: AssemblyTitle("OxyPlot")]
+[assembly: AssemblyDescription("OxyPlot core library")]
\ No newline at end of file
diff --git a/oxyplot/OxyPlot/Render/AngleAxisRenderer.cs b/oxyplot/OxyPlot/Render/AngleAxisRenderer.cs
new file mode 100644
index 0000000..20e4af8
--- /dev/null
+++ b/oxyplot/OxyPlot/Render/AngleAxisRenderer.cs
@@ -0,0 +1,166 @@
+// 
--------------------------------------------------------------------------------------------------------------------
+// <copyright file="AngleAxisRenderer.cs" company="OxyPlot">
+//   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.
+// </copyright>
+// <summary>
+//   The angle axis renderer.
+// </summary>
+// 
--------------------------------------------------------------------------------------------------------------------
+namespace OxyPlot
+{
+    using System;
+
+    using OxyPlot.Axes;
+
+    /// <summary>
+    /// Provides functionality to render <see cref="AngleAxis"/>.
+    /// </summary>
+    public class AngleAxisRenderer : AxisRendererBase
+    {
+        /// <summary>
+        /// Initializes a new instance of the <see cref="AngleAxisRenderer"/> class.
+        /// </summary>
+        /// <param name="rc">
+        /// The render context.
+        /// </param>
+        /// <param name="plot">
+        /// The plot.
+        /// </param>
+        public AngleAxisRenderer(IRenderContext rc, PlotModel plot)
+            : base(rc, plot)
+        {
+        }
+
+        /// <summary>
+        /// Renders the specified axis.
+        /// </summary>
+        /// <param name="axis">The axis.</param>
+        /// <param name="pass">The render pass.</param>
+        /// <exception cref="System.InvalidOperationException">Magnitude axis not defined.</exception>
+        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 --git a/oxyplot/OxyPlot/Render/AxisRenderer.cs b/oxyplot/OxyPlot/Render/AxisRenderer.cs
new file mode 100644
index 0000000..009eff4
--- /dev/null
+++ b/oxyplot/OxyPlot/Render/AxisRenderer.cs
@@ -0,0 +1,532 @@
+// 
--------------------------------------------------------------------------------------------------------------------
+// <copyright file="AxisRenderer.cs" company="OxyPlot">
+//   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.
+// </copyright>
+// 
--------------------------------------------------------------------------------------------------------------------
+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<double> majorTickValues;
+        private OxyPen minorPen;
+        private OxyPen minorTickPen;
+        private ICollection<double> 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<ScreenPoint>();
+                    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<ScreenPoint>();
+                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 --git a/oxyplot/OxyPlot/Render/AxisRendererBase.cs b/oxyplot/OxyPlot/Render/AxisRendererBase.cs
new file mode 100644
index 0000000..f79b4b8
--- /dev/null
+++ b/oxyplot/OxyPlot/Render/AxisRendererBase.cs
@@ -0,0 +1,217 @@
+// 
--------------------------------------------------------------------------------------------------------------------
+// <copyright file="AxisRendererBase.cs" company="OxyPlot">
+//   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.
+// </copyright>
+// <summary>
+//   The axis renderer base.
+// </summary>
+// 
--------------------------------------------------------------------------------------------------------------------
+namespace OxyPlot
+{
+    using System.Collections.Generic;
+
+    using OxyPlot.Axes;
+
+    /// <summary>
+    /// Provides an abstract base class for axis renderers.
+    /// </summary>
+    public abstract class AxisRendererBase
+    {
+        /// <summary>
+        /// The plot.
+        /// </summary>
+        protected readonly PlotModel Plot;
+
+        /// <summary>
+        /// The render context.
+        /// </summary>
+        protected readonly IRenderContext rc;
+
+        /// <summary>
+        /// The axis lines pen.
+        /// </summary>
+        protected OxyPen AxislinePen;
+
+        /// <summary>
+        /// The extra grid lines pen.
+        /// </summary>
+        protected OxyPen ExtraPen;
+
+        /// <summary>
+        /// The major label values.
+        /// </summary>
+        protected IList<double> MajorLabelValues;
+
+        /// <summary>
+        /// The major grid lines pen.
+        /// </summary>
+        protected OxyPen MajorPen;
+
+        /// <summary>
+        /// The major tick pen.
+        /// </summary>
+        protected OxyPen MajorTickPen;
+
+        /// <summary>
+        /// The major tick values.
+        /// </summary>
+        protected IList<double> MajorTickValues;
+
+        /// <summary>
+        /// The minor grid lines pen.
+        /// </summary>
+        protected OxyPen MinorPen;
+
+        /// <summary>
+        /// The minor tick pen.
+        /// </summary>
+        protected OxyPen MinorTickPen;
+
+        /// <summary>
+        /// The minor tick values.
+        /// </summary>
+        protected IList<double> MinorTickValues;
+
+        /// <summary>
+        /// The zero grid line pen.
+        /// </summary>
+        protected OxyPen ZeroPen;
+
+        /// <summary>
+        /// Initializes a new instance of the <see cref="AxisRendererBase"/> class.
+        /// </summary>
+        /// <param name="rc">
+        /// The render context.
+        /// </param>
+        /// <param name="plot">
+        /// The plot.
+        /// </param>
+        protected AxisRendererBase(IRenderContext rc, PlotModel plot)
+        {
+            this.Plot = plot;
+            this.rc = rc;
+        }
+
+        /// <summary>
+        /// Renders the specified axis.
+        /// </summary>
+        /// <param name="axis">The axis.</param>
+        /// <param name="pass">The pass.</param>
+        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);
+        }
+
+        /// <summary>
+        /// The create pens.
+        /// </summary>
+        /// <param name="axis">
+        /// The axis.
+        /// </param>
+        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);
+        }
+
+        /// <summary>
+        /// The get tick positions.
+        /// </summary>
+        /// <param name="axis">
+        /// The axis.
+        /// </param>
+        /// <param name="glt">
+        /// The glt.
+        /// </param>
+        /// <param name="ticksize">
+        /// The ticksize.
+        /// </param>
+        /// <param name="position">
+        /// The position.
+        /// </param>
+        /// <param name="x0">
+        /// The x 0.
+        /// </param>
+        /// <param name="x1">
+        /// The x 1.
+        /// </param>
+        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;
+            }
+        }
+
+        /// <summary>
+        /// Determines whether the specified value is within the specified range.
+        /// </summary>
+        /// <param name="d">The value to check.</param>
+        /// <param name="min">The minium value of the range.</param>
+        /// <param name="max">The maximum value of the range.</param>
+        /// <returns>
+        ///  <c>true</c> if the specified value is within the range; otherwise, <c>false</c>.
+        /// </returns>
+        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 --git a/oxyplot/OxyPlot/Render/HorizontalAndVerticalAxisRenderer.cs 
b/oxyplot/OxyPlot/Render/HorizontalAndVerticalAxisRenderer.cs
new file mode 100644
index 0000000..15ad869
--- /dev/null
+++ b/oxyplot/OxyPlot/Render/HorizontalAndVerticalAxisRenderer.cs
@@ -0,0 +1,642 @@
+// 
--------------------------------------------------------------------------------------------------------------------
+// <copyright file="HorizontalAndVerticalAxisRenderer.cs" company="OxyPlot">
+//   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.
+// </copyright>
+// <summary>
+//   Rendering helper class for horizontal and vertical axes (both linear and logarithmic)
+// </summary>
+// 
--------------------------------------------------------------------------------------------------------------------
+namespace OxyPlot
+{
+    using System;
+    using System.Collections.Generic;
+    using System.Diagnostics;
+
+    using OxyPlot.Axes;
+
+    /// <summary>
+    /// Preovides functionality to render horizontal and vertical axes.
+    /// </summary>
+    public class HorizontalAndVerticalAxisRenderer : AxisRendererBase
+    {
+        /// <summary>
+        /// Initializes a new instance of the <see cref="HorizontalAndVerticalAxisRenderer"/> class.
+        /// </summary>
+        /// <param name="rc">
+        /// The render context.
+        /// </param>
+        /// <param name="plot">
+        /// The plot.
+        /// </param>
+        public HorizontalAndVerticalAxisRenderer(IRenderContext rc, PlotModel plot)
+            : base(rc, plot)
+        {
+        }
+
+        /// <summary>
+        /// Renders the specified axis.
+        /// </summary>
+        /// <param name="axis">The axis.</param>
+        /// <param name="pass">The pass.</param>
+        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);
+            }
+        }
+
+        /// <summary>
+        /// Gets the axis title position, rotation and alignment.
+        /// </summary>
+        /// <param name="axis">
+        /// The axis.
+        /// </param>
+        /// <param name="titlePosition">
+        /// The title position.
+        /// </param>
+        /// <param name="angle">
+        /// The angle.
+        /// </param>
+        /// <param name="halign">
+        /// The horizontal alignment.
+        /// </param>
+        /// <param name="valign">
+        /// The vertical alignment.
+        /// </param>
+        /// <returns>
+        /// The <see cref="ScreenPoint"/>.
+        /// </returns>
+        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");
+            }
+        }
+
+        /// <summary>
+        /// Gets the alignments given the specified rotation angle.
+        /// </summary>
+        /// <param name="angle">
+        /// The angle.
+        /// </param>
+        /// <param name="defaultHorizontalAlignment">
+        /// The default horizontal alignment.
+        /// </param>
+        /// <param name="defaultVerticalAlignment">
+        /// The default vertical alignment.
+        /// </param>
+        /// <param name="ha">
+        /// The rotated horizontal alignment.
+        /// </param>
+        /// <param name="va">
+        /// The rotated vertical alignment.
+        /// </param>
+        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);
+            }
+        }
+
+        /// <summary>
+        /// Linear interpolation
+        /// http://en.wikipedia.org/wiki/Linear_interpolation
+        /// </summary>
+        /// <param name="x0">
+        /// The x0.
+        /// </param>
+        /// <param name="x1">
+        /// The x1.
+        /// </param>
+        /// <param name="f">
+        /// The interpolation factor.
+        /// </param>
+        /// <returns>
+        /// The interpolated value.
+        /// </returns>
+        private static double Lerp(double x0, double x1, double f)
+        {
+            return (x0 * (1 - f)) + (x1 * f);
+        }
+
+        /// <summary>
+        /// Snaps v to value if it is within the the specified distance.
+        /// </summary>
+        /// <param name="target">
+        /// The target value.
+        /// </param>
+        /// <param name="v">
+        /// The value to snap.
+        /// </param>
+        /// <param name="eps">
+        /// The distance tolerance.
+        /// </param>
+        private static void SnapTo(double target, ref double v, double eps = 0.5)
+        {
+            if (v > target - eps && v < target + eps)
+            {
+                v = target;
+            }
+        }
+
+        /// <summary>
+        /// Renders the axis title.
+        /// </summary>
+        /// <param name="axis">
+        /// The axis.
+        /// </param>
+        /// <param name="titlePosition">
+        /// The title position.
+        /// </param>
+        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);
+        }
+
+        /// <summary>
+        /// Renders the major items.
+        /// </summary>
+        /// <param name="axis">
+        /// The axis.
+        /// </param>
+        /// <param name="axisPosition">
+        /// The axis position.
+        /// </param>
+        /// <param name="titlePosition">
+        /// The title position.
+        /// </param>
+        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<ScreenPoint>();
+            var majorTickSegments = new List<ScreenPoint>();
+            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);
+            }
+        }
+
+        /// <summary>
+        /// Renders the minor items.
+        /// </summary>
+        /// <param name="axis">
+        /// The axis.
+        /// </param>
+        /// <param name="axisPosition">
+        /// The axis position.
+        /// </param>
+        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<ScreenPoint>();
+            var minorTickSegments = new List<ScreenPoint>();
+            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 --git a/oxyplot/OxyPlot/Render/IRenderContext.cs b/oxyplot/OxyPlot/Render/IRenderContext.cs
new file mode 100644
index 0000000..2bebb80
--- /dev/null
+++ b/oxyplot/OxyPlot/Render/IRenderContext.cs
@@ -0,0 +1,400 @@
+// 
--------------------------------------------------------------------------------------------------------------------
+// <copyright file="IRenderContext.cs" company="OxyPlot">
+//   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.
+// </copyright>
+// <summary>
+//   Render context interface.
+// </summary>
+// 
--------------------------------------------------------------------------------------------------------------------
+namespace OxyPlot
+{
+    using System.Collections.Generic;
+
+    /// <summary>
+    /// Defines rendering functionality.
+    /// </summary>
+    public interface IRenderContext
+    {
+        /// <summary>
+        /// Gets a value indicating whether the context renders to screen.
+        /// </summary>
+        /// <value>
+        ///   <c>true</c> if the context renders to screen; otherwise, <c>false</c>.
+        /// </value>
+        bool RendersToScreen { get; }
+
+        /// <summary>
+        /// Draws an ellipse.
+        /// </summary>
+        /// <param name="rect">
+        /// The rectangle.
+        /// </param>
+        /// <param name="fill">
+        /// The fill color.
+        /// </param>
+        /// <param name="stroke">
+        /// The stroke color.
+        /// </param>
+        /// <param name="thickness">
+        /// The thickness.
+        /// </param>
+        void DrawEllipse(OxyRect rect, OxyColor fill, OxyColor stroke, double thickness = 1.0);
+
+        /// <summary>
+        /// Draws the collection of ellipses, where all have the same stroke and fill.
+        /// This performs better than calling DrawEllipse multiple times.
+        /// </summary>
+        /// <param name="rectangles">
+        /// The rectangles.
+        /// </param>
+        /// <param name="fill">
+        /// The fill color.
+        /// </param>
+        /// <param name="stroke">
+        /// The stroke color.
+        /// </param>
+        /// <param name="thickness">
+        /// The stroke thickness.
+        /// </param>
+        void DrawEllipses(IList<OxyRect> rectangles, OxyColor fill, OxyColor stroke, double thickness = 1.0);
+
+        /// <summary>
+        /// Draws the polyline from the specified points.
+        /// </summary>
+        /// <param name="points">
+        /// The points.
+        /// </param>
+        /// <param name="stroke">
+        /// The stroke color.
+        /// </param>
+        /// <param name="thickness">
+        /// The stroke thickness.
+        /// </param>
+        /// <param name="dashArray">
+        /// The dash array.
+        /// </param>
+        /// <param name="lineJoin">
+        /// The line join type.
+        /// </param>
+        /// <param name="aliased">
+        /// if set to <c>true</c> the shape will be aliased.
+        /// </param>
+        void DrawLine(
+            IList<ScreenPoint> points,
+            OxyColor stroke,
+            double thickness = 1.0,
+            double[] dashArray = null,
+            OxyPenLineJoin lineJoin = OxyPenLineJoin.Miter,
+            bool aliased = false);
+
+        /// <summary>
+        /// 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.
+        /// </summary>
+        /// <param name="points">
+        /// The points.
+        /// </param>
+        /// <param name="stroke">
+        /// The stroke color.
+        /// </param>
+        /// <param name="thickness">
+        /// The stroke thickness.
+        /// </param>
+        /// <param name="dashArray">
+        /// The dash array.
+        /// </param>
+        /// <param name="lineJoin">
+        /// The line join type.
+        /// </param>
+        /// <param name="aliased">
+        /// if set to <c>true</c> the shape will be aliased.
+        /// </param>
+        void DrawLineSegments(
+            IList<ScreenPoint> points,
+            OxyColor stroke,
+            double thickness = 1.0,
+            double[] dashArray = null,
+            OxyPenLineJoin lineJoin = OxyPenLineJoin.Miter,
+            bool aliased = false);
+
+        /// <summary>
+        /// Draws the polygon from the specified points. The polygon can have stroke and/or fill.
+        /// </summary>
+        /// <param name="points">
+        /// The points.
+        /// </param>
+        /// <param name="fill">
+        /// The fill color.
+        /// </param>
+        /// <param name="stroke">
+        /// The stroke color.
+        /// </param>
+        /// <param name="thickness">
+        /// The stroke thickness.
+        /// </param>
+        /// <param name="dashArray">
+        /// The dash array.
+        /// </param>
+        /// <param name="lineJoin">
+        /// The line join type.
+        /// </param>
+        /// <param name="aliased">
+        /// if set to <c>true</c> the shape will be aliased.
+        /// </param>
+        void DrawPolygon(
+            IList<ScreenPoint> points,
+            OxyColor fill,
+            OxyColor stroke,
+            double thickness = 1.0,
+            double[] dashArray = null,
+            OxyPenLineJoin lineJoin = OxyPenLineJoin.Miter,
+            bool aliased = false);
+
+        /// <summary>
+        /// Draws a collection of polygons, where all polygons have the same stroke and fill.
+        /// This performs better than calling DrawPolygon multiple times.
+        /// </summary>
+        /// <param name="polygons">
+        /// The polygons.
+        /// </param>
+        /// <param name="fill">
+        /// The fill color.
+        /// </param>
+        /// <param name="stroke">
+        /// The stroke color.
+        /// </param>
+        /// <param name="thickness">
+        /// The stroke thickness.
+        /// </param>
+        /// <param name="dashArray">
+        /// The dash array.
+        /// </param>
+        /// <param name="lineJoin">
+        /// The line join type.
+        /// </param>
+        /// <param name="aliased">
+        /// if set to <c>true</c> the shape will be aliased.
+        /// </param>
+        void DrawPolygons(
+            IList<IList<ScreenPoint>> polygons,
+            OxyColor fill,
+            OxyColor stroke,
+            double thickness = 1.0,
+            double[] dashArray = null,
+            OxyPenLineJoin lineJoin = OxyPenLineJoin.Miter,
+            bool aliased = false);
+
+        /// <summary>
+        /// Draws the rectangle.
+        /// </summary>
+        /// <param name="rect">
+        /// The rectangle.
+        /// </param>
+        /// <param name="fill">
+        /// The fill color.
+        /// </param>
+        /// <param name="stroke">
+        /// The stroke color.
+        /// </param>
+        /// <param name="thickness">
+        /// The stroke thickness.
+        /// </param>
+        void DrawRectangle(OxyRect rect, OxyColor fill, OxyColor stroke, double thickness = 1.0);
+
+        /// <summary>
+        /// Draws a collection of rectangles, where all have the same stroke and fill.
+        /// This performs better than calling DrawRectangle multiple times.
+        /// </summary>
+        /// <param name="rectangles">
+        /// The rectangles.
+        /// </param>
+        /// <param name="fill">
+        /// The fill color.
+        /// </param>
+        /// <param name="stroke">
+        /// The stroke color.
+        /// </param>
+        /// <param name="thickness">
+        /// The stroke thickness.
+        /// </param>
+        void DrawRectangles(IList<OxyRect> rectangles, OxyColor fill, OxyColor stroke, double thickness = 
1.0);
+
+        /// <summary>
+        /// Draws the text.
+        /// </summary>
+        /// <param name="p">
+        /// The position.
+        /// </param>
+        /// <param name="text">
+        /// The text.
+        /// </param>
+        /// <param name="fill">
+        /// The fill color.
+        /// </param>
+        /// <param name="fontFamily">
+        /// The font family.
+        /// </param>
+        /// <param name="fontSize">
+        /// Size of the font.
+        /// </param>
+        /// <param name="fontWeight">
+        /// The font weight.
+        /// </param>
+        /// <param name="rotate">
+        /// The rotation angle.
+        /// </param>
+        /// <param name="halign">
+        /// The horizontal alignment.
+        /// </param>
+        /// <param name="valign">
+        /// The vertical alignment.
+        /// </param>
+        /// <param name="maxSize">
+        /// The maximum size of the text.
+        /// </param>
+        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);
+
+        /// <summary>
+        /// Measures the text.
+        /// </summary>
+        /// <param name="text">
+        /// The text.
+        /// </param>
+        /// <param name="fontFamily">
+        /// The font family.
+        /// </param>
+        /// <param name="fontSize">
+        /// Size of the font.
+        /// </param>
+        /// <param name="fontWeight">
+        /// The font weight.
+        /// </param>
+        /// <returns>
+        /// The text size.
+        /// </returns>
+        OxySize MeasureText(string text, string fontFamily = null, double fontSize = 10, double fontWeight = 
500);
+
+        /// <summary>
+        /// Sets the tool tip for the following items.
+        /// </summary>
+        /// <params>
+        /// This is only used in the plot controls.
+        /// </params>
+        /// <param name="text">
+        /// The text in the tooltip.
+        /// </param>
+        void SetToolTip(string text);
+
+        /// <summary>
+        /// Cleans up resources not in use.
+        /// </summary>
+        /// <remarks>
+        /// This method is called at the end of each rendering.
+        /// </remarks>
+        void CleanUp();
+
+        /// <summary>
+        /// Gets the size of the specified image.
+        /// </summary>
+        /// <param name="source">The image source.</param>
+        /// <returns>The image info.</returns>
+        OxyImageInfo GetImageInfo(OxyImage source);
+
+        /// <summary>
+        /// Draws the specified portion of the specified <see cref="OxyImage"/> at the specified location 
and with the specified size.
+        /// </summary>
+        /// <param name="source">The source.</param>
+        /// <param name="srcX">The x-coordinate of the upper-left corner of the portion of the source image 
to draw.</param>
+        /// <param name="srcY">The y-coordinate of the upper-left corner of the portion of the source image 
to draw.</param>
+        /// <param name="srcWidth">Width of the portion of the source image to draw.</param>
+        /// <param name="srcHeight">Height of the portion of the source image to draw.</param>
+        /// <param name="destX">The x-coordinate of the upper-left corner of drawn image.</param>
+        /// <param name="destY">The y-coordinate of the upper-left corner of drawn image.</param>
+        /// <param name="destWidth">The width of the drawn image.</param>
+        /// <param name="destHeight">The height of the drawn image.</param>
+        /// <param name="opacity">The opacity.</param>
+        /// <param name="interpolate">interpolate if set to <c>true</c>.</param>
+        void DrawImage(OxyImage source, uint srcX, uint srcY, uint srcWidth, uint srcHeight, double destX, 
double destY, double destWidth, double destHeight, double opacity, bool interpolate);
+
+        /// <summary>
+        /// Sets the clip rectangle.
+        /// </summary>
+        /// <param name="rect">The clip rectangle.</param>
+        /// <returns>True if the clip rectangle was set.</returns>
+        bool SetClip(OxyRect rect);
+
+        /// <summary>
+        /// Resets the clip rectangle.
+        /// </summary>
+        void ResetClip();
+    }
+
+    /// <summary>
+    /// Provides information about the size of an image.
+    /// </summary>
+    public class OxyImageInfo
+    {
+        /// <summary>
+        /// Gets or sets the width in pixels.
+        /// </summary>
+        /// <value>
+        /// The width.
+        /// </value>
+        public uint Width { get; set; }
+
+        /// <summary>
+        /// Gets or sets the height in pixels.
+        /// </summary>
+        /// <value>
+        /// The height.
+        /// </value>
+        public uint Height { get; set; }
+
+        /// <summary>
+        /// Gets or sets the horizontal resolution in dpi.
+        /// </summary>
+        /// <value>
+        /// The dpi X.
+        /// </value>
+        public double DpiX { get; set; }
+
+        /// <summary>
+        /// Gets or sets the vertical resolution in dpi.
+        /// </summary>
+        /// <value>
+        /// The dpi Y.
+        /// </value>
+        public double DpiY { get; set; }
+    }
+}
\ No newline at end of file
diff --git a/oxyplot/OxyPlot/Render/MagnitudeAxisRenderer.cs b/oxyplot/OxyPlot/Render/MagnitudeAxisRenderer.cs
new file mode 100644
index 0000000..de46e38
--- /dev/null
+++ b/oxyplot/OxyPlot/Render/MagnitudeAxisRenderer.cs
@@ -0,0 +1,145 @@
+// 
--------------------------------------------------------------------------------------------------------------------
+// <copyright file="MagnitudeAxisRenderer.cs" company="OxyPlot">
+//   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.
+// </copyright>
+// <summary>
+//   The magnitude axis renderer.
+// </summary>
+// 
--------------------------------------------------------------------------------------------------------------------
+namespace OxyPlot
+{
+    using System;
+    using System.Collections.Generic;
+
+    using OxyPlot.Axes;
+
+    /// <summary>
+    /// Provides functionality to render <see cref="MagnitudeAxis"/>.
+    /// </summary>
+    public class MagnitudeAxisRenderer : AxisRendererBase
+    {
+        /// <summary>
+        /// Initializes a new instance of the <see cref="MagnitudeAxisRenderer"/> class.
+        /// </summary>
+        /// <param name="rc">
+        /// The render context.
+        /// </param>
+        /// <param name="plot">
+        /// The plot.
+        /// </param>
+        public MagnitudeAxisRenderer(IRenderContext rc, PlotModel plot)
+            : base(rc, plot)
+        {
+        }
+
+        /// <summary>
+        /// Renders the specified axis.
+        /// </summary>
+        /// <param name="axis">The axis.</param>
+        /// <param name="pass">The pass.</param>
+        /// <exception cref="System.NullReferenceException">Angle axis should not be null.</exception>
+        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<ScreenPoint>();
+                    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<ScreenPoint>();
+                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 --git a/oxyplot/OxyPlot/Render/MathRenderingExtensions.cs 
b/oxyplot/OxyPlot/Render/MathRenderingExtensions.cs
new file mode 100644
index 0000000..afb6631
--- /dev/null
+++ b/oxyplot/OxyPlot/Render/MathRenderingExtensions.cs
@@ -0,0 +1,347 @@
+// 
--------------------------------------------------------------------------------------------------------------------
+// <copyright file="MathRenderingExtensions.cs" company="OxyPlot">
+//   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.
+// </copyright>
+// <summary>
+//   The math rendering extensions.
+// </summary>
+// 
--------------------------------------------------------------------------------------------------------------------
+namespace OxyPlot
+{
+    using System;
+
+    /// <summary>
+    /// Provides functionality to render mathematic expressions (TeX syntax).
+    /// </summary>
+    public static class MathRenderingExtensions
+    {
+        /// <summary>
+        /// Initializes static members of the <see cref = "MathRenderingExtensions" /> class.
+        /// </summary>
+        static MathRenderingExtensions()
+        {
+            SubAlignment = 0.6;
+            SubSize = 0.62;
+            SuperAlignment = 0;
+            SuperSize = 0.62;
+        }
+
+        /// <summary>
+        /// Gets or sets the subscript alignment.
+        /// </summary>
+        private static double SubAlignment { get; set; }
+
+        /// <summary>
+        /// Gets or sets the subscript size.
+        /// </summary>
+        private static double SubSize { get; set; }
+
+        /// <summary>
+        /// Gets or sets the superscript alignment.
+        /// </summary>
+        private static double SuperAlignment { get; set; }
+
+        /// <summary>
+        /// Gets or sets the superscript size.
+        /// </summary>
+        private static double SuperSize { get; set; }
+
+        /// <summary>
+        /// Draws or measures text containing sub- and superscript.
+        /// </summary>
+        /// <param name="rc">The render context.</param>
+        /// <param name="pt">The point.</param>
+        /// <param name="text">The text.</param>
+        /// <param name="textColor">Color of the text.</param>
+        /// <param name="fontFamily">The font family.</param>
+        /// <param name="fontSize">The font size.</param>
+        /// <param name="fontWeight">The font weight.</param>
+        /// <param name="angle">The angle.</param>
+        /// <param name="ha">The horizontal alignment.</param>
+        /// <param name="va">The vertical alignment.</param>
+        /// <param name="maxsize">The maximum size of the text.</param>
+        /// <param name="measure">Measure the size of the text if set to <c>true</c>.</param>
+        /// <returns>The size of the text.</returns>
+        /// <example>
+        /// Subscript: H_{2}O
+        /// Superscript: E=mc^{2}
+        /// Both: A^{2}_{i,j}
+        /// </example>
+        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;
+        }
+
+        /// <summary>
+        /// Draws text containing sub- and superscript.
+        /// </summary>
+        /// <param name="rc">The render context.</param>
+        /// <param name="pt">The point.</param>
+        /// <param name="text">The text.</param>
+        /// <param name="textColor">Color of the text.</param>
+        /// <param name="fontFamily">The font family.</param>
+        /// <param name="fontSize">The font size.</param>
+        /// <param name="fontWeight">The font weight.</param>
+        /// <param name="angle">The angle.</param>
+        /// <param name="ha">The horizontal alignment.</param>
+        /// <param name="va">The vertical alignment.</param>
+        /// <param name="maxsize">The maximum size of the text.</param>
+        /// <example>
+        /// Subscript: H_{2}O
+        /// Superscript: E=mc^{2}
+        /// Both: A^{2}_{i,j}
+        /// </example>
+        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);
+        }
+
+        /// <summary>
+        /// The measure math text.
+        /// </summary>
+        /// <param name="rc">
+        /// The render context.
+        /// </param>
+        /// <param name="text">
+        /// The text.
+        /// </param>
+        /// <param name="fontFamily">
+        /// The font family.
+        /// </param>
+        /// <param name="fontSize">
+        /// The font size.
+        /// </param>
+        /// <param name="fontWeight">
+        /// The font weight.
+        /// </param>
+        /// <returns>
+        /// The size of the text.
+        /// </returns>
+        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);
+        }
+
+        /// <summary>
+        /// The internal draw math text.
+        /// </summary>
+        /// <param name="rc">
+        /// The render context.
+        /// </param>
+        /// <param name="x">
+        /// The x.
+        /// </param>
+        /// <param name="y">
+        /// The y.
+        /// </param>
+        /// <param name="s">
+        /// The s.
+        /// </param>
+        /// <param name="textColor">
+        /// The text color.
+        /// </param>
+        /// <param name="fontFamily">
+        /// The font family.
+        /// </param>
+        /// <param name="fontSize">
+        /// The font size.
+        /// </param>
+        /// <param name="fontWeight">
+        /// The font weight.
+        /// </param>
+        /// <param name="measureOnly">
+        /// The measure only.
+        /// </param>
+        /// <returns>
+        /// The size of the text.
+        /// </returns>
+        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<double, double, string, double, OxySize> 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 --git a/oxyplot/OxyPlot/Render/PlotRenderer.cs b/oxyplot/OxyPlot/Render/PlotRenderer.cs
new file mode 100644
index 0000000..b8b749c
--- /dev/null
+++ b/oxyplot/OxyPlot/Render/PlotRenderer.cs
@@ -0,0 +1,159 @@
+// 
--------------------------------------------------------------------------------------------------------------------
+// <copyright file="PlotRenderer.cs" company="OxyPlot">
+//   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.
+// </copyright>
+// 
--------------------------------------------------------------------------------------------------------------------
+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 --git a/oxyplot/OxyPlot/Render/RenderContextBase.cs b/oxyplot/OxyPlot/Render/RenderContextBase.cs
new file mode 100644
index 0000000..930b91d
--- /dev/null
+++ b/oxyplot/OxyPlot/Render/RenderContextBase.cs
@@ -0,0 +1,423 @@
+// 
--------------------------------------------------------------------------------------------------------------------
+// <copyright file="RenderContextBase.cs" company="OxyPlot">
+//   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.
+// </copyright>
+// <summary>
+//   The abstract render context base class.
+// </summary>
+// 
--------------------------------------------------------------------------------------------------------------------
+namespace OxyPlot
+{
+    using System.Collections.Generic;
+
+    /// <summary>
+    /// Provides an abstract base class for rendering contexts.
+    /// </summary>
+    public abstract class RenderContextBase : IRenderContext
+    {
+        /// <summary>
+        /// Initializes a new instance of the <see cref="RenderContextBase" /> class.
+        /// </summary>
+        protected RenderContextBase()
+        {
+            this.RendersToScreen = true;
+        }
+
+        /// <summary>
+        /// Gets or sets a value indicating whether the context renders to screen.
+        /// </summary>
+        /// <value>
+        /// <c>true</c> if the context renders to screen; otherwise, <c>false</c>.
+        /// </value>
+        public bool RendersToScreen { get; set; }
+
+        /// <summary>
+        /// Draws an ellipse.
+        /// </summary>
+        /// <param name="rect">
+        /// The rectangle.
+        /// </param>
+        /// <param name="fill">
+        /// The fill color.
+        /// </param>
+        /// <param name="stroke">
+        /// The stroke color.
+        /// </param>
+        /// <param name="thickness">
+        /// The thickness.
+        /// </param>
+        public abstract void DrawEllipse(OxyRect rect, OxyColor fill, OxyColor stroke, double thickness);
+
+        /// <summary>
+        /// Draws the collection of ellipses, where all have the same stroke and fill.
+        /// This performs better than calling DrawEllipse multiple times.
+        /// </summary>
+        /// <param name="rectangles">
+        /// The rectangles.
+        /// </param>
+        /// <param name="fill">
+        /// The fill color.
+        /// </param>
+        /// <param name="stroke">
+        /// The stroke color.
+        /// </param>
+        /// <param name="thickness">
+        /// The stroke thickness.
+        /// </param>
+        public virtual void DrawEllipses(IList<OxyRect> rectangles, OxyColor fill, OxyColor stroke, double 
thickness)
+        {
+            foreach (var r in rectangles)
+            {
+                this.DrawEllipse(r, fill, stroke, thickness);
+            }
+        }
+
+        /// <summary>
+        /// Draws the polyline from the specified points.
+        /// </summary>
+        /// <param name="points">
+        /// The points.
+        /// </param>
+        /// <param name="stroke">
+        /// The stroke color.
+        /// </param>
+        /// <param name="thickness">
+        /// The stroke thickness.
+        /// </param>
+        /// <param name="dashArray">
+        /// The dash array.
+        /// </param>
+        /// <param name="lineJoin">
+        /// The line join type.
+        /// </param>
+        /// <param name="aliased">
+        /// if set to <c>true</c> the shape will be aliased.
+        /// </param>
+        public abstract void DrawLine(
+            IList<ScreenPoint> points,
+            OxyColor stroke,
+            double thickness,
+            double[] dashArray,
+            OxyPenLineJoin lineJoin,
+            bool aliased);
+
+        /// <summary>
+        /// 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.
+        /// </summary>
+        /// <param name="points">
+        /// The points.
+        /// </param>
+        /// <param name="stroke">
+        /// The stroke color.
+        /// </param>
+        /// <param name="thickness">
+        /// The stroke thickness.
+        /// </param>
+        /// <param name="dashArray">
+        /// The dash array.
+        /// </param>
+        /// <param name="lineJoin">
+        /// The line join type.
+        /// </param>
+        /// <param name="aliased">
+        /// if set to <c>true</c> the shape will be aliased.
+        /// </param>
+        public virtual void DrawLineSegments(
+            IList<ScreenPoint> 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);
+            }
+        }
+
+        /// <summary>
+        /// Draws the polygon from the specified points. The polygon can have stroke and/or fill.
+        /// </summary>
+        /// <param name="points">
+        /// The points.
+        /// </param>
+        /// <param name="fill">
+        /// The fill color.
+        /// </param>
+        /// <param name="stroke">
+        /// The stroke color.
+        /// </param>
+        /// <param name="thickness">
+        /// The stroke thickness.
+        /// </param>
+        /// <param name="dashArray">
+        /// The dash array.
+        /// </param>
+        /// <param name="lineJoin">
+        /// The line join type.
+        /// </param>
+        /// <param name="aliased">
+        /// if set to <c>true</c> the shape will be aliased.
+        /// </param>
+        public abstract void DrawPolygon(
+            IList<ScreenPoint> points,
+            OxyColor fill,
+            OxyColor stroke,
+            double thickness,
+            double[] dashArray,
+            OxyPenLineJoin lineJoin,
+            bool aliased);
+
+        /// <summary>
+        /// Draws a collection of polygons, where all polygons have the same stroke and fill.
+        /// This performs better than calling DrawPolygon multiple times.
+        /// </summary>
+        /// <param name="polygons">
+        /// The polygons.
+        /// </param>
+        /// <param name="fill">
+        /// The fill color.
+        /// </param>
+        /// <param name="stroke">
+        /// The stroke color.
+        /// </param>
+        /// <param name="thickness">
+        /// The stroke thickness.
+        /// </param>
+        /// <param name="dashArray">
+        /// The dash array.
+        /// </param>
+        /// <param name="lineJoin">
+        /// The line join type.
+        /// </param>
+        /// <param name="aliased">
+        /// if set to <c>true</c> the shape will be aliased.
+        /// </param>
+        public virtual void DrawPolygons(
+            IList<IList<ScreenPoint>> 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);
+            }
+        }
+
+        /// <summary>
+        /// Draws the rectangle.
+        /// </summary>
+        /// <param name="rect">
+        /// The rectangle.
+        /// </param>
+        /// <param name="fill">
+        /// The fill color.
+        /// </param>
+        /// <param name="stroke">
+        /// The stroke color.
+        /// </param>
+        /// <param name="thickness">
+        /// The stroke thickness.
+        /// </param>
+        public abstract void DrawRectangle(OxyRect rect, OxyColor fill, OxyColor stroke, double thickness);
+
+        /// <summary>
+        /// Draws a collection of rectangles, where all have the same stroke and fill.
+        /// This performs better than calling DrawRectangle multiple times.
+        /// </summary>
+        /// <param name="rectangles">
+        /// The rectangles.
+        /// </param>
+        /// <param name="fill">
+        /// The fill color.
+        /// </param>
+        /// <param name="stroke">
+        /// The stroke color.
+        /// </param>
+        /// <param name="thickness">
+        /// The stroke thickness.
+        /// </param>
+        public virtual void DrawRectangles(IList<OxyRect> rectangles, OxyColor fill, OxyColor stroke, double 
thickness)
+        {
+            foreach (var r in rectangles)
+            {
+                this.DrawRectangle(r, fill, stroke, thickness);
+            }
+        }
+
+        /// <summary>
+        /// Draws the text.
+        /// </summary>
+        /// <param name="p">
+        /// The p.
+        /// </param>
+        /// <param name="text">
+        /// The text.
+        /// </param>
+        /// <param name="fill">
+        /// The fill color.
+        /// </param>
+        /// <param name="fontFamily">
+        /// The font family.
+        /// </param>
+        /// <param name="fontSize">
+        /// Size of the font.
+        /// </param>
+        /// <param name="fontWeight">
+        /// The font weight.
+        /// </param>
+        /// <param name="rotate">
+        /// The rotation angle.
+        /// </param>
+        /// <param name="halign">
+        /// The horizontal alignment.
+        /// </param>
+        /// <param name="valign">
+        /// The vertical alignment.
+        /// </param>
+        /// <param name="maxSize">
+        /// The maximum size of the text.
+        /// </param>
+        public abstract void DrawText(
+            ScreenPoint p,
+            string text,
+            OxyColor fill,
+            string fontFamily,
+            double fontSize,
+            double fontWeight,
+            double rotate,
+            HorizontalAlignment halign,
+            VerticalAlignment valign,
+            OxySize? maxSize);
+
+        /// <summary>
+        /// Measures the text.
+        /// </summary>
+        /// <param name="text">
+        /// The text.
+        /// </param>
+        /// <param name="fontFamily">
+        /// The font family.
+        /// </param>
+        /// <param name="fontSize">
+        /// Size of the font.
+        /// </param>
+        /// <param name="fontWeight">
+        /// The font weight.
+        /// </param>
+        /// <returns>
+        /// The text size.
+        /// </returns>
+        public abstract OxySize MeasureText(string text, string fontFamily, double fontSize, double 
fontWeight);
+
+        /// <summary>
+        /// Sets the tool tip for the following items.
+        /// </summary>
+        /// <param name="text">
+        /// The text in the tooltip.
+        /// </param>
+        /// <params>
+        /// This is only used in the plot controls.
+        /// </params>
+        public virtual void SetToolTip(string text)
+        {
+        }
+
+        /// <summary>
+        /// Cleans up resources not in use.
+        /// </summary>
+        /// <remarks>
+        /// This method is called at the end of each rendering.
+        /// </remarks>
+        public virtual void CleanUp()
+        {
+        }
+
+        /// <summary>
+        /// Gets the size of the specified image.
+        /// </summary>
+        /// <param name="source">The image source.</param>
+        /// <returns>
+        /// The image info.
+        /// </returns>
+        public virtual OxyImageInfo GetImageInfo(OxyImage source)
+        {
+            return null;
+        }
+
+        /// <summary>
+        /// Draws the image.
+        /// </summary>
+        /// <param name="source">The source.</param>
+        /// <param name="srcX">The SRC X.</param>
+        /// <param name="srcY">The SRC Y.</param>
+        /// <param name="srcWidth">Width of the SRC.</param>
+        /// <param name="srcHeight">Height of the SRC.</param>
+        /// <param name="x">The x.</param>
+        /// <param name="y">The y.</param>
+        /// <param name="w">The w.</param>
+        /// <param name="h">The h.</param>
+        /// <param name="opacity">The opacity.</param>
+        /// <param name="interpolate">interpolate if set to <c>true</c>.</param>
+        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)
+        {
+        }
+
+        /// <summary>
+        /// Sets the clip rectangle.
+        /// </summary>
+        /// <param name="rect">The clip rectangle.</param>
+        /// <returns>
+        /// True if the clip rectangle was set.
+        /// </returns>
+        public virtual bool SetClip(OxyRect rect)
+        {
+            return false;
+        }
+
+        /// <summary>
+        /// Resets the clip rectangle.
+        /// </summary>
+        public virtual void ResetClip()
+        {
+        }
+    }
+}
\ No newline at end of file
diff --git a/oxyplot/OxyPlot/Render/RenderingExtensions.cs b/oxyplot/OxyPlot/Render/RenderingExtensions.cs
new file mode 100644
index 0000000..85f50d3
--- /dev/null
+++ b/oxyplot/OxyPlot/Render/RenderingExtensions.cs
@@ -0,0 +1,1109 @@
+// 
--------------------------------------------------------------------------------------------------------------------
+// <copyright file="RenderingExtensions.cs" company="OxyPlot">
+//   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.
+// </copyright>
+// <summary>
+//   The rendering extensions.
+// </summary>
+// 
--------------------------------------------------------------------------------------------------------------------
+
+namespace OxyPlot
+{
+    using System;
+    using System.Collections.Generic;
+    using System.Linq;
+
+    /// <summary>
+    /// Provides extension methods for <see cref="IRenderContext"/>.
+    /// </summary>
+    public static class RenderingExtensions
+    {
+        /* Length constants used to draw triangles and stars
+                             ___
+         /\                   |
+         /  \                 |
+         /    \               | M2
+         /      \             |
+         /        \           |
+         /     +    \        ---
+         /            \       |
+         /              \     | M1
+         /________________\  _|_
+         |--------|-------|
+              1       1
+        
+                  |
+            \     |     /     ---
+              \   |   /        | M3
+                \ | /          |
+         ---------+--------   ---
+                / | \          | M3
+              /   |   \        |
+            /     |     \     ---
+                  |
+            |-----|-----|
+               M3    M3
+        */
+
+        /// <summary>
+        /// The vertical distance to the bottom points of the triangles.
+        /// </summary>
+        private static readonly double M1 = Math.Tan(Math.PI / 6);
+
+        /// <summary>
+        /// The vertical distance to the top points of the triangles .
+        /// </summary>
+        private static readonly double M2 = Math.Sqrt(1 + (M1 * M1));
+
+        /// <summary>
+        /// The horizontal/vertical distance to the end points of the stars.
+        /// </summary>
+        private static readonly double M3 = Math.Tan(Math.PI / 4);
+
+        /// <summary>
+        /// Draws the clipped line.
+        /// </summary>
+        /// <param name="rc">The render context.</param>
+        /// <param name="points">The points.</param>
+        /// <param name="clippingRectangle">The clipping rectangle.</param>
+        /// <param name="minDistSquared">The squared minimum distance.</param>
+        /// <param name="stroke">The stroke.</param>
+        /// <param name="strokeThickness">The stroke thickness.</param>
+        /// <param name="lineStyle">The line style.</param>
+        /// <param name="lineJoin">The line join.</param>
+        /// <param name="aliased">if set to <c>true</c> [aliased].</param>
+        /// <param name="pointsRendered">The points rendered callback.</param>
+        public static void DrawClippedLine(
+            this IRenderContext rc,
+            IList<ScreenPoint> points,
+            OxyRect clippingRectangle,
+            double minDistSquared,
+            OxyColor stroke,
+            double strokeThickness,
+            LineStyle lineStyle,
+            OxyPenLineJoin lineJoin,
+            bool aliased,
+            Action<IList<ScreenPoint>> pointsRendered = null)
+        {
+            var clipping = new CohenSutherlandClipping(clippingRectangle.Left, clippingRectangle.Right, 
clippingRectangle.Top, clippingRectangle.Bottom);
+
+            var pts = new List<ScreenPoint>();
+            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<ScreenPoint>();
+                        }
+                    }
+                }
+
+                if (pts.Count > 0)
+                {
+                    EnsureNonEmptyLineIsVisible(pts);
+                    rc.DrawLine(pts, stroke, strokeThickness, lineStyle.GetDashArray(), lineJoin, aliased);
+
+                    // Execute the 'callback'.
+                    if (pointsRendered != null)
+                    {
+                        pointsRendered(pts);
+                    }
+                }
+            }
+        }
+
+        /// <summary>
+        /// Draws the clipped line segments.
+        /// </summary>
+        /// <param name="rc">The render context.</param>
+        /// <param name="points">The points.</param>
+        /// <param name="clippingRectangle">The clipping rectangle.</param>
+        /// <param name="stroke">The stroke.</param>
+        /// <param name="strokeThickness">The stroke thickness.</param>
+        /// <param name="lineStyle">The line style.</param>
+        /// <param name="lineJoin">The line join.</param>
+        /// <param name="aliased">if set to <c>true</c> [aliased].</param>
+        public static void DrawClippedLineSegments(
+            this IRenderContext rc,
+            IList<ScreenPoint> 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<ScreenPoint>(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);
+        }
+
+        /// <summary>
+        /// Draws the specified image.
+        /// </summary>
+        /// <param name="rc">The render context.</param>
+        /// <param name="image">The image.</param>
+        /// <param name="x">The destination X position.</param>
+        /// <param name="y">The destination Y position.</param>
+        /// <param name="w">The width.</param>
+        /// <param name="h">The height.</param>
+        /// <param name="opacity">The opacity.</param>
+        /// <param name="interpolate">Interpolate the image if set to <c>true</c>.</param>
+        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);
+        }
+
+        /// <summary>
+        /// Draws the clipped image.
+        /// </summary>
+        /// <param name="rc">The render context.</param>
+        /// <param name="clippingRect">The clipping rectangle.</param>
+        /// <param name="source">The source.</param>
+        /// <param name="x">The destination X position.</param>
+        /// <param name="y">The destination Y position.</param>
+        /// <param name="w">The width.</param>
+        /// <param name="h">The height.</param>
+        /// <param name="opacity">The opacity.</param>
+        /// <param name="interpolate">interpolate if set to <c>true</c>.</param>
+        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);
+        }
+
+        /// <summary>
+        /// Draws the polygon within the specified clipping rectangle.
+        /// </summary>
+        /// <param name="rc">
+        /// The render context.
+        /// </param>
+        /// <param name="points">
+        /// The points.
+        /// </param>
+        /// <param name="clippingRectangle">
+        /// The clipping rectangle.
+        /// </param>
+        /// <param name="minDistSquared">
+        /// The squared minimum distance between points.
+        /// </param>
+        /// <param name="fill">
+        /// The fill.
+        /// </param>
+        /// <param name="stroke">
+        /// The stroke.
+        /// </param>
+        /// <param name="strokeThickness">
+        /// The stroke thickness.
+        /// </param>
+        /// <param name="lineStyle">
+        /// The line style.
+        /// </param>
+        /// <param name="lineJoin">
+        /// The line join.
+        /// </param>
+        /// <param name="aliased">
+        /// The aliased.
+        /// </param>
+        public static void DrawClippedPolygon(
+            this IRenderContext rc,
+            IList<ScreenPoint> 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);
+        }
+
+        /// <summary>
+        /// Draws the clipped rectangle.
+        /// </summary>
+        /// <param name="rc">
+        /// The render context.
+        /// </param>
+        /// <param name="rect">
+        /// The rectangle to draw.
+        /// </param>
+        /// <param name="clippingRectangle">
+        /// The clipping rectangle.
+        /// </param>
+        /// <param name="fill">
+        /// The fill color.
+        /// </param>
+        /// <param name="stroke">
+        /// The stroke color.
+        /// </param>
+        /// <param name="thickness">
+        /// The stroke thickness.
+        /// </param>
+        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);
+        }
+
+        /// <summary>
+        /// Draws the clipped rectangle as a polygon.
+        /// </summary>
+        /// <param name="rc">
+        /// The render context.
+        /// </param>
+        /// <param name="rect">
+        /// The rectangle to draw.
+        /// </param>
+        /// <param name="clippingRectangle">
+        /// The clipping rectangle.
+        /// </param>
+        /// <param name="fill">
+        /// The fill color.
+        /// </param>
+        /// <param name="stroke">
+        /// The stroke color.
+        /// </param>
+        /// <param name="thickness">
+        /// The stroke thickness.
+        /// </param>
+        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);
+        }
+
+        /// <summary>
+        /// Draws a clipped ellipse.
+        /// </summary>
+        /// <param name="rc">The render context.</param>
+        /// <param name="clippingRectangle">The clipping rectangle.</param>
+        /// <param name="rect">The rectangle.</param>
+        /// <param name="fill">The fill color.</param>
+        /// <param name="stroke">The stroke color.</param>
+        /// <param name="thickness">The stroke thickness.</param>
+        /// <param name="n">The number of points around the ellipse.</param>
+        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);
+        }
+
+        /// <summary>
+        /// Draws the clipped text.
+        /// </summary>
+        /// <param name="rc">The rendering context.</param>
+        /// <param name="clippingRectangle">The clipping rectangle.</param>
+        /// <param name="p">The position.</param>
+        /// <param name="text">The text.</param>
+        /// <param name="fill">The fill color.</param>
+        /// <param name="fontFamily">The font family.</param>
+        /// <param name="fontSize">Size of the font.</param>
+        /// <param name="fontWeight">The font weight.</param>
+        /// <param name="rotate">The rotation angle.</param>
+        /// <param name="horizontalAlignment">The horizontal align.</param>
+        /// <param name="verticalAlignment">The vertical align.</param>
+        /// <param name="maxSize">Size of the max.</param>
+        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);
+            }
+        }
+
+        /// <summary>
+        /// Draws a line specified by coordinates.
+        /// </summary>
+        /// <param name="rc">
+        /// The render context.
+        /// </param>
+        /// <param name="x0">
+        /// The x0.
+        /// </param>
+        /// <param name="y0">
+        /// The y0.
+        /// </param>
+        /// <param name="x1">
+        /// The x1.
+        /// </param>
+        /// <param name="y1">
+        /// The y1.
+        /// </param>
+        /// <param name="pen">
+        /// The pen.
+        /// </param>
+        /// <param name="aliased">
+        /// Aliased line if set to <c>true</c>.
+        /// </param>
+        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);
+        }
+
+        /// <summary>
+        /// Draws the line segments.
+        /// </summary>
+        /// <param name="rc">
+        /// The render context.
+        /// </param>
+        /// <param name="points">
+        /// The points.
+        /// </param>
+        /// <param name="pen">
+        /// The pen.
+        /// </param>
+        /// <param name="aliased">
+        /// if set to <c>true</c> [aliased].
+        /// </param>
+        public static void DrawLineSegments(
+            this IRenderContext rc, IList<ScreenPoint> points, OxyPen pen, bool aliased = true)
+        {
+            if (pen == null)
+            {
+                return;
+            }
+
+            rc.DrawLineSegments(points, pen.Color, pen.Thickness, pen.DashArray, pen.LineJoin, aliased);
+        }
+
+        /// <summary>
+        /// Renders the marker.
+        /// </summary>
+        /// <param name="rc">The render context.</param>
+        /// <param name="p">The center point of the marker.</param>
+        /// <param name="clippingRect">The clipping rectangle.</param>
+        /// <param name="type">The marker type.</param>
+        /// <param name="outline">The outline.</param>
+        /// <param name="size">The size of the marker.</param>
+        /// <param name="fill">The fill color.</param>
+        /// <param name="stroke">The stroke color.</param>
+        /// <param name="strokeThickness">The stroke thickness.</param>
+        public static void DrawMarker(
+            this IRenderContext rc,
+            ScreenPoint p,
+            OxyRect clippingRect,
+            MarkerType type,
+            IList<ScreenPoint> outline,
+            double size,
+            OxyColor fill,
+            OxyColor stroke,
+            double strokeThickness)
+        {
+            rc.DrawMarkers(new[] { p }, clippingRect, type, outline, new[] { size }, fill, stroke, 
strokeThickness);
+        }
+
+        /// <summary>
+        /// Draws a list of markers.
+        /// </summary>
+        /// <param name="rc">
+        /// The render context.
+        /// </param>
+        /// <param name="markerPoints">
+        /// The marker points.
+        /// </param>
+        /// <param name="clippingRect">
+        /// The clipping rectangle.
+        /// </param>
+        /// <param name="markerType">
+        /// Type of the marker.
+        /// </param>
+        /// <param name="markerOutline">
+        /// The marker outline.
+        /// </param>
+        /// <param name="markerSize">
+        /// Size of the marker.
+        /// </param>
+        /// <param name="markerFill">
+        /// The marker fill.
+        /// </param>
+        /// <param name="markerStroke">
+        /// The marker stroke.
+        /// </param>
+        /// <param name="markerStrokeThickness">
+        /// The marker stroke thickness.
+        /// </param>
+        /// <param name="resolution">
+        /// The resolution.
+        /// </param>
+        /// <param name="binOffset">
+        /// The bin Offset.
+        /// </param>
+        public static void DrawMarkers(
+            this IRenderContext rc,
+            IList<ScreenPoint> markerPoints,
+            OxyRect clippingRect,
+            MarkerType markerType,
+            IList<ScreenPoint> 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);
+        }
+
+        /// <summary>
+        /// Draws a list of markers.
+        /// </summary>
+        /// <param name="rc">
+        /// The render context.
+        /// </param>
+        /// <param name="markerPoints">
+        /// The marker points.
+        /// </param>
+        /// <param name="clippingRect">
+        /// The clipping rectangle.
+        /// </param>
+        /// <param name="markerType">
+        /// Type of the marker.
+        /// </param>
+        /// <param name="markerOutline">
+        /// The marker outline.
+        /// </param>
+        /// <param name="markerSize">
+        /// Size of the markers.
+        /// </param>
+        /// <param name="markerFill">
+        /// The marker fill.
+        /// </param>
+        /// <param name="markerStroke">
+        /// The marker stroke.
+        /// </param>
+        /// <param name="markerStrokeThickness">
+        /// The marker stroke thickness.
+        /// </param>
+        /// <param name="resolution">
+        /// The resolution.
+        /// </param>
+        /// <param name="binOffset">
+        /// The bin Offset.
+        /// </param>
+        public static void DrawMarkers(
+            this IRenderContext rc,
+            IList<ScreenPoint> markerPoints,
+            OxyRect clippingRect,
+            MarkerType markerType,
+            IList<ScreenPoint> markerOutline,
+            IList<double> 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<OxyRect>(n);
+            var rects = new List<OxyRect>(n);
+            var polygons = new List<IList<ScreenPoint>>(n);
+            var lines = new List<ScreenPoint>(n);
+
+            var hashset = new Dictionary<uint, bool>();
+
+            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);
+            }
+        }
+
+        /// <summary>
+        /// Draws the rectangle as an aliased polygon.
+        /// (makes sure pixel alignment is the same as for lines)
+        /// </summary>
+        /// <param name="rc">
+        /// The render context.
+        /// </param>
+        /// <param name="rect">
+        /// The rectangle.
+        /// </param>
+        /// <param name="fill">
+        /// The fill.
+        /// </param>
+        /// <param name="stroke">
+        /// The stroke.
+        /// </param>
+        /// <param name="thickness">
+        /// The thickness.
+        /// </param>
+        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);
+        }
+
+        /// <summary>
+        /// Draws the rectangle as an aliased polygon.
+        /// (makes sure pixel alignment is the same as for lines)
+        /// </summary>
+        /// <param name="rc">
+        /// The render context.
+        /// </param>
+        /// <param name="rect">
+        /// The rectangle.
+        /// </param>
+        /// <param name="fill">
+        /// The fill.
+        /// </param>
+        /// <param name="stroke">
+        /// The stroke.
+        /// </param>
+        /// <param name="thickness">
+        /// The thickness.
+        /// </param>
+        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);
+        }
+
+        /// <summary>
+        /// Adds a marker geometry.
+        /// </summary>
+        /// <param name="p">
+        /// The position of the marker.
+        /// </param>
+        /// <param name="type">
+        /// The type.
+        /// </param>
+        /// <param name="outline">
+        /// The outline.
+        /// </param>
+        /// <param name="size">
+        /// The size.
+        /// </param>
+        /// <param name="ellipses">
+        /// The ellipse collection.
+        /// </param>
+        /// <param name="rects">
+        /// The rectangle collection.
+        /// </param>
+        /// <param name="polygons">
+        /// The polygon collection.
+        /// </param>
+        /// <param name="lines">
+        /// The line collection.
+        /// </param>
+        private static void AddMarkerGeometry(
+            ScreenPoint p,
+            MarkerType type,
+            IEnumerable<ScreenPoint> outline,
+            double size,
+            IList<OxyRect> ellipses,
+            IList<OxyRect> rects,
+            IList<IList<ScreenPoint>> polygons,
+            IList<ScreenPoint> 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;
+                    }
+            }
+        }
+
+        /// <summary>
+        /// Calculates the clipped version of a rectangle.
+        /// </summary>
+        /// <param name="rect">
+        /// The rectangle to clip.
+        /// </param>
+        /// <param name="clippingRectangle">
+        /// The clipping rectangle.
+        /// </param>
+        /// <returns>
+        /// The clipped rectangle, or null if the rectangle is outside the clipping area.
+        /// </returns>
+        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;
+        }
+
+        /// <summary>
+        /// Makes sure that a non empty line is visible.
+        /// </summary>
+        /// <param name="pts">The points (screen coordinates).</param>
+        /// <remarks>
+        /// 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.
+        /// </remarks>
+        private static void EnsureNonEmptyLineIsVisible(IList<ScreenPoint> 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 --git a/oxyplot/OxyPlot/Render/VerticalAxisRenderer.cs b/oxyplot/OxyPlot/Render/VerticalAxisRenderer.cs
new file mode 100644
index 0000000..77ec36e
--- /dev/null
+++ b/oxyplot/OxyPlot/Render/VerticalAxisRenderer.cs
@@ -0,0 +1,318 @@
+// 
--------------------------------------------------------------------------------------------------------------------
+// <copyright file="VerticalAxisRenderer.cs" company="OxyPlot">
+//   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.
+// </copyright>
+// <summary>
+//   Gets the rotated alignments given the specified angle.
+// </summary>
+// 
--------------------------------------------------------------------------------------------------------------------
+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);
+            }
+        }
+
+        /// <summary>
+        /// Gets the rotated alignments given the specified angle.
+        /// </summary>
+        /// <param name="angle">The angle.</param>
+        /// <param name="defaultHorizontalAlignment">The default horizontal alignment.</param>
+        /// <param name="defaultVerticalAlignment">The default vertical alignment.</param>
+        /// <param name="ha">The rotated horizontal alignment.</param>
+        /// <param name="va">The rotated vertical alignment.</param>
+        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 --git a/oxyplot/OxyPlot/Reporting/NamespaceDoc.cs b/oxyplot/OxyPlot/Reporting/NamespaceDoc.cs
new file mode 100644
index 0000000..8c9173b
--- /dev/null
+++ b/oxyplot/OxyPlot/Reporting/NamespaceDoc.cs
@@ -0,0 +1,39 @@
+// 
--------------------------------------------------------------------------------------------------------------------
+// <copyright file="NamespaceDoc.cs" company="OxyPlot">
+//   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.
+// </copyright>
+// 
--------------------------------------------------------------------------------------------------------------------
+
+namespace OxyPlot.Reporting
+{
+    using System.Runtime.CompilerServices;
+
+    /// <summary>
+    ///     The OxyPlot.Reporting namespace contains a simple report model.
+    /// </summary>
+    [CompilerGenerated]
+    internal class NamespaceDoc
+    {
+    }
+}
\ No newline at end of file
diff --git a/oxyplot/OxyPlot/Reporting/Report/Content.cs b/oxyplot/OxyPlot/Reporting/Report/Content.cs
new file mode 100644
index 0000000..162e526
--- /dev/null
+++ b/oxyplot/OxyPlot/Reporting/Report/Content.cs
@@ -0,0 +1,75 @@
+// 
--------------------------------------------------------------------------------------------------------------------
+// <copyright file="Content.cs" company="OxyPlot">
+//   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.
+// </copyright>
+// 
--------------------------------------------------------------------------------------------------------------------
+using System.Collections.Generic;
+
+namespace OxyPlot.Reporting
+{
+    public class Content : Table
+    {
+        public List<ContentItem> Contents { get; set; }
+        public ReportItem Base { get; set; }
+
+        public Content(ReportItem b)
+        {
+            this.Base = b;
+            Class = "content";
+            Contents = new List<ContentItem>();
+            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 --git a/oxyplot/OxyPlot/Reporting/Report/Drawing.cs b/oxyplot/OxyPlot/Reporting/Report/Drawing.cs
new file mode 100644
index 0000000..66bb42b
--- /dev/null
+++ b/oxyplot/OxyPlot/Reporting/Report/Drawing.cs
@@ -0,0 +1,46 @@
+// 
--------------------------------------------------------------------------------------------------------------------
+// <copyright file="Drawing.cs" company="OxyPlot">
+//   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.
+// </copyright>
+// <summary>
+//   Drawing currently only supports SVG format.
+// </summary>
+// 
--------------------------------------------------------------------------------------------------------------------
+namespace OxyPlot.Reporting
+{
+    /// <summary>
+    /// Drawing currently only supports SVG format.
+    /// </summary>
+    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 --git a/oxyplot/OxyPlot/Reporting/Report/DrawingFigure.cs 
b/oxyplot/OxyPlot/Reporting/Report/DrawingFigure.cs
new file mode 100644
index 0000000..d72cdad
--- /dev/null
+++ b/oxyplot/OxyPlot/Reporting/Report/DrawingFigure.cs
@@ -0,0 +1,73 @@
+// 
--------------------------------------------------------------------------------------------------------------------
+// <copyright file="DrawingFigure.cs" company="OxyPlot">
+//   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.
+// </copyright>
+// <summary>
+//   Represents a drawing report item.
+// </summary>
+// 
--------------------------------------------------------------------------------------------------------------------
+namespace OxyPlot.Reporting
+{
+    /// <summary>
+    /// Represents a drawing report item.
+    /// </summary>
+    /// <remarks>
+    /// Drawing currently only supports SVG format.
+    /// </remarks>
+    public class DrawingFigure : Figure
+    {
+        /// <summary>
+        /// The drawing format.
+        /// </summary>
+        public enum DrawingFormat
+        {
+            /// <summary>
+            /// The svg.
+            /// </summary>
+            Svg
+        }
+
+        /// <summary>
+        /// Gets or sets Content.
+        /// </summary>
+        public string Content { get; set; }
+
+        /// <summary>
+        /// Gets or sets Format.
+        /// </summary>
+        public DrawingFormat Format { get; set; }
+
+        /// <summary>
+        /// The write content.
+        /// </summary>
+        /// <param name="w">
+        /// The w.
+        /// </param>
+        public override void WriteContent(IReportWriter w)
+        {
+            w.WriteDrawing(this);
+        }
+
+    }
+}
\ No newline at end of file
diff --git a/oxyplot/OxyPlot/Reporting/Report/Equation.cs b/oxyplot/OxyPlot/Reporting/Report/Equation.cs
new file mode 100644
index 0000000..efa7eb4
--- /dev/null
+++ b/oxyplot/OxyPlot/Reporting/Report/Equation.cs
@@ -0,0 +1,59 @@
+// 
--------------------------------------------------------------------------------------------------------------------
+// <copyright file="Equation.cs" company="OxyPlot">
+//   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.
+// </copyright>
+// <summary>
+//   Represents an equation.
+// </summary>
+// 
--------------------------------------------------------------------------------------------------------------------
+namespace OxyPlot.Reporting
+{
+    /// <summary>
+    /// Represents an equation.
+    /// </summary>
+    public class Equation : ReportItem
+    {
+        /// <summary>
+        /// Gets or sets Caption.
+        /// </summary>
+        public string Caption { get; set; }
+
+        /// <summary>
+        /// Gets or sets Content.
+        /// </summary>
+        public string Content { get; set; }
+
+        /// <summary>
+        /// The write content.
+        /// </summary>
+        /// <param name="w">
+        /// The w.
+        /// </param>
+        public override void WriteContent(IReportWriter w)
+        {
+            w.WriteEquation(this);
+        }
+
+    }
+}
\ No newline at end of file
diff --git a/oxyplot/OxyPlot/Reporting/Report/Figure.cs b/oxyplot/OxyPlot/Reporting/Report/Figure.cs
new file mode 100644
index 0000000..30c4ecc
--- /dev/null
+++ b/oxyplot/OxyPlot/Reporting/Report/Figure.cs
@@ -0,0 +1,62 @@
+// 
--------------------------------------------------------------------------------------------------------------------
+// <copyright file="Figure.cs" company="OxyPlot">
+//   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.
+// </copyright>
+// <summary>
+//   Represents a figure (abstract base class for DrawingFigure, Image and PlotFigure).
+// </summary>
+// 
--------------------------------------------------------------------------------------------------------------------
+namespace OxyPlot.Reporting
+{
+    /// <summary>
+    /// Represents a figure (abstract base class for DrawingFigure, Image and PlotFigure).
+    /// </summary>
+    public abstract class Figure : ReportItem
+    {
+        /// <summary>
+        /// Gets or sets FigureNumber.
+        /// </summary>
+        public int FigureNumber { get; set; }
+
+        /// <summary>
+        /// Gets or sets FigureText.
+        /// </summary>
+        public string FigureText { get; set; }
+
+        /// <summary>
+        /// The get full caption.
+        /// </summary>
+        /// <param name="style">
+        /// The style.
+        /// </param>
+        /// <returns>
+        /// The get full caption.
+        /// </returns>
+        public string GetFullCaption(ReportStyle style)
+        {
+            return string.Format(style.FigureTextFormatString, this.FigureNumber, this.FigureText);
+        }
+
+    }
+}
\ No newline at end of file
diff --git a/oxyplot/OxyPlot/Reporting/Report/Header.cs b/oxyplot/OxyPlot/Reporting/Report/Header.cs
new file mode 100644
index 0000000..39a2c69
--- /dev/null
+++ b/oxyplot/OxyPlot/Reporting/Report/Header.cs
@@ -0,0 +1,82 @@
+// 
--------------------------------------------------------------------------------------------------------------------
+// <copyright file="Header.cs" company="OxyPlot">
+//   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.
+// </copyright>
+// <summary>
+//   Represents a header.
+// </summary>
+// 
--------------------------------------------------------------------------------------------------------------------
+namespace OxyPlot.Reporting
+{
+    /// <summary>
+    /// Represents a header.
+    /// </summary>
+    public class Header : ReportItem
+    {
+        /// <summary>
+        /// Gets or sets the chapter number(s).
+        /// </summary>
+        public string Chapter { get; set; }
+
+        /// <summary>
+        /// Gets or sets the level of the header (1-5).
+        /// </summary>
+        public int Level { get; set; }
+
+        /// <summary>
+        /// Gets or sets the header text.
+        /// </summary>
+        public string Text { get; set; }
+
+        /// <summary>
+        /// The to string.
+        /// </summary>
+        /// <returns>
+        /// The to string.
+        /// </returns>
+        public override string ToString()
+        {
+            string h = string.Empty;
+            if (this.Chapter != null)
+            {
+                h += this.Chapter + " ";
+            }
+
+            h += this.Text;
+            return h;
+        }
+
+        /// <summary>
+        /// The write content.
+        /// </summary>
+        /// <param name="w">
+        /// The w.
+        /// </param>
+        public override void WriteContent(IReportWriter w)
+        {
+            w.WriteHeader(this);
+        }
+
+    }
+}
\ No newline at end of file
diff --git a/oxyplot/OxyPlot/Reporting/Report/HeaderHelper.cs 
b/oxyplot/OxyPlot/Reporting/Report/HeaderHelper.cs
new file mode 100644
index 0000000..50989c8
--- /dev/null
+++ b/oxyplot/OxyPlot/Reporting/Report/HeaderHelper.cs
@@ -0,0 +1,82 @@
+// 
--------------------------------------------------------------------------------------------------------------------
+// <copyright file="HeaderHelper.cs" company="OxyPlot">
+//   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.
+// </copyright>
+// <summary>
+//   The header helper.
+// </summary>
+// 
--------------------------------------------------------------------------------------------------------------------
+namespace OxyPlot.Reporting
+{
+    /// <summary>
+    /// The header helper.
+    /// </summary>
+    public class HeaderHelper
+    {
+        /// <summary>
+        /// The header level.
+        /// </summary>
+        private readonly int[] headerLevel = new int[10];
+
+        /// <summary>
+        /// The get header.
+        /// </summary>
+        /// <param name="level">
+        /// The level.
+        /// </param>
+        /// <returns>
+        /// The get header.
+        /// </returns>
+        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 --git a/oxyplot/OxyPlot/Reporting/Report/Image.cs b/oxyplot/OxyPlot/Reporting/Report/Image.cs
new file mode 100644
index 0000000..d6140d6
--- /dev/null
+++ b/oxyplot/OxyPlot/Reporting/Report/Image.cs
@@ -0,0 +1,54 @@
+// 
--------------------------------------------------------------------------------------------------------------------
+// <copyright file="Image.cs" company="OxyPlot">
+//   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.
+// </copyright>
+// <summary>
+//   Represents an image report item.
+// </summary>
+// 
--------------------------------------------------------------------------------------------------------------------
+namespace OxyPlot.Reporting
+{
+    /// <summary>
+    /// Represents an image report item.
+    /// </summary>
+    public class Image : Figure
+    {
+        /// <summary>
+        /// Gets or sets Source.
+        /// </summary>
+        public string Source { get; set; }
+
+        /// <summary>
+        /// The write content.
+        /// </summary>
+        /// <param name="w">
+        /// The w.
+        /// </param>
+        public override void WriteContent(IReportWriter w)
+        {
+            w.WriteImage(this);
+        }
+
+    }
+}
\ No newline at end of file
diff --git a/oxyplot/OxyPlot/Reporting/Report/ItemsTable.cs b/oxyplot/OxyPlot/Reporting/Report/ItemsTable.cs
new file mode 100644
index 0000000..e14eb6f
--- /dev/null
+++ b/oxyplot/OxyPlot/Reporting/Report/ItemsTable.cs
@@ -0,0 +1,243 @@
+// 
--------------------------------------------------------------------------------------------------------------------
+// <copyright file="ItemsTable.cs" company="OxyPlot">
+//   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.
+// </copyright>
+// <summary>
+//   Represents a table of items.
+// </summary>
+// 
--------------------------------------------------------------------------------------------------------------------
+namespace OxyPlot.Reporting
+{
+    using System.Collections;
+    using System.Collections.Generic;
+    using System.Diagnostics;
+    using System.Linq;
+
+    /// <summary>
+    /// Represents a table of items.
+    /// </summary>
+    public class ItemsTable : Table
+    {
+        /// <summary>
+        /// Initializes a new instance of the <see cref="ItemsTable"/> class.
+        /// </summary>
+        /// <param name="itemsInRows">
+        /// The items in rows.
+        /// </param>
+        public ItemsTable(bool itemsInRows = true)
+        {
+            this.Fields = new List<ItemsTableField>();
+            this.ItemsInRows = itemsInRows;
+            this.Alignment = Alignment.Center;
+        }
+
+        /// <summary>
+        /// Gets or sets Alignment.
+        /// </summary>
+        public Alignment Alignment { get; set; }
+
+        /// <summary>
+        /// Gets or sets Fields.
+        /// </summary>
+        public IList<ItemsTableField> Fields { get; set; }
+
+        /// <summary>
+        /// Gets or sets the items.
+        /// The table will be filled when this property is set.
+        /// </summary>
+        /// <value>The items.</value>
+        public IEnumerable Items { get; set; }
+
+        /// <summary>
+        /// Gets a value indicating whether ItemsInRows.
+        /// </summary>
+        public bool ItemsInRows { get; private set; }
+
+        /// <summary>
+        /// The has header.
+        /// </summary>
+        /// <returns>
+        /// The has header.
+        /// </returns>
+        public bool HasHeader()
+        {
+            foreach (var c in this.Fields)
+            {
+                if (c.Header != null)
+                {
+                    return true;
+                }
+            }
+
+            return false;
+        }
+
+        /// <summary>
+        /// The to array.
+        /// </summary>
+        /// <returns>
+        /// </returns>
+        public string[,] ToArray()
+        {
+            List<object> items = this.Items.Cast<object>().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;
+        }
+
+        /// <summary>
+        /// The update.
+        /// </summary>
+        public override void Update()
+        {
+            base.Update();
+            this.UpdateItems();
+        }
+
+        /// <summary>
+        /// The update items.
+        /// </summary>
+        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);
+            }
+        }
+
+        /// <summary>
+        /// Writes the content of the item.
+        /// </summary>
+        /// <param name="w">
+        /// The writer.
+        /// </param>
+        public override void WriteContent(IReportWriter w)
+        {
+            w.WriteTable(this);
+        }
+
+        /// <summary>
+        /// The transpose.
+        /// </summary>
+        /// <param name="input">
+        /// The input.
+        /// </param>
+        /// <returns>
+        /// </returns>
+        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 --git a/oxyplot/OxyPlot/Reporting/Report/ItemsTableField.cs 
b/oxyplot/OxyPlot/Reporting/Report/ItemsTableField.cs
new file mode 100644
index 0000000..9c041d4
--- /dev/null
+++ b/oxyplot/OxyPlot/Reporting/Report/ItemsTableField.cs
@@ -0,0 +1,136 @@
+// 
--------------------------------------------------------------------------------------------------------------------
+// <copyright file="ItemsTableField.cs" company="OxyPlot">
+//   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.
+// </copyright>
+// <summary>
+//   The alignment.
+// </summary>
+// 
--------------------------------------------------------------------------------------------------------------------
+namespace OxyPlot.Reporting
+{
+    using System;
+    using System.Reflection;
+
+    /// <summary>
+    /// The alignment.
+    /// </summary>
+    public enum Alignment
+    {
+        /// <summary>
+        /// The left.
+        /// </summary>
+        Left,
+
+        /// <summary>
+        /// The right.
+        /// </summary>
+        Right,
+
+        /// <summary>
+        /// The center.
+        /// </summary>
+        Center
+    }
+
+    /// <summary>
+    /// Represents a field in an items table.
+    /// </summary>
+    public class ItemsTableField
+    {
+        /// <summary>
+        /// Initializes a new instance of the <see cref="ItemsTableField"/> class.
+        /// </summary>
+        /// <param name="header">
+        /// The header.
+        /// </param>
+        /// <param name="path">
+        /// The path.
+        /// </param>
+        /// <param name="stringFormat">
+        /// The string format.
+        /// </param>
+        /// <param name="alignment">
+        /// The alignment.
+        /// </param>
+        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;
+        }
+
+        /// <summary>
+        /// Gets or sets Alignment.
+        /// </summary>
+        public Alignment Alignment { get; set; }
+
+        /// <summary>
+        /// Gets or sets Header.
+        /// </summary>
+        public string Header { get; set; }
+
+        /// <summary>
+        /// Gets or sets Path.
+        /// </summary>
+        public string Path { get; set; }
+
+        /// <summary>
+        /// Gets or sets StringFormat.
+        /// </summary>
+        public string StringFormat { get; set; }
+
+        /// <summary>
+        /// Gets or sets Width.
+        /// </summary>
+        public double Width { get; set; }
+
+        /// <summary>
+        /// Gets the text.
+        /// </summary>
+        /// <param name="item">
+        /// The item.
+        /// </param>
+        /// <param name="formatProvider">
+        /// The format provider.
+        /// </param>
+        /// <returns>
+        /// The text.
+        /// </returns>
+        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 --git a/oxyplot/OxyPlot/Reporting/Report/Paragraph.cs b/oxyplot/OxyPlot/Reporting/Report/Paragraph.cs
new file mode 100644
index 0000000..90634ab
--- /dev/null
+++ b/oxyplot/OxyPlot/Reporting/Report/Paragraph.cs
@@ -0,0 +1,54 @@
+// 
--------------------------------------------------------------------------------------------------------------------
+// <copyright file="Paragraph.cs" company="OxyPlot">
+//   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.
+// </copyright>
+// <summary>
+//   Represents a paragraph.
+// </summary>
+// 
--------------------------------------------------------------------------------------------------------------------
+namespace OxyPlot.Reporting
+{
+    /// <summary>
+    /// Represents a paragraph.
+    /// </summary>
+    public class Paragraph : ReportItem
+    {
+        /// <summary>
+        /// Gets or sets Text.
+        /// </summary>
+        public string Text { get; set; }
+
+        /// <summary>
+        /// The write content.
+        /// </summary>
+        /// <param name="w">
+        /// The w.
+        /// </param>
+        public override void WriteContent(IReportWriter w)
+        {
+            w.WriteParagraph(this);
+        }
+
+    }
+}
\ No newline at end of file
diff --git a/oxyplot/OxyPlot/Reporting/Report/ParagraphStyle.cs 
b/oxyplot/OxyPlot/Reporting/Report/ParagraphStyle.cs
new file mode 100644
index 0000000..450404a
--- /dev/null
+++ b/oxyplot/OxyPlot/Reporting/Report/ParagraphStyle.cs
@@ -0,0 +1,397 @@
+// 
--------------------------------------------------------------------------------------------------------------------
+// <copyright file="ParagraphStyle.cs" company="OxyPlot">
+//   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.
+// </copyright>
+// <summary>
+//   The paragraph style.
+// </summary>
+// 
--------------------------------------------------------------------------------------------------------------------
+namespace OxyPlot.Reporting
+{
+    /// <summary>
+    /// The paragraph style.
+    /// </summary>
+    public class ParagraphStyle
+    {
+        /// <summary>
+        /// The default font.
+        /// </summary>
+        private const string DefaultFont = "Arial";
+
+        /// <summary>
+        /// The default font size.
+        /// </summary>
+        private const double DefaultFontSize = 11;
+
+        /// <summary>
+        /// The bold.
+        /// </summary>
+        private bool? bold;
+
+        /// <summary>
+        /// The font family.
+        /// </summary>
+        private string fontFamily;
+
+        /// <summary>
+        /// The font size.
+        /// </summary>
+        private double? fontSize;
+
+        /// <summary>
+        /// The italic.
+        /// </summary>
+        private bool? italic;
+
+        /// <summary>
+        /// The left indentation.
+        /// </summary>
+        private double? leftIndentation;
+
+        /// <summary>
+        /// The line spacing.
+        /// </summary>
+        private double? lineSpacing;
+
+        /// <summary>
+        /// The page break before.
+        /// </summary>
+        private bool? pageBreakBefore;
+
+        /// <summary>
+        /// The right indentation.
+        /// </summary>
+        private double? rightIndentation;
+
+        /// <summary>
+        /// The spacing after.
+        /// </summary>
+        private double? spacingAfter;
+
+        /// <summary>
+        /// The spacing before.
+        /// </summary>
+        private double? spacingBefore;
+
+        /// <summary>
+        /// The text color.
+        /// </summary>
+        private OxyColor textColor;
+
+        /// <summary>
+        /// Gets or sets BasedOn.
+        /// </summary>
+        public ParagraphStyle BasedOn { get; set; }
+
+        /// <summary>
+        /// Gets or sets a value indicating whether Bold.
+        /// </summary>
+        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;
+            }
+        }
+
+        /// <summary>
+        /// Gets or sets FontFamily.
+        /// </summary>
+        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;
+            }
+        }
+
+        /// <summary>
+        /// Gets or sets FontSize.
+        /// </summary>
+        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;
+            }
+        }
+
+        /// <summary>
+        /// Gets or sets a value indicating whether Italic.
+        /// </summary>
+        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;
+            }
+        }
+
+        /// <summary>
+        /// Gets or sets LeftIndentation.
+        /// </summary>
+        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;
+            }
+        }
+
+        /// <summary>
+        /// Gets or sets LineSpacing.
+        /// </summary>
+        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;
+            }
+        }
+
+        /// <summary>
+        /// Gets or sets a value indicating whether PageBreakBefore.
+        /// </summary>
+        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;
+            }
+        }
+
+        /// <summary>
+        /// Gets or sets RightIndentation.
+        /// </summary>
+        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;
+            }
+        }
+
+        /// <summary>
+        /// Gets or sets SpacingAfter.
+        /// </summary>
+        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;
+            }
+        }
+
+        /// <summary>
+        /// Gets or sets SpacingBefore.
+        /// </summary>
+        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;
+            }
+        }
+
+        /// <summary>
+        /// Gets or sets TextColor.
+        /// </summary>
+        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 --git a/oxyplot/OxyPlot/Reporting/Report/Plot.cs b/oxyplot/OxyPlot/Reporting/Report/Plot.cs
new file mode 100644
index 0000000..7dc0d3f
--- /dev/null
+++ b/oxyplot/OxyPlot/Reporting/Report/Plot.cs
@@ -0,0 +1,40 @@
+// 
--------------------------------------------------------------------------------------------------------------------
+// <copyright file="Plot.cs" company="OxyPlot">
+//   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.
+// </copyright>
+// 
--------------------------------------------------------------------------------------------------------------------
+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 --git a/oxyplot/OxyPlot/Reporting/Report/PlotFigure.cs b/oxyplot/OxyPlot/Reporting/Report/PlotFigure.cs
new file mode 100644
index 0000000..8c2ce9b
--- /dev/null
+++ b/oxyplot/OxyPlot/Reporting/Report/PlotFigure.cs
@@ -0,0 +1,64 @@
+// 
--------------------------------------------------------------------------------------------------------------------
+// <copyright file="PlotFigure.cs" company="OxyPlot">
+//   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.
+// </copyright>
+// <summary>
+//   Represents a plot figure.
+// </summary>
+// 
--------------------------------------------------------------------------------------------------------------------
+namespace OxyPlot.Reporting
+{
+    /// <summary>
+    /// Represents a plot figure.
+    /// </summary>
+    public class PlotFigure : Figure
+    {
+        /// <summary>
+        /// Gets or sets Height.
+        /// </summary>
+        public double Height { get; set; }
+
+        /// <summary>
+        /// Gets or sets PlotModel.
+        /// </summary>
+        public PlotModel PlotModel { get; set; }
+
+        /// <summary>
+        /// Gets or sets Width.
+        /// </summary>
+        public double Width { get; set; }
+
+        /// <summary>
+        /// The write content.
+        /// </summary>
+        /// <param name="w">
+        /// The w.
+        /// </param>
+        public override void WriteContent(IReportWriter w)
+        {
+            w.WritePlot(this);
+        }
+
+    }
+}
\ No newline at end of file
diff --git a/oxyplot/OxyPlot/Reporting/Report/PropertyTable.cs 
b/oxyplot/OxyPlot/Reporting/Report/PropertyTable.cs
new file mode 100644
index 0000000..0111197
--- /dev/null
+++ b/oxyplot/OxyPlot/Reporting/Report/PropertyTable.cs
@@ -0,0 +1,114 @@
+// 
--------------------------------------------------------------------------------------------------------------------
+// <copyright file="PropertyTable.cs" company="OxyPlot">
+//   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.
+// </copyright>
+// <summary>
+//   Represents a table of autogenerated property values.
+// </summary>
+// 
--------------------------------------------------------------------------------------------------------------------
+namespace OxyPlot.Reporting
+{
+    using System;
+    using System.Collections;
+    using System.ComponentModel;
+
+    /// <summary>
+    /// Represents a table of autogenerated property values.
+    /// </summary>
+    /// <remarks>
+    /// The PropertyTable autogenerates columns or rows based on reflecting the Items type.
+    /// Only [Browsable] properties are included.
+    /// </remarks>
+    public class PropertyTable : ItemsTable
+    {
+        /// <summary>
+        /// Initializes a new instance of the <see cref="PropertyTable"/> class.
+        /// </summary>
+        /// <param name="items">
+        /// The items.
+        /// </param>
+        /// <param name="itemsInRows">
+        /// The items in rows.
+        /// </param>
+        public PropertyTable(IEnumerable items, bool itemsInRows)
+            : base(itemsInRows)
+        {
+            this.Alignment = Alignment.Left;
+            this.UpdateFields(items);
+            this.Items = items;
+        }
+
+        /// <summary>
+        /// The get item type.
+        /// </summary>
+        /// <param name="items">
+        /// The items.
+        /// </param>
+        /// <returns>
+        /// </returns>
+        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;
+        }
+
+        /// <summary>
+        /// Updates the fields.
+        /// </summary>
+        /// <param name="items">
+        /// The items.
+        /// </param>
+        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 --git a/oxyplot/OxyPlot/Reporting/Report/Report.cs b/oxyplot/OxyPlot/Reporting/Report/Report.cs
new file mode 100644
index 0000000..cfac574
--- /dev/null
+++ b/oxyplot/OxyPlot/Reporting/Report/Report.cs
@@ -0,0 +1,87 @@
+// 
--------------------------------------------------------------------------------------------------------------------
+// <copyright file="Report.cs" company="OxyPlot">
+//   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.
+// </copyright>
+// <summary>
+//   Represents a report.
+// </summary>
+// 
--------------------------------------------------------------------------------------------------------------------
+namespace OxyPlot.Reporting
+{
+    using System.Globalization;
+
+    /// <summary>
+    /// Represents a report.
+    /// </summary>
+    public class Report : ReportItem
+    {
+        /// <summary>
+        /// Gets the actual culture.
+        /// </summary>
+        public CultureInfo ActualCulture
+        {
+            get
+            {
+                return this.Culture ?? CultureInfo.CurrentCulture;
+            }
+        }
+
+        /// <summary>
+        /// Gets or sets Author.
+        /// </summary>
+        public string Author { get; set; }
+
+        /// <summary>
+        /// Gets or sets the culture.
+        /// </summary>
+        /// <value>
+        /// The culture.
+        /// </value>
+        public CultureInfo Culture { get; set; }
+
+        /// <summary>
+        /// Gets or sets SubTitle.
+        /// </summary>
+        public string SubTitle { get; set; }
+
+        /// <summary>
+        /// Gets or sets Title.
+        /// </summary>
+        public string Title { get; set; }
+
+        /// <summary>
+        /// The write.
+        /// </summary>
+        /// <param name="w">
+        /// The w.
+        /// </param>
+        public override void Write(IReportWriter w)
+        {
+            this.UpdateParent(this);
+            this.UpdateFigureNumbers();
+            base.Write(w);
+        }
+
+    }
+}
\ No newline at end of file
diff --git a/oxyplot/OxyPlot/Reporting/Report/ReportItem.cs b/oxyplot/OxyPlot/Reporting/Report/ReportItem.cs
new file mode 100644
index 0000000..125716d
--- /dev/null
+++ b/oxyplot/OxyPlot/Reporting/Report/ReportItem.cs
@@ -0,0 +1,311 @@
+// 
--------------------------------------------------------------------------------------------------------------------
+// <copyright file="ReportItem.cs" company="OxyPlot">
+//   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.
+// </copyright>
+// <summary>
+//   Represents a report item (abstract base class).
+// </summary>
+// 
--------------------------------------------------------------------------------------------------------------------
+namespace OxyPlot.Reporting
+{
+    using System.Collections;
+    using System.Collections.Generic;
+    using System.Collections.ObjectModel;
+
+    /// <summary>
+    /// Represents a report item (abstract base class).
+    /// </summary>
+    public abstract class ReportItem
+    {
+        /// <summary>
+        /// Initializes a new instance of the <see cref = "ReportItem" /> class.
+        /// </summary>
+        protected ReportItem()
+        {
+            this.Children = new Collection<ReportItem>();
+        }
+
+        /// <summary>
+        /// Gets the children.
+        /// </summary>
+        public Collection<ReportItem> Children { get; private set; }
+
+        /// <summary>
+        /// Gets the report.
+        /// </summary>
+        public Report Report { get; internal set; }
+
+        /// <summary>
+        /// Adds a report item to the report.
+        /// </summary>
+        /// <param name="child">
+        /// The child.
+        /// </param>
+        public void Add(ReportItem child)
+        {
+            this.Children.Add(child);
+        }
+
+        /// <summary>
+        /// Adds a drawing to the report.
+        /// </summary>
+        /// <param name="content">
+        /// The content.
+        /// </param>
+        /// <param name="text">
+        /// The text.
+        /// </param>
+        public void AddDrawing(string content, string text)
+        {
+            this.Add(new DrawingFigure { Content = content, FigureText = text });
+        }
+
+        /// <summary>
+        /// Adds a plot to the report.
+        /// </summary>
+        /// <param name="plot">The plot model.</param>
+        /// <param name="text">The text.</param>
+        /// <param name="width">The width.</param>
+        /// <param name="height">The height.</param>
+        public void AddPlot(PlotModel plot, string text, double width, double height)
+        {
+            this.Add(new PlotFigure { PlotModel = plot, Width = width, Height = height, FigureText = text });
+        }
+
+        /// <summary>
+        /// Adds an equation to the report.
+        /// </summary>
+        /// <param name="equation">
+        /// The equation.
+        /// </param>
+        /// <param name="caption">
+        /// The caption.
+        /// </param>
+        public void AddEquation(string equation, string caption = null)
+        {
+            this.Add(new Equation { Content = equation, Caption = caption });
+        }
+
+        /// <summary>
+        /// Adds a header to the report.
+        /// </summary>
+        /// <param name="level">
+        /// The level.
+        /// </param>
+        /// <param name="header">
+        /// The header.
+        /// </param>
+        public void AddHeader(int level, string header)
+        {
+            this.Add(new Header { Level = level, Text = header });
+        }
+
+        /// <summary>
+        /// Adds an image to the report.
+        /// </summary>
+        /// <param name="src">
+        /// The src.
+        /// </param>
+        /// <param name="text">
+        /// The text.
+        /// </param>
+        public void AddImage(string src, string text)
+        {
+            this.Add(new Image { Source = src, FigureText = text });
+        }
+
+        /// <summary>
+        /// Adds an items table to the report.
+        /// </summary>
+        /// <param name="title">
+        /// The title.
+        /// </param>
+        /// <param name="items">
+        /// The items.
+        /// </param>
+        /// <param name="fields">
+        /// The fields.
+        /// </param>
+        public void AddItemsTable(string title, IEnumerable items, IList<ItemsTableField> fields)
+        {
+            this.Add(new ItemsTable { Caption = title, Items = items, Fields = fields });
+        }
+
+        /// <summary>
+        /// Adds a paragraph to the report.
+        /// </summary>
+        /// <param name="content">
+        /// The content.
+        /// </param>
+        public void AddParagraph(string content)
+        {
+            this.Add(new Paragraph { Text = content });
+        }
+
+        /// <summary>
+        /// Adds a property table to the report.
+        /// </summary>
+        /// <param name="title">
+        /// The title.
+        /// </param>
+        /// <param name="obj">
+        /// The object.
+        /// </param>
+        /// <returns>
+        /// A PropertyTable.
+        /// </returns>
+        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;
+        }
+
+        /// <summary>
+        /// The add table of contents.
+        /// </summary>
+        /// <param name="b">
+        /// The b.
+        /// </param>
+        public void AddTableOfContents(ReportItem b)
+        {
+            this.Add(new TableOfContents(b));
+        }
+
+        /// <summary>
+        /// The update.
+        /// </summary>
+        public virtual void Update()
+        {
+        }
+
+        /// <summary>
+        /// The write.
+        /// </summary>
+        /// <param name="w">
+        /// The w.
+        /// </param>
+        public virtual void Write(IReportWriter w)
+        {
+            this.Update();
+            this.WriteContent(w);
+            foreach (var child in this.Children)
+            {
+                child.Write(w);
+            }
+        }
+
+        /// <summary>
+        /// Writes the content of the item.
+        /// </summary>
+        /// <param name="w">
+        /// The writer.
+        /// </param>
+        public virtual void WriteContent(IReportWriter w)
+        {
+        }
+
+        /// <summary>
+        /// The update figure numbers.
+        /// </summary>
+        protected void UpdateFigureNumbers()
+        {
+            var fc = new FigureCounter();
+            this.UpdateFigureNumbers(fc);
+        }
+
+        /// <summary>
+        /// Updates the Report property.
+        /// </summary>
+        /// <param name="report">
+        /// The report.
+        /// </param>
+        protected void UpdateParent(Report report)
+        {
+            this.Report = report;
+            foreach (var child in this.Children)
+            {
+                child.UpdateParent(report);
+            }
+        }
+
+        /// <summary>
+        /// The update figure numbers.
+        /// </summary>
+        /// <param name="fc">
+        /// The fc.
+        /// </param>
+        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);
+            }
+        }
+
+        /// <summary>
+        /// The figure counter.
+        /// </summary>
+        private class FigureCounter
+        {
+            /// <summary>
+            /// Initializes a new instance of the <see cref = "FigureCounter" /> class.
+            /// </summary>
+            public FigureCounter()
+            {
+                this.FigureNumber = 1;
+                this.TableNumber = 1;
+            }
+
+            /// <summary>
+            /// Gets or sets FigureNumber.
+            /// </summary>
+            public int FigureNumber { get; set; }
+
+            /// <summary>
+            /// Gets or sets TableNumber.
+            /// </summary>
+            public int TableNumber { get; set; }
+
+        }
+    }
+}
\ No newline at end of file
diff --git a/oxyplot/OxyPlot/Reporting/Report/ReportSection.cs 
b/oxyplot/OxyPlot/Reporting/Report/ReportSection.cs
new file mode 100644
index 0000000..7a1b0e8
--- /dev/null
+++ b/oxyplot/OxyPlot/Reporting/Report/ReportSection.cs
@@ -0,0 +1,38 @@
+// 
--------------------------------------------------------------------------------------------------------------------
+// <copyright file="ReportSection.cs" company="OxyPlot">
+//   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.
+// </copyright>
+// <summary>
+//   Represents a report section.
+// </summary>
+// 
--------------------------------------------------------------------------------------------------------------------
+namespace OxyPlot.Reporting
+{
+    /// <summary>
+    /// Represents a report section.
+    /// </summary>
+    public class ReportSection : ReportItem
+    {
+    }
+}
\ No newline at end of file
diff --git a/oxyplot/OxyPlot/Reporting/Report/ReportStyle.cs b/oxyplot/OxyPlot/Reporting/Report/ReportStyle.cs
new file mode 100644
index 0000000..3428125
--- /dev/null
+++ b/oxyplot/OxyPlot/Reporting/Report/ReportStyle.cs
@@ -0,0 +1,156 @@
+// 
--------------------------------------------------------------------------------------------------------------------
+// <copyright file="ReportStyle.cs" company="OxyPlot">
+//   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.
+// </copyright>
+// <summary>
+//   The report style.
+// </summary>
+// 
--------------------------------------------------------------------------------------------------------------------
+namespace OxyPlot.Reporting
+{
+    /// <summary>
+    /// The report style.
+    /// </summary>
+    public class ReportStyle
+    {
+        /// <summary>
+        /// Initializes a new instance of the <see cref="ReportStyle"/> class.
+        /// </summary>
+        /// <param name="titleFontFamily">
+        /// The title font family.
+        /// </param>
+        /// <param name="bodyTextFontFamily">
+        /// The body text font family.
+        /// </param>
+        /// <param name="tableTextFontFamily">
+        /// The table text font family.
+        /// </param>
+        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}";
+        }
+
+        /// <summary>
+        /// Gets or sets BodyTextStyle.
+        /// </summary>
+        public ParagraphStyle BodyTextStyle { get; set; }
+
+        /// <summary>
+        /// Gets or sets DefaultStyle.
+        /// </summary>
+        public ParagraphStyle DefaultStyle { get; set; }
+
+        /// <summary>
+        /// Gets or sets FigureTextFormatString.
+        /// </summary>
+        public string FigureTextFormatString { get; set; }
+
+        /// <summary>
+        /// Gets or sets FigureTextStyle.
+        /// </summary>
+        public ParagraphStyle FigureTextStyle { get; set; }
+
+        /// <summary>
+        /// Gets or sets HeaderStyles.
+        /// </summary>
+        public ParagraphStyle[] HeaderStyles { get; set; }
+
+        /// <summary>
+        /// Gets or sets the page margins (mm).
+        /// </summary>
+        public OxyThickness Margins { get; set; }
+
+        // todo: should the FormatStrings be in the Report class?
+
+        /// <summary>
+        /// Gets or sets TableCaptionFormatString.
+        /// </summary>
+        public string TableCaptionFormatString { get; set; }
+
+        /// <summary>
+        /// Gets or sets TableCaptionStyle.
+        /// </summary>
+        public ParagraphStyle TableCaptionStyle { get; set; }
+
+        /// <summary>
+        /// Gets or sets TableHeaderStyle.
+        /// </summary>
+        public ParagraphStyle TableHeaderStyle { get; set; }
+
+        /// <summary>
+        /// Gets or sets TableTextStyle.
+        /// </summary>
+        public ParagraphStyle TableTextStyle { get; set; }
+
+    }
+}
\ No newline at end of file
diff --git a/oxyplot/OxyPlot/Reporting/Report/Table.cs b/oxyplot/OxyPlot/Reporting/Report/Table.cs
new file mode 100644
index 0000000..94e4a17
--- /dev/null
+++ b/oxyplot/OxyPlot/Reporting/Report/Table.cs
@@ -0,0 +1,252 @@
+// 
--------------------------------------------------------------------------------------------------------------------
+// <copyright file="Table.cs" company="OxyPlot">
+//   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.
+// </copyright>
+// <summary>
+//   Represents a table column definition.
+// </summary>
+// 
--------------------------------------------------------------------------------------------------------------------
+namespace OxyPlot.Reporting
+{
+    using System;
+    using System.Collections.Generic;
+
+    /// <summary>
+    /// Represents a table column definition.
+    /// </summary>
+    public class TableColumn
+    {
+        /// <summary>
+        /// Initializes a new instance of the <see cref = "TableColumn" /> class.
+        /// </summary>
+        public TableColumn()
+        {
+            this.Width = double.NaN;
+            this.Alignment = Alignment.Center;
+        }
+
+        /// <summary>
+        /// Gets or sets the actual width (mm).
+        /// </summary>
+        /// <value>The actual width.</value>
+        public double ActualWidth { get; internal set; }
+
+        /// <summary>
+        /// Gets or sets Alignment.
+        /// </summary>
+        public Alignment Alignment { get; set; }
+
+        /// <summary>
+        /// Gets or sets a value indicating whether IsHeader.
+        /// </summary>
+        public bool IsHeader { get; set; }
+
+        /// <summary>
+        /// Gets or sets the width.
+        /// NaN: auto width.
+        /// Negative numbers: weights
+        /// </summary>
+        /// <value>The width.</value>
+        public double Width { get; set; }
+
+    }
+
+    /// <summary>
+    /// Represents a table row definition.
+    /// </summary>
+    public class TableRow
+    {
+        /// <summary>
+        /// Initializes a new instance of the <see cref = "TableRow" /> class.
+        /// </summary>
+        public TableRow()
+        {
+            this.Cells = new List<TableCell>();
+        }
+
+        /// <summary>
+        /// Gets Cells.
+        /// </summary>
+        public IList<TableCell> Cells { get; private set; }
+
+        /// <summary>
+        /// Gets or sets a value indicating whether IsHeader.
+        /// </summary>
+        public bool IsHeader { get; set; }
+
+    }
+
+    /// <summary>
+    /// Represents a table cell.
+    /// </summary>
+    public class TableCell
+    {
+        // public Alignment Alignment { get; set; }
+        // public int RowSpan { get; set; }
+        // public int ColumnSpan { get; set; }
+        /// <summary>
+        /// Gets or sets Content.
+        /// </summary>
+        public string Content { get; set; }
+
+    }
+
+    /// <summary>
+    /// Represents a table.
+    /// </summary>
+    public class Table : ReportItem
+    {
+        /// <summary>
+        /// Initializes a new instance of the <see cref = "Table" /> class.
+        /// </summary>
+        public Table()
+        {
+            this.Rows = new List<TableRow>();
+            this.Columns = new List<TableColumn>();
+            this.Width = double.NaN;
+        }
+
+        /// <summary>
+        /// Gets or sets the actual width of the table (mm).
+        /// </summary>
+        /// <value>The actual width.</value>
+        public double ActualWidth { get; private set; }
+
+        /// <summary>
+        /// Gets or sets Caption.
+        /// </summary>
+        public string Caption { get; set; }
+
+        /// <summary>
+        /// Gets Columns.
+        /// </summary>
+        public IList<TableColumn> Columns { get; private set; }
+
+        /// <summary>
+        /// Gets Rows.
+        /// </summary>
+        public IList<TableRow> Rows { get; private set; }
+
+        /// <summary>
+        /// Gets or sets TableNumber.
+        /// </summary>
+        public int TableNumber { get; set; }
+
+        /// <summary>
+        /// Gets or sets the width of the table (mm).
+        /// NaN: auto width.
+        /// 0..-1: fraction of page width.
+        /// </summary>
+        public double Width { get; set; }
+
+        /// <summary>
+        /// The get full caption.
+        /// </summary>
+        /// <param name="style">
+        /// The style.
+        /// </param>
+        /// <returns>
+        /// The get full caption.
+        /// </returns>
+        public string GetFullCaption(ReportStyle style)
+        {
+            return string.Format(style.TableCaptionFormatString, this.TableNumber, this.Caption);
+        }
+
+        /// <summary>
+        /// The update.
+        /// </summary>
+        public override void Update()
+        {
+            base.Update();
+            this.UpdateWidths();
+        }
+
+        /// <summary>
+        /// The write content.
+        /// </summary>
+        /// <param name="w">
+        /// The w.
+        /// </param>
+        public override void WriteContent(IReportWriter w)
+        {
+            // todo
+        }
+
+        /// <summary>
+        /// The update widths.
+        /// </summary>
+        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 --git a/oxyplot/OxyPlot/Reporting/Report/TableColumn.cs b/oxyplot/OxyPlot/Reporting/Report/TableColumn.cs
new file mode 100644
index 0000000..cfd2ae3
--- /dev/null
+++ b/oxyplot/OxyPlot/Reporting/Report/TableColumn.cs
@@ -0,0 +1,63 @@
+// 
--------------------------------------------------------------------------------------------------------------------
+// <copyright file="TableColumn.cs" company="OxyPlot">
+//   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.
+// </copyright>
+// 
--------------------------------------------------------------------------------------------------------------------
+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<TableColumn> 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<TableColumn>();
+        }
+
+        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 --git a/oxyplot/OxyPlot/Reporting/Report/TableOfContents.cs 
b/oxyplot/OxyPlot/Reporting/Report/TableOfContents.cs
new file mode 100644
index 0000000..4a1432d
--- /dev/null
+++ b/oxyplot/OxyPlot/Reporting/Report/TableOfContents.cs
@@ -0,0 +1,115 @@
+// 
--------------------------------------------------------------------------------------------------------------------
+// <copyright file="TableOfContents.cs" company="OxyPlot">
+//   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.
+// </copyright>
+// <summary>
+//   Represents a table of contents.
+// </summary>
+// 
--------------------------------------------------------------------------------------------------------------------
+namespace OxyPlot.Reporting
+{
+    using System.Collections.Generic;
+
+    /// <summary>
+    /// Represents a table of contents.
+    /// </summary>
+    public class TableOfContents : ItemsTable
+    {
+        /// <summary>
+        /// Initializes a new instance of the <see cref="TableOfContents"/> class.
+        /// </summary>
+        /// <param name="b">
+        /// The b.
+        /// </param>
+        public TableOfContents(ReportItem b)
+        {
+            this.Base = b;
+            this.Contents = new List<ContentItem>();
+            this.Fields.Add(new ItemsTableField(null, "Chapter"));
+            this.Fields.Add(new ItemsTableField(null, "Title"));
+            this.Items = this.Contents;
+        }
+
+        /// <summary>
+        /// Gets or sets Base.
+        /// </summary>
+        public ReportItem Base { get; set; }
+
+        /// <summary>
+        /// Gets or sets Contents.
+        /// </summary>
+        public List<ContentItem> Contents { get; set; }
+
+        /// <summary>
+        /// The update.
+        /// </summary>
+        public override void Update()
+        {
+            this.Contents.Clear();
+            var hh = new HeaderHelper();
+            this.Search(this.Base, hh);
+            base.Update();
+        }
+
+        /// <summary>
+        /// The search.
+        /// </summary>
+        /// <param name="item">
+        /// The item.
+        /// </param>
+        /// <param name="hh">
+        /// The hh.
+        /// </param>
+        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);
+            }
+        }
+
+        /// <summary>
+        /// The content item.
+        /// </summary>
+        public class ContentItem
+        {
+            /// <summary>
+            /// Gets or sets Chapter.
+            /// </summary>
+            public string Chapter { get; set; }
+
+            /// <summary>
+            /// Gets or sets Title.
+            /// </summary>
+            public string Title { get; set; }
+        }
+    }
+}
\ No newline at end of file
diff --git a/oxyplot/OxyPlot/Reporting/ReportWriters/HtmlReportWriter.cs 
b/oxyplot/OxyPlot/Reporting/ReportWriters/HtmlReportWriter.cs
new file mode 100644
index 0000000..b759d19
--- /dev/null
+++ b/oxyplot/OxyPlot/Reporting/ReportWriters/HtmlReportWriter.cs
@@ -0,0 +1,501 @@
+// 
--------------------------------------------------------------------------------------------------------------------
+// <copyright file="HtmlReportWriter.cs" company="OxyPlot">
+//   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.
+// </copyright>
+// <summary>
+//   Specifies the html element type to use when writing plots.
+// </summary>
+// 
--------------------------------------------------------------------------------------------------------------------
+namespace OxyPlot.Reporting
+{
+    using System.Collections.Generic;
+    using System.IO;
+    using System.Text;
+
+    /// <summary>
+    /// Specifies the html element type to use when writing plots.
+    /// </summary>
+    public enum HtmlPlotElementType
+    {
+        /// <summary>
+        /// Use the embed tag and reference an external svg file.
+        /// </summary>
+        Embed,
+
+        /// <summary>
+        /// Use the object tag and reference an external svg file.
+        /// </summary>
+        Object,
+
+        /// <summary>
+        /// Use the svg tag and include the plot inline.
+        /// </summary>
+        Svg
+    }
+
+    /// <summary>
+    /// HTML5 report writer.
+    /// </summary>
+    public class HtmlReportWriter : XmlWriterBase, IReportWriter
+    {
+        /// <summary>
+        /// The text measurer.
+        /// </summary>
+        private readonly IRenderContext textMeasurer;
+
+        /// <summary>
+        /// The figure counter.
+        /// </summary>
+        private int figureCounter;
+
+        /// <summary>
+        /// The style.
+        /// </summary>
+        private ReportStyle style;
+
+        /// <summary>
+        /// Initializes a new instance of the <see cref="HtmlReportWriter"/> class.
+        /// </summary>
+        /// <param name="stream">
+        /// The stream.
+        /// </param>
+        /// <param name="textMeasurer">
+        /// The text measurer.
+        /// </param>
+        public HtmlReportWriter(Stream stream, IRenderContext textMeasurer = null)
+            : base(stream)
+        {
+            this.textMeasurer = textMeasurer;
+            this.WriteHtmlElement();
+            this.PlotElementType = HtmlPlotElementType.Svg;
+        }
+
+        /// <summary>
+        /// Gets or sets the type of the plot element.
+        /// </summary>
+        /// <value>
+        /// The type of the plot element.
+        /// </value>
+        public HtmlPlotElementType PlotElementType { get; set; }
+
+        /// <summary>
+        /// Closes this instance.
+        /// </summary>
+        public override void Close()
+        {
+            this.WriteEndElement();
+            this.WriteEndElement();
+            base.Close();
+        }
+
+        /// <summary>
+        /// Writes the class ID.
+        /// </summary>
+        /// <param name="className">
+        /// The class.
+        /// </param>
+        /// <param name="id">
+        /// The id.
+        /// </param>
+        public void WriteClassId(string className, string id = null)
+        {
+            if (className != null)
+            {
+                this.WriteAttributeString("class", className);
+            }
+
+            if (id != null)
+            {
+                this.WriteAttributeString("id", id);
+            }
+        }
+
+        /// <summary>
+        /// Writes the drawing.
+        /// </summary>
+        /// <param name="d">
+        /// The drawing.
+        /// </param>
+        public void WriteDrawing(DrawingFigure d)
+        {
+            this.WriteStartFigure();
+            this.WriteRaw(d.Content);
+            this.WriteEndFigure(d.FigureText);
+        }
+
+        /// <summary>
+        /// Writes the equation.
+        /// </summary>
+        /// <param name="equation">
+        /// The equation.
+        /// </param>
+        public void WriteEquation(Equation equation)
+        {
+            // todo: MathML?
+        }
+
+        /// <summary>
+        /// Writes the header.
+        /// </summary>
+        /// <param name="h">
+        /// The header.
+        /// </param>
+        public void WriteHeader(Header h)
+        {
+            if (h.Text == null)
+            {
+                return;
+            }
+
+            this.WriteStartElement("h" + h.Level);
+            this.WriteString(h.ToString());
+            this.WriteEndElement();
+        }
+
+        /// <summary>
+        /// Writes the image.
+        /// </summary>
+        /// <param name="i">
+        /// The image.
+        /// </param>
+        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);
+        }
+
+        /// <summary>
+        /// Writes the paragraph.
+        /// </summary>
+        /// <param name="p">
+        /// The paragraph.
+        /// </param>
+        public void WriteParagraph(Paragraph p)
+        {
+            this.WriteElementString("p", p.Text);
+        }
+
+        /// <summary>
+        /// Writes the plot.
+        /// </summary>
+        /// <param name="plot">
+        /// The plot.
+        /// </param>
+        public void WritePlot(PlotFigure plot)
+        {
+            this.WriteStartFigure();
+            switch (this.PlotElementType)
+            {
+                case HtmlPlotElementType.Embed:
+                case HtmlPlotElementType.Object:
+                    // TODO: need a Func<string,Stream> 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);
+        }
+
+        /// <summary>
+        /// The write report.
+        /// </summary>
+        /// <param name="report">
+        /// The report.
+        /// </param>
+        /// <param name="reportStyle">
+        /// The style.
+        /// </param>
+        public void WriteReport(Report report, ReportStyle reportStyle)
+        {
+            this.style = reportStyle;
+            this.WriteHtmlHeader(report.Title, null, CreateCss(reportStyle));
+            report.Write(this);
+        }
+
+        /// <summary>
+        /// Writes the items.
+        /// </summary>
+        /// <param name="t">
+        /// The table.
+        /// </param>
+        public void WriteRows(Table t)
+        {
+            IList<TableColumn> 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
+                }
+            }
+        }
+
+        /// <summary>
+        /// Writes the table.
+        /// </summary>
+        /// <param name="t">
+        /// The t.
+        /// </param>
+        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
+        }
+
+        /// <summary>
+        /// Creates the css section.
+        /// </summary>
+        /// <param name="style">
+        /// The style.
+        /// </param>
+        /// <returns>
+        /// The css.
+        /// </returns>
+        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();
+        }
+
+        /// <summary>
+        /// Gets the alignment string.
+        /// </summary>
+        /// <param name="a">
+        /// The alignment type.
+        /// </param>
+        /// <returns>
+        /// An alignment string.
+        /// </returns>
+        private static string GetAlignmentString(Alignment a)
+        {
+            return a.ToString().ToLower();
+        }
+
+        /// <summary>
+        /// Converts a paragraphes style to css.
+        /// </summary>
+        /// <param name="s">
+        /// The style.
+        /// </param>
+        /// <returns>
+        /// A css string.
+        /// </returns>
+        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();
+        }
+
+        /// <summary>
+        /// Initializes this instance.
+        /// </summary>
+        private void WriteHtmlElement()
+        {
+            this.WriteStartElement("html", "http://www.w3.org/1999/xhtml";);
+        }
+
+        /// <summary>
+        /// Writes the div.
+        /// </summary>
+        /// <param name="divstyle">
+        /// The style of the div.
+        /// </param>
+        /// <param name="content">
+        /// The content.
+        /// </param>
+        private void WriteDiv(string divstyle, string content)
+        {
+            this.WriteStartElement("div");
+            this.WriteAttributeString("class", divstyle);
+            this.WriteString(content);
+            this.WriteEndElement();
+        }
+
+        /// <summary>
+        /// Writes the end figure.
+        /// </summary>
+        /// <param name="text">
+        /// The figure text.
+        /// </param>
+        private void WriteEndFigure(string text)
+        {
+            this.WriteDiv("figuretext", string.Format("Fig {0}. {1}", this.figureCounter, text));
+            this.WriteEndElement();
+        }
+
+        /// <summary>
+        /// Writes the HTML header.
+        /// </summary>
+        /// <param name="title">
+        /// The title.
+        /// </param>
+        /// <param name="cssPath">
+        /// The CSS path.
+        /// </param>
+        /// <param name="cssStyle">
+        /// The style.
+        /// </param>
+        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");
+        }
+
+        /// <summary>
+        /// Writes the start figure element.
+        /// </summary>
+        private void WriteStartFigure()
+        {
+            this.figureCounter++;
+            this.WriteStartElement("p");
+            this.WriteClassId("figure");
+        }
+
+    }
+}
\ No newline at end of file
diff --git a/oxyplot/OxyPlot/Reporting/ReportWriters/IReportWriter.cs 
b/oxyplot/OxyPlot/Reporting/ReportWriters/IReportWriter.cs
new file mode 100644
index 0000000..2e7c0dc
--- /dev/null
+++ b/oxyplot/OxyPlot/Reporting/ReportWriters/IReportWriter.cs
@@ -0,0 +1,87 @@
+// 
--------------------------------------------------------------------------------------------------------------------
+// <copyright file="IReportWriter.cs" company="OxyPlot">
+//   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.
+// </copyright>
+// <summary>
+//   Interface for Report writers.
+// </summary>
+// 
--------------------------------------------------------------------------------------------------------------------
+namespace OxyPlot.Reporting
+{
+    /// <summary>
+    /// Interface for Report writers.
+    /// </summary>
+    public interface IReportWriter
+    {
+        /// <summary>
+        /// Writes the drawing.
+        /// </summary>
+        /// <param name="drawing">The drawing.</param>
+        void WriteDrawing(DrawingFigure drawing);
+
+        /// <summary>
+        /// Writes the equation.
+        /// </summary>
+        /// <param name="equation">The equation.</param>
+        void WriteEquation(Equation equation);
+
+        /// <summary>
+        /// Writes the header.
+        /// </summary>
+        /// <param name="header">The header.</param>
+        void WriteHeader(Header header);
+
+        /// <summary>
+        /// Writes the image.
+        /// </summary>
+        /// <param name="image">The image.</param>
+        void WriteImage(Image image);
+
+        /// <summary>
+        /// Writes the paragraph.
+        /// </summary>
+        /// <param name="paragraph">The paragraph.</param>
+        void WriteParagraph(Paragraph paragraph);
+
+        /// <summary>
+        /// Writes the plot.
+        /// </summary>
+        /// <param name="plot">The plot.</param>
+        void WritePlot(PlotFigure plot);
+
+        /// <summary>
+        /// Writes the report.
+        /// </summary>
+        /// <param name="report">The report.</param>
+        /// <param name="reportStyle">The style.</param>
+        void WriteReport(Report report, ReportStyle reportStyle);
+
+        /// <summary>
+        /// Writes the table.
+        /// </summary>
+        /// <param name="table">The table.</param>
+        void WriteTable(Table table);
+
+    }
+}
\ No newline at end of file
diff --git a/oxyplot/OxyPlot/Reporting/ReportWriters/StringExtensions.cs 
b/oxyplot/OxyPlot/Reporting/ReportWriters/StringExtensions.cs
new file mode 100644
index 0000000..617bda8
--- /dev/null
+++ b/oxyplot/OxyPlot/Reporting/ReportWriters/StringExtensions.cs
@@ -0,0 +1,130 @@
+// 
--------------------------------------------------------------------------------------------------------------------
+// <copyright file="StringExtensions.cs" company="OxyPlot">
+//   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.
+// </copyright>
+// <summary>
+//   The string extensions.
+// </summary>
+// 
--------------------------------------------------------------------------------------------------------------------
+namespace OxyPlot.Reporting
+{
+    using System.Collections.Generic;
+    using System.Text;
+
+    /// <summary>
+    /// The string extensions.
+    /// </summary>
+    public static class StringExtensions
+    {
+        /// <summary>
+        /// The repeat.
+        /// </summary>
+        /// <param name="source">
+        /// The source.
+        /// </param>
+        /// <param name="n">
+        /// The n.
+        /// </param>
+        /// <returns>
+        /// The repeat.
+        /// </returns>
+        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();
+        }
+
+        /// <summary>
+        /// The split lines.
+        /// </summary>
+        /// <param name="s">
+        /// The s.
+        /// </param>
+        /// <param name="lineLength">
+        /// The line length.
+        /// </param>
+        /// <returns>
+        /// </returns>
+        public static string[] SplitLines(this string s, int lineLength = 80)
+        {
+            var lines = new List<string>();
+
+            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();
+        }
+
+        /// <summary>
+        /// The find line length.
+        /// </summary>
+        /// <param name="text">
+        /// The text.
+        /// </param>
+        /// <param name="i">
+        /// The i.
+        /// </param>
+        /// <param name="maxLineLength">
+        /// The max line length.
+        /// </param>
+        /// <returns>
+        /// The find line length.
+        /// </returns>
+        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 --git a/oxyplot/OxyPlot/Reporting/ReportWriters/TextReportWriter.cs 
b/oxyplot/OxyPlot/Reporting/ReportWriters/TextReportWriter.cs
new file mode 100644
index 0000000..7340bc2
--- /dev/null
+++ b/oxyplot/OxyPlot/Reporting/ReportWriters/TextReportWriter.cs
@@ -0,0 +1,289 @@
+// 
--------------------------------------------------------------------------------------------------------------------
+// <copyright file="TextReportWriter.cs" company="OxyPlot">
+//   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.
+// </copyright>
+// <summary>
+//   ANSI text report writer.
+// </summary>
+// 
--------------------------------------------------------------------------------------------------------------------
+namespace OxyPlot.Reporting
+{
+    using System;
+    using System.IO;
+
+    /// <summary>
+    /// ANSI text report writer.
+    /// </summary>
+    /// <remarks>
+    /// This will not write figures/images.
+    /// </remarks>
+    public class TextReportWriter : StreamWriter, IReportWriter
+    {
+        /// <summary>
+        /// The table cell separator.
+        /// </summary>
+        private const string TableCellSeparator = " | ";
+
+        /// <summary>
+        /// The table row end.
+        /// </summary>
+        private const string TableRowEnd = " |";
+
+        /// <summary>
+        /// The table row start.
+        /// </summary>
+        private const string TableRowStart = "| ";
+
+        /// <summary>
+        /// The table counter.
+        /// </summary>
+        private int tableCounter;
+
+        /// <summary>
+        /// Initializes a new instance of the <see cref="TextReportWriter"/> class.
+        /// </summary>
+        /// <param name="stream">
+        /// The stream.
+        /// </param>
+        public TextReportWriter(Stream stream)
+            : base(stream)
+        {
+            this.MaxLineLength = 60;
+        }
+
+        /// <summary>
+        /// Gets or sets MaxLineLength.
+        /// </summary>
+        public int MaxLineLength { get; set; }
+
+        /// <summary>
+        /// The write drawing.
+        /// </summary>
+        /// <param name="d">
+        /// The d.
+        /// </param>
+        public void WriteDrawing(DrawingFigure d)
+        {
+        }
+
+        /// <summary>
+        /// The write equation.
+        /// </summary>
+        /// <param name="equation">
+        /// The equation.
+        /// </param>
+        public void WriteEquation(Equation equation)
+        {
+        }
+
+        /// <summary>
+        /// The write header.
+        /// </summary>
+        /// <param name="h">
+        /// The h.
+        /// </param>
+        public void WriteHeader(Header h)
+        {
+            if (h.Text == null)
+            {
+                return;
+            }
+
+            WriteLine(h);
+            if (h.Level == 1)
+            {
+                this.WriteLine("=".Repeat(h.Text.Length));
+            }
+
+            this.WriteLine();
+        }
+
+        /// <summary>
+        /// The write image.
+        /// </summary>
+        /// <param name="i">
+        /// The i.
+        /// </param>
+        public void WriteImage(Image i)
+        {
+        }
+
+        /// <summary>
+        /// The write paragraph.
+        /// </summary>
+        /// <param name="p">
+        /// The p.
+        /// </param>
+        public void WriteParagraph(Paragraph p)
+        {
+            foreach (string line in p.Text.SplitLines(this.MaxLineLength))
+            {
+                WriteLine(line);
+            }
+
+            this.WriteLine();
+        }
+
+        /// <summary>
+        /// The write plot.
+        /// </summary>
+        /// <param name="plot">
+        /// The plot.
+        /// </param>
+        public void WritePlot(PlotFigure plot)
+        {
+        }
+
+        /// <summary>
+        /// The write report.
+        /// </summary>
+        /// <param name="report">
+        /// The report.
+        /// </param>
+        /// <param name="reportStyle">
+        /// The style.
+        /// </param>
+        public void WriteReport(Report report, ReportStyle reportStyle)
+        {
+            report.Write(this);
+        }
+
+        /// <summary>
+        /// The write table.
+        /// </summary>
+        /// <param name="t">
+        /// The t.
+        /// </param>
+        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();
+        }
+
+        /// <summary>
+        /// The get cell text.
+        /// </summary>
+        /// <param name="i">
+        /// The i.
+        /// </param>
+        /// <param name="count">
+        /// The count.
+        /// </param>
+        /// <param name="p">
+        /// The p.
+        /// </param>
+        /// <returns>
+        /// The get cell text.
+        /// </returns>
+        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;
+        }
+
+        /// <summary>
+        /// The pad string.
+        /// </summary>
+        /// <param name="text">
+        /// The text.
+        /// </param>
+        /// <param name="alignment">
+        /// The alignment.
+        /// </param>
+        /// <param name="width">
+        /// The width.
+        /// </param>
+        /// <returns>
+        /// The pad string.
+        /// </returns>
+        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 --git a/oxyplot/OxyPlot/Reporting/ReportWriters/WikiReportWriter.cs 
b/oxyplot/OxyPlot/Reporting/ReportWriters/WikiReportWriter.cs
new file mode 100644
index 0000000..3403b20
--- /dev/null
+++ b/oxyplot/OxyPlot/Reporting/ReportWriters/WikiReportWriter.cs
@@ -0,0 +1,308 @@
+// 
--------------------------------------------------------------------------------------------------------------------
+// <copyright file="WikiReportWriter.cs" company="OxyPlot">
+//   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.
+// </copyright>
+// <summary>
+//   Wiki formatting report writer.
+// </summary>
+// 
--------------------------------------------------------------------------------------------------------------------
+namespace OxyPlot.Reporting
+{
+    using System;
+    using System.IO;
+
+    /// <summary>
+    /// Wiki formatting report writer.
+    /// </summary>
+    /// <remarks>
+    /// This will not write figures/images.
+    /// </remarks>
+    public class WikiReportWriter : StreamWriter, IReportWriter
+    {
+        /// <summary>
+        /// The table cell separator.
+        /// </summary>
+        private const string TableCellSeparator = " | ";
+
+        /// <summary>
+        /// The table header cell separator.
+        /// </summary>
+        private const string TableHeaderCellSeparator = " || ";
+
+        /// <summary>
+        /// The table header row end.
+        /// </summary>
+        private const string TableHeaderRowEnd = " ||";
+
+        /// <summary>
+        /// The table header row start.
+        /// </summary>
+        private const string TableHeaderRowStart = "|| ";
+
+        /// <summary>
+        /// The table row end.
+        /// </summary>
+        private const string TableRowEnd = " |";
+
+        /// <summary>
+        /// The table row start.
+        /// </summary>
+        private const string TableRowStart = "| ";
+
+        /// <summary>
+        /// The table counter.
+        /// </summary>
+        private int tableCounter;
+
+        /// <summary>
+        /// Initializes a new instance of the <see cref="WikiReportWriter"/> class.
+        /// </summary>
+        /// <param name="s">
+        /// The s.
+        /// </param>
+        public WikiReportWriter(Stream s)
+            : base(s)
+        {
+            this.MaxLineLength = 60;
+        }
+
+        /// <summary>
+        /// Gets or sets MaxLineLength.
+        /// </summary>
+        public int MaxLineLength { get; set; }
+
+        /// <summary>
+        /// The write drawing.
+        /// </summary>
+        /// <param name="d">
+        /// The d.
+        /// </param>
+        public void WriteDrawing(DrawingFigure d)
+        {
+        }
+
+        /// <summary>
+        /// The write equation.
+        /// </summary>
+        /// <param name="equation">
+        /// The equation.
+        /// </param>
+        public void WriteEquation(Equation equation)
+        {
+        }
+
+        /// <summary>
+        /// The write header.
+        /// </summary>
+        /// <param name="h">
+        /// The h.
+        /// </param>
+        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);
+        }
+
+        /// <summary>
+        /// The write image.
+        /// </summary>
+        /// <param name="i">
+        /// The i.
+        /// </param>
+        public void WriteImage(Image i)
+        {
+        }
+
+        /// <summary>
+        /// The write paragraph.
+        /// </summary>
+        /// <param name="p">
+        /// The p.
+        /// </param>
+        public void WriteParagraph(Paragraph p)
+        {
+            foreach (string line in p.Text.SplitLines(this.MaxLineLength))
+            {
+                WriteLine(line);
+            }
+
+            this.WriteLine();
+        }
+
+        /// <summary>
+        /// The write plot.
+        /// </summary>
+        /// <param name="plot">
+        /// The plot.
+        /// </param>
+        public void WritePlot(PlotFigure plot)
+        {
+        }
+
+        /// <summary>
+        /// The write report.
+        /// </summary>
+        /// <param name="report">
+        /// The report.
+        /// </param>
+        /// <param name="reportStyle">
+        /// The style.
+        /// </param>
+        public void WriteReport(Report report, ReportStyle reportStyle)
+        {
+            report.Write(this);
+        }
+
+        /// <summary>
+        /// The write table.
+        /// </summary>
+        /// <param name="t">
+        /// The t.
+        /// </param>
+        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();
+        }
+
+        /// <summary>
+        /// The get cell text.
+        /// </summary>
+        /// <param name="i">
+        /// The i.
+        /// </param>
+        /// <param name="count">
+        /// The count.
+        /// </param>
+        /// <param name="p">
+        /// The p.
+        /// </param>
+        /// <param name="isHeader">
+        /// The is header.
+        /// </param>
+        /// <returns>
+        /// The get cell text.
+        /// </returns>
+        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;
+        }
+
+        /// <summary>
+        /// The pad string.
+        /// </summary>
+        /// <param name="text">
+        /// The text.
+        /// </param>
+        /// <param name="alignment">
+        /// The alignment.
+        /// </param>
+        /// <param name="width">
+        /// The width.
+        /// </param>
+        /// <returns>
+        /// The pad string.
+        /// </returns>
+        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 --git a/oxyplot/OxyPlot/Series/AreaSeries.cs b/oxyplot/OxyPlot/Series/AreaSeries.cs
new file mode 100644
index 0000000..c914eaa
--- /dev/null
+++ b/oxyplot/OxyPlot/Series/AreaSeries.cs
@@ -0,0 +1,295 @@
+// 
--------------------------------------------------------------------------------------------------------------------
+// <copyright file="AreaSeries.cs" company="OxyPlot">
+//   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.
+// </copyright>
+// <summary>
+//   Represents an area series that fills the polygon defined by one or two sets of points.
+// </summary>
+// 
--------------------------------------------------------------------------------------------------------------------
+namespace OxyPlot.Series
+{
+    using System;
+    using System.Collections.Generic;
+
+    /// <summary>
+    /// Represents an area series that fills the polygon defined by two sets of points or one set of points 
and a constant.
+    /// </summary>
+    public class AreaSeries : LineSeries
+    {
+        /// <summary>
+        /// The second list of points.
+        /// </summary>
+        private readonly List<IDataPoint> points2 = new List<IDataPoint>();
+
+        /// <summary>
+        /// Initializes a new instance of the <see cref = "AreaSeries" /> class.
+        /// </summary>
+        public AreaSeries()
+        {
+            this.Reverse2 = true;
+        }
+
+        /// <summary>
+        /// Gets or sets a constant value for the area definition.
+        /// This is used if DataFieldBase and BaselineValues are null.
+        /// </summary>
+        /// <value>The baseline.</value>
+        public double ConstantY2 { get; set; }
+
+        /// <summary>
+        /// Gets or sets the second X data field.
+        /// </summary>
+        public string DataFieldX2 { get; set; }
+
+        /// <summary>
+        /// Gets or sets the second Y data field.
+        /// </summary>
+        public string DataFieldY2 { get; set; }
+
+        /// <summary>
+        /// Gets or sets the area fill color.
+        /// </summary>
+        /// <value>The fill.</value>
+        public OxyColor Fill { get; set; }
+
+        /// <summary>
+        /// Gets the second list of points.
+        /// </summary>
+        /// <value>The second list of points.</value>
+        public List<IDataPoint> Points2
+        {
+            get
+            {
+                return this.points2;
+            }
+        }
+
+        /// <summary>
+        /// 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.
+        /// </summary>
+        public bool Reverse2 { get; set; }
+
+        /// <summary>
+        /// Gets the nearest point.
+        /// </summary>
+        /// <param name="point">The point.</param>
+        /// <param name="interpolate">interpolate if set to <c>true</c> .</param>
+        /// <returns>A TrackerHitResult for the current hit.</returns>
+        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;
+        }
+
+        /// <summary>
+        /// Renders the series on the specified rendering context.
+        /// </summary>
+        /// <param name="rc">The rendering context.</param>
+        /// <param name="model">The owner plot model.</param>
+        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<ScreenPoint> 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<ScreenPoint> 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<ScreenPoint>();
+            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);
+        }
+
+        /// <summary>
+        /// Renders the legend symbol for the line series on the
+        /// specified rendering context.
+        /// </summary>
+        /// <param name="rc">
+        /// The rendering context.
+        /// </param>
+        /// <param name="legendBox">
+        /// The bounding rectangle of the legend box.
+        /// </param>
+        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<ScreenPoint>();
+            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);
+        }
+
+        /// <summary>
+        /// The update data.
+        /// </summary>
+        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);
+        }
+
+        /// <summary>
+        /// The update max min.
+        /// </summary>
+        protected internal override void UpdateMaxMin()
+        {
+            base.UpdateMaxMin();
+            this.InternalUpdateMaxMin(this.points2);
+        }
+
+    }
+}
\ No newline at end of file
diff --git a/oxyplot/OxyPlot/Series/BarSeries/BarItem.cs b/oxyplot/OxyPlot/Series/BarSeries/BarItem.cs
new file mode 100644
index 0000000..faa1ecf
--- /dev/null
+++ b/oxyplot/OxyPlot/Series/BarSeries/BarItem.cs
@@ -0,0 +1,64 @@
+// 
--------------------------------------------------------------------------------------------------------------------
+// <copyright file="BarItem.cs" company="OxyPlot">
+//   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.
+// </copyright>
+// <summary>
+//   Represents an item used in the BarSeries.
+// </summary>
+// 
--------------------------------------------------------------------------------------------------------------------
+namespace OxyPlot.Series
+{
+    /// <summary>
+    /// Represents an item used in the BarSeries.
+    /// </summary>
+    public class BarItem : BarItemBase
+    {
+        /// <summary>
+        /// Initializes a new instance of the <see cref="BarItem"/> class.
+        /// </summary>
+        public BarItem()
+        {
+        }
+
+        /// <summary>
+        /// Initializes a new instance of the <see cref="BarItem"/> class.
+        /// </summary>
+        /// <param name="value">
+        /// The value.
+        /// </param>
+        /// <param name="categoryIndex">
+        /// Index of the category.
+        /// </param>
+        /// <param name="color">
+        /// The color.
+        /// </param>
+        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 --git a/oxyplot/OxyPlot/Series/BarSeries/BarItemBase.cs b/oxyplot/OxyPlot/Series/BarSeries/BarItemBase.cs
new file mode 100644
index 0000000..8641536
--- /dev/null
+++ b/oxyplot/OxyPlot/Series/BarSeries/BarItemBase.cs
@@ -0,0 +1,83 @@
+// 
--------------------------------------------------------------------------------------------------------------------
+// <copyright file="BarItemBase.cs" company="OxyPlot">
+//   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.
+// </copyright>
+// <summary>
+//   Represents an item used in the BarSeriesBase.
+// </summary>
+// 
--------------------------------------------------------------------------------------------------------------------
+namespace OxyPlot.Series
+{
+    /// <summary>
+    /// Represents an item used in the BarSeriesBase.
+    /// </summary>
+    public abstract class BarItemBase : CategorizedItem, ICodeGenerating
+    {
+        /// <summary>
+        /// Initializes a new instance of the <see cref="BarItemBase"/> class. Initializes a new instance of 
the <see cref="BarItem"/> class.
+        /// </summary>
+        protected BarItemBase()
+        {
+            // Label = null;
+            this.Value = double.NaN;
+            this.Color = null;
+        }
+
+        /// <summary>
+        /// Gets or sets the color of the item.
+        /// </summary>
+        /// <remarks>
+        /// If the color is not specified (default), the color of the series will be used.
+        /// </remarks>
+        public OxyColor Color { get; set; }
+
+        /// <summary>
+        /// Gets or sets the value of the item.
+        /// </summary>
+        public double Value { get; set; }
+
+        /// <summary>
+        /// Returns c# code that generates this instance.
+        /// </summary>
+        /// <returns>
+        /// C# code.
+        /// </returns>
+        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 --git a/oxyplot/OxyPlot/Series/BarSeries/BarSeries.cs b/oxyplot/OxyPlot/Series/BarSeries/BarSeries.cs
new file mode 100644
index 0000000..b117fcb
--- /dev/null
+++ b/oxyplot/OxyPlot/Series/BarSeries/BarSeries.cs
@@ -0,0 +1,198 @@
+// 
--------------------------------------------------------------------------------------------------------------------
+// <copyright file="BarSeries.cs" company="OxyPlot">
+//   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.
+// </copyright>
+// <summary>
+//   Represents a series for clustered or stacked bar charts.
+// </summary>
+// 
--------------------------------------------------------------------------------------------------------------------
+namespace OxyPlot.Series
+{
+    using System;
+
+    using OxyPlot.Axes;
+
+    /// <summary>
+    /// Represents a series for clustered or stacked bar charts.
+    /// </summary>
+    public class BarSeries : BarSeriesBase<BarItem>
+    {
+        /// <summary>
+        /// Initializes a new instance of the <see cref="BarSeries"/> class.
+        /// </summary>
+        public BarSeries()
+        {
+            this.BarWidth = 1;
+        }
+
+        /// <summary>
+        /// Gets or sets the width (height) of the bars.
+        /// </summary>
+        /// <value>
+        /// The width of the bars.
+        /// </value>
+        public double BarWidth { get; set; }
+
+        /// <summary>
+        /// Gets or sets the width of the columns/bars (as a fraction of the available space).
+        /// </summary>
+        /// <returns>
+        /// The fractional width.
+        /// </returns>
+        /// <value>
+        /// The width of the bars.
+        /// </value>
+        /// <remarks>
+        /// The available space will be determined by the GapWidth of the CategoryAxis used by this series.
+        /// </remarks>
+        internal override double GetBarWidth()
+        {
+            return this.BarWidth;
+        }
+
+        /// <summary>
+        /// Gets the actual width/height of the items of this series.
+        /// </summary>
+        /// <returns>
+        /// The width or height.
+        /// </returns>
+        /// <remarks>
+        /// The actual width is also influenced by the GapWidth of the CategoryAxis used by this series.
+        /// </remarks>
+        protected override double GetActualBarWidth()
+        {
+            var categoryAxis = this.GetCategoryAxis();
+            return this.BarWidth / (1 + categoryAxis.GapWidth) / categoryAxis.MaxWidth;
+        }
+
+        /// <summary>
+        /// Gets the category axis.
+        /// </summary>
+        /// <returns>
+        /// The category axis.
+        /// </returns>
+        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;
+        }
+
+        /// <summary>
+        /// Gets the rectangle for the specified values.
+        /// </summary>
+        /// <param name="baseValue">
+        /// The base value of the bar
+        /// </param>
+        /// <param name="topValue">
+        /// The top value of the bar
+        /// </param>
+        /// <param name="beginValue">
+        /// The begin value of the bar
+        /// </param>
+        /// <param name="endValue">
+        /// The end value of the bar
+        /// </param>
+        /// <returns>
+        /// The rectangle.
+        /// </returns>
+        protected override OxyRect GetRectangle(double baseValue, double topValue, double beginValue, double 
endValue)
+        {
+            return OxyRect.Create(this.Transform(baseValue, beginValue), this.Transform(topValue, endValue));
+        }
+
+        /// <summary>
+        /// Gets the value axis.
+        /// </summary>
+        /// <returns>
+        /// The value axis.
+        /// </returns>
+        protected override Axis GetValueAxis()
+        {
+            return this.XAxis;
+        }
+
+        /// <summary>
+        /// Draws the label.
+        /// </summary>
+        /// <param name="rc">
+        /// The render context.
+        /// </param>
+        /// <param name="clippingRect">
+        /// The clipping rect.
+        /// </param>
+        /// <param name="rect">
+        /// The rect.
+        /// </param>
+        /// <param name="value">
+        /// The value.
+        /// </param>
+        /// <param name="i">
+        /// The i.
+        /// </param>
+        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 --git a/oxyplot/OxyPlot/Series/BarSeries/BarSeriesBase.cs 
b/oxyplot/OxyPlot/Series/BarSeries/BarSeriesBase.cs
new file mode 100644
index 0000000..5d55af0
--- /dev/null
+++ b/oxyplot/OxyPlot/Series/BarSeries/BarSeriesBase.cs
@@ -0,0 +1,603 @@
+// 
--------------------------------------------------------------------------------------------------------------------
+// <copyright file="BarSeriesBase.cs" company="OxyPlot">
+//   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.
+// </copyright>
+// <summary>
+//   Base class for BarSeries and ColumnSeries.
+// </summary>
+// 
--------------------------------------------------------------------------------------------------------------------
+namespace OxyPlot.Series
+{
+    using System;
+    using System.Collections.Generic;
+    using System.Linq;
+
+    using OxyPlot.Axes;
+
+    /// <summary>
+    /// Base class for BarSeries and ColumnSeries.
+    /// </summary>
+    public abstract class BarSeriesBase : CategorizedSeries, IStackableSeries
+    {
+        /// <summary>
+        /// The default fill color.
+        /// </summary>
+        private OxyColor defaultFillColor;
+
+        /// <summary>
+        /// Initializes a new instance of the <see cref="BarSeriesBase"/> class.
+        /// </summary>
+        protected BarSeriesBase()
+        {
+            this.StrokeColor = OxyColors.Black;
+            this.StrokeThickness = 0;
+            this.TrackerFormatString = "{0}, {1}: {2}";
+            this.LabelMargin = 2;
+            this.StackGroup = string.Empty;
+        }
+
+        /// <summary>
+        /// Gets or sets the base value.
+        /// </summary>
+        /// <value>
+        /// The base value.
+        /// </value>
+        public double BaseValue { get; set; }
+
+        /// <summary>
+        /// Gets or sets the color field.
+        /// </summary>
+        public string ColorField { get; set; }
+
+        /// <summary>
+        /// Gets or sets the color of the interior of the bars.
+        /// </summary>
+        /// <value>
+        /// The color.
+        /// </value>
+        public OxyColor FillColor { get; set; }
+
+        /// <summary>
+        /// Gets the actual fill color.
+        /// </summary>
+        /// <value>The actual color.</value>
+        public OxyColor ActualFillColor
+        {
+            get { return this.FillColor ?? this.defaultFillColor; }
+        }
+
+        /// <summary>
+        /// Gets or sets a value indicating whether this bar series is stacked.
+        /// </summary>
+        public bool IsStacked { get; set; }
+
+        /// <summary>
+        /// Gets or sets the label format string.
+        /// </summary>
+        /// <value>
+        /// The label format string.
+        /// </value>
+        public string LabelFormatString { get; set; }
+
+        /// <summary>
+        /// Gets or sets the label margins.
+        /// </summary>
+        public double LabelMargin { get; set; }
+
+        /// <summary>
+        /// Gets or sets label placements.
+        /// </summary>
+        public LabelPlacement LabelPlacement { get; set; }
+
+        /// <summary>
+        /// Gets or sets the color of the interior of the bars when the value is negative.
+        /// </summary>
+        /// <value>
+        /// The color.
+        /// </value>
+        public OxyColor NegativeFillColor { get; set; }
+
+        /// <summary>
+        /// 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.
+        /// </summary>
+        public string StackGroup { get; set; }
+
+        /// <summary>
+        /// Gets or sets the color of the border around the bars.
+        /// </summary>
+        /// <value>
+        /// The color of the stroke.
+        /// </value>
+        public OxyColor StrokeColor { get; set; }
+
+        /// <summary>
+        /// Gets or sets the thickness of the bar border strokes.
+        /// </summary>
+        /// <value>
+        /// The stroke thickness.
+        /// </value>
+        public double StrokeThickness { get; set; }
+
+        /// <summary>
+        /// Gets or sets the value field.
+        /// </summary>
+        public string ValueField { get; set; }
+
+        /// <summary>
+        /// Gets or sets the valid items
+        /// </summary>
+        protected internal IList<BarItemBase> ValidItems { get; set; }
+
+        /// <summary>
+        /// Gets or sets the dictionary which stores the index-inversion for the valid items
+        /// </summary>
+        protected internal Dictionary<int, int> ValidItemsIndexInversion { get; set; }
+
+        /// <summary>
+        /// Gets or sets the actual rectangles for the bars.
+        /// </summary>
+        protected IList<OxyRect> ActualBarRectangles { get; set; }
+
+        /// <summary>
+        /// Gets the nearest point.
+        /// </summary>
+        /// <param name="point">
+        /// The point.
+        /// </param>
+        /// <param name="interpolate">
+        /// interpolate if set to <c>true</c> .
+        /// </param>
+        /// <returns>
+        /// A TrackerHitResult for the current hit.
+        /// </returns>
+        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;
+        }
+
+        /// <summary>
+        /// Renders the series on the specified rendering context.
+        /// </summary>
+        /// <param name="rc">
+        /// The rendering context.
+        /// </param>
+        /// <param name="model">
+        /// The model.
+        /// </param>
+        public override void Render(IRenderContext rc, PlotModel model)
+        {
+            this.ActualBarRectangles = new List<OxyRect>();
+
+            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;
+                }
+            }
+        }
+
+        /// <summary>
+        /// Renders the legend symbol on the specified rendering context.
+        /// </summary>
+        /// <param name="rc">
+        /// The rendering context.
+        /// </param>
+        /// <param name="legendBox">
+        /// The legend rectangle.
+        /// </param>
+        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);
+        }
+
+        /// <summary>
+        /// Check if the data series is using the specified axis.
+        /// </summary>
+        /// <param name="axis">
+        /// An axis which should be checked if used
+        /// </param>
+        /// <returns>
+        /// True if the axis is in use.
+        /// </returns>
+        protected internal override bool IsUsing(Axis axis)
+        {
+            return this.XAxis == axis || this.YAxis == axis;
+        }
+
+        /// <summary>
+        /// The set default values.
+        /// </summary>
+        /// <param name="model">
+        /// The model.
+        /// </param>
+        protected internal override void SetDefaultValues(PlotModel model)
+        {
+            if (this.FillColor == null)
+            {
+                this.defaultFillColor = model.GetDefaultColor();
+            }
+        }
+
+        /// <summary>
+        /// The update axis max min.
+        /// </summary>
+        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);
+            }
+        }
+
+        /// <summary>
+        /// Updates the maximum/minimum value on the value axis from the bar values.
+        /// </summary>
+        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;
+            }
+        }
+
+        /// <summary>
+        /// Updates the valid items
+        /// </summary>
+        protected internal override void UpdateValidData()
+        {
+            this.ValidItems = new List<BarItemBase>();
+            this.ValidItemsIndexInversion = new Dictionary<int, int>();
+            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++;
+            }
+        }
+
+        /// <summary>
+        /// Gets the rectangle for the specified values.
+        /// </summary>
+        /// <param name="baseValue">
+        /// The base value of the bar
+        /// </param>
+        /// <param name="topValue">
+        /// The top value of the bar
+        /// </param>
+        /// <param name="beginValue">
+        /// The begin value of the bar
+        /// </param>
+        /// <param name="endValue">
+        /// The end value of the bar
+        /// </param>
+        /// <returns>
+        /// The rectangle.
+        /// </returns>
+        protected abstract OxyRect GetRectangle(double baseValue, double topValue, double beginValue, double 
endValue);
+
+        /// <summary>
+        /// Gets the tracker text for the specified item.
+        /// </summary>
+        /// <param name="item">
+        /// The item.
+        /// </param>
+        /// <param name="categoryIndex">
+        /// Category index of the item.
+        /// </param>
+        /// <returns>
+        /// The tracker text.
+        /// </returns>
+        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;
+        }
+
+        /// <summary>
+        /// Gets the value axis.
+        /// </summary>
+        /// <returns>
+        /// The value axis.
+        /// </returns>
+        protected abstract Axis GetValueAxis();
+
+        /// <summary>
+        /// Checks if the specified value is valid.
+        /// </summary>
+        /// <param name="v">
+        /// The value.
+        /// </param>
+        /// <param name="yaxis">
+        /// The y axis.
+        /// </param>
+        /// <returns>
+        /// True if the value is valid.
+        /// </returns>
+        protected virtual bool IsValidPoint(double v, Axis yaxis)
+        {
+            return !double.IsNaN(v) && !double.IsInfinity(v);
+        }
+
+        /// <summary>
+        /// Renders the bar/column item.
+        /// </summary>
+        /// <param name="rc">
+        /// The render context.
+        /// </param>
+        /// <param name="clippingRect">
+        /// The clipping rectangle.
+        /// </param>
+        /// <param name="topValue">
+        /// The end value of the bar.
+        /// </param>
+        /// <param name="categoryValue">
+        /// The category value.
+        /// </param>
+        /// <param name="actualBarWidth">
+        /// The actual width of the bar.
+        /// </param>
+        /// <param name="item">
+        /// The item.
+        /// </param>
+        /// <param name="rect">
+        /// The rectangle of the bar.
+        /// </param>
+        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);
+        }
+
+        /// <summary>
+        /// Renders the item label.
+        /// </summary>
+        /// <param name="rc">
+        /// The render context
+        /// </param>
+        /// <param name="clippingRect">
+        /// The clipping rectangle
+        /// </param>
+        /// <param name="rect">
+        /// The rectangle of the item.
+        /// </param>
+        /// <param name="value">
+        /// The value of the label.
+        /// </param>
+        /// <param name="index">
+        /// The index of the bar item.
+        /// </param>
+        protected abstract void RenderLabel(
+            IRenderContext rc, OxyRect clippingRect, OxyRect rect, double value, int index);
+
+    }
+}
\ No newline at end of file
diff --git a/oxyplot/OxyPlot/Series/BarSeries/BarSeriesBase{T}.cs 
b/oxyplot/OxyPlot/Series/BarSeries/BarSeriesBase{T}.cs
new file mode 100644
index 0000000..d206196
--- /dev/null
+++ b/oxyplot/OxyPlot/Series/BarSeries/BarSeriesBase{T}.cs
@@ -0,0 +1,113 @@
+// 
--------------------------------------------------------------------------------------------------------------------
+// <copyright file="BarSeriesBase{T}.cs" company="OxyPlot">
+//   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.
+// </copyright>
+// <summary>
+//   Generic base class that provides common properties and methods for the BarSeries and ColumnSeries.
+// </summary>
+// 
--------------------------------------------------------------------------------------------------------------------
+namespace OxyPlot.Series
+{
+    using System;
+    using System.Collections;
+    using System.Collections.Generic;
+    using System.Linq;
+
+    /// <summary>
+    /// Generic base class that provides common properties and methods for the BarSeries and ColumnSeries.
+    /// </summary>
+    /// <typeparam name="T">
+    /// The type of the items.
+    /// </typeparam>
+    public abstract class BarSeriesBase<T> : BarSeriesBase
+        where T : BarItemBase, new()
+    {
+        /// <summary>
+        /// Initializes a new instance of the <see cref="BarSeriesBase{T}"/> class. Initializes a new 
instance of the <see cref="BarSeriesBase&lt;T&gt;"/> class.
+        /// </summary>
+        protected BarSeriesBase()
+        {
+            this.Items = new List<T>();
+        }
+
+        /// <summary>
+        /// Gets the items.
+        /// </summary>
+        /// <value>
+        /// The items.
+        /// </value>
+        public IList<T> Items { get; private set; }
+
+        /// <summary>
+        /// Gets the items of this series.
+        /// </summary>
+        /// <returns>
+        /// The items.
+        /// </returns>
+        protected internal override IList<CategorizedItem> GetItems()
+        {
+            return this.Items.Cast<CategorizedItem>().ToList();
+        }
+
+        /// <summary>
+        /// Updates the data.
+        /// </summary>
+        protected internal override void UpdateData()
+        {
+            if (this.ItemsSource == null)
+            {
+                return;
+            }
+
+            var dest = new List<T>();
+
+            // Using reflection to add points
+            var filler = new ListFiller<T>();
+            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;
+        }
+
+        /// <summary>
+        /// Gets the item at the specified index.
+        /// </summary>
+        /// <param name="i">
+        /// The index of the item.
+        /// </param>
+        /// <returns>
+        /// The item of the index.
+        /// </returns>
+        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 --git a/oxyplot/OxyPlot/Series/BarSeries/CategorizedItem.cs 
b/oxyplot/OxyPlot/Series/BarSeries/CategorizedItem.cs
new file mode 100644
index 0000000..cfc34be
--- /dev/null
+++ b/oxyplot/OxyPlot/Series/BarSeries/CategorizedItem.cs
@@ -0,0 +1,73 @@
+// 
--------------------------------------------------------------------------------------------------------------------
+// <copyright file="CategorizedItem.cs" company="OxyPlot">
+//   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.
+// </copyright>
+// <summary>
+//   Represents an item in a CategorizedSeries.
+// </summary>
+// 
--------------------------------------------------------------------------------------------------------------------
+namespace OxyPlot.Series
+{
+    /// <summary>
+    /// Represents an item in a CategorizedSeries.
+    /// </summary>
+    public abstract class CategorizedItem
+    {
+        /// <summary>
+        /// Initializes a new instance of the <see cref="CategorizedItem"/> class. Initializes a new 
instance of the <see cref="CategorizedItem"/> class.
+        /// </summary>
+        protected CategorizedItem()
+        {
+            this.CategoryIndex = -1;
+        }
+
+        /// <summary>
+        /// Gets or sets the index of the category.
+        /// </summary>
+        /// <value>
+        /// The index of the category.
+        /// </value>
+        public int CategoryIndex { get; set; }
+
+        /// <summary>
+        /// Gets the index of the category.
+        /// </summary>
+        /// <param name="defaultIndex">
+        /// The default index.
+        /// </param>
+        /// <returns>
+        /// The index.
+        /// </returns>
+        internal int GetCategoryIndex(int defaultIndex)
+        {
+            if (this.CategoryIndex < 0)
+            {
+                return defaultIndex;
+            }
+
+            return this.CategoryIndex;
+        }
+
+    }
+}
\ No newline at end of file
diff --git a/oxyplot/OxyPlot/Series/BarSeries/CategorizedSeries.cs 
b/oxyplot/OxyPlot/Series/BarSeries/CategorizedSeries.cs
new file mode 100644
index 0000000..9eaaf65
--- /dev/null
+++ b/oxyplot/OxyPlot/Series/BarSeries/CategorizedSeries.cs
@@ -0,0 +1,83 @@
+// 
--------------------------------------------------------------------------------------------------------------------
+// <copyright file="CategorizedSeries.cs" company="OxyPlot">
+//   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.
+// </copyright>
+// <summary>
+//   Base class for series where the items are categorized.
+// </summary>
+// 
--------------------------------------------------------------------------------------------------------------------
+namespace OxyPlot.Series
+{
+    using System.Collections.Generic;
+
+    using OxyPlot.Axes;
+
+    /// <summary>
+    /// Base class for series where the items are categorized.
+    /// </summary>
+    public abstract class CategorizedSeries : XYAxisSeries
+    {
+        /// <summary>
+        /// Gets or sets the width/height of the columns/bars (as a fraction of the available space).
+        /// </summary>
+        /// <returns>
+        /// The fractional width.
+        /// </returns>
+        /// <value>
+        /// The width of the bars.
+        /// </value>
+        /// <remarks>
+        /// The available space will be determined by the GapWidth of the CategoryAxis used by this series.
+        /// </remarks>
+        internal abstract double GetBarWidth();
+
+        /// <summary>
+        /// Gets the items of this series.
+        /// </summary>
+        /// <returns>
+        /// The items.
+        /// </returns>
+        protected internal abstract IList<CategorizedItem> GetItems();
+
+        /// <summary>
+        /// Gets the actual bar width/height of the items in this series.
+        /// </summary>
+        /// <returns>
+        /// The width or height.
+        /// </returns>
+        /// <remarks>
+        /// The actual width is also influenced by the GapWidth of the CategoryAxis used by this series.
+        /// </remarks>
+        protected abstract double GetActualBarWidth();
+
+        /// <summary>
+        /// Gets the category axis.
+        /// </summary>
+        /// <returns>
+        /// The category axis.
+        /// </returns>
+        protected abstract CategoryAxis GetCategoryAxis();
+
+    }
+}
\ No newline at end of file
diff --git a/oxyplot/OxyPlot/Series/BarSeries/ColumnItem.cs b/oxyplot/OxyPlot/Series/BarSeries/ColumnItem.cs
new file mode 100644
index 0000000..87c0d8a
--- /dev/null
+++ b/oxyplot/OxyPlot/Series/BarSeries/ColumnItem.cs
@@ -0,0 +1,64 @@
+// 
--------------------------------------------------------------------------------------------------------------------
+// <copyright file="ColumnItem.cs" company="OxyPlot">
+//   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.
+// </copyright>
+// <summary>
+//   Represents an item used in the ColumnSeries.
+// </summary>
+// 
--------------------------------------------------------------------------------------------------------------------
+namespace OxyPlot.Series
+{
+    /// <summary>
+    /// Represents an item used in the ColumnSeries.
+    /// </summary>
+    public class ColumnItem : BarItemBase
+    {
+        /// <summary>
+        /// Initializes a new instance of the <see cref="ColumnItem"/> class.
+        /// </summary>
+        public ColumnItem()
+        {
+        }
+
+        /// <summary>
+        /// Initializes a new instance of the <see cref="ColumnItem"/> class.
+        /// </summary>
+        /// <param name="value">
+        /// The value.
+        /// </param>
+        /// <param name="categoryIndex">
+        /// Index of the category.
+        /// </param>
+        /// <param name="color">
+        /// The color.
+        /// </param>
+        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 --git a/oxyplot/OxyPlot/Series/BarSeries/ColumnSeries.cs 
b/oxyplot/OxyPlot/Series/BarSeries/ColumnSeries.cs
new file mode 100644
index 0000000..7eb81fa
--- /dev/null
+++ b/oxyplot/OxyPlot/Series/BarSeries/ColumnSeries.cs
@@ -0,0 +1,198 @@
+// 
--------------------------------------------------------------------------------------------------------------------
+// <copyright file="ColumnSeries.cs" company="OxyPlot">
+//   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.
+// </copyright>
+// <summary>
+//   Represents a series for clustered or stacked column charts.
+// </summary>
+// 
--------------------------------------------------------------------------------------------------------------------
+namespace OxyPlot.Series
+{
+    using System;
+
+    using OxyPlot.Axes;
+
+    /// <summary>
+    /// Represents a series for clustered or stacked column charts.
+    /// </summary>
+    public class ColumnSeries : BarSeriesBase<ColumnItem>
+    {
+        /// <summary>
+        /// Initializes a new instance of the <see cref="ColumnSeries"/> class.
+        /// </summary>
+        public ColumnSeries()
+        {
+            this.ColumnWidth = 1;
+        }
+
+        /// <summary>
+        /// Gets or sets the width of the column.
+        /// </summary>
+        /// <value>
+        /// The width of the column.
+        /// </value>
+        public double ColumnWidth { get; set; }
+
+        /// <summary>
+        /// Gets or sets the width/height of the columns/bars (as a fraction of the available space).
+        /// </summary>
+        /// <returns>
+        /// The fractional width.
+        /// </returns>
+        /// <value>
+        /// The width of the bars.
+        /// </value>
+        /// <remarks>
+        /// The available space will be determined by the GapWidth of the CategoryAxis used by this series.
+        /// </remarks>
+        internal override double GetBarWidth()
+        {
+            return this.ColumnWidth;
+        }
+
+        /// <summary>
+        /// Gets the actual width/height of the items of this series.
+        /// </summary>
+        /// <returns>
+        /// The width or height.
+        /// </returns>
+        /// <remarks>
+        /// The actual width is also influenced by the GapWidth of the CategoryAxis used by this series.
+        /// </remarks>
+        protected override double GetActualBarWidth()
+        {
+            var categoryAxis = this.GetCategoryAxis();
+            return this.ColumnWidth / (1 + categoryAxis.GapWidth) / categoryAxis.MaxWidth;
+        }
+
+        /// <summary>
+        /// Gets the category axis.
+        /// </summary>
+        /// <returns>
+        /// The category axis.
+        /// </returns>
+        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;
+        }
+
+        /// <summary>
+        /// Gets the rectangle for the specified values.
+        /// </summary>
+        /// <param name="baseValue">
+        /// The base value of the bar
+        /// </param>
+        /// <param name="topValue">
+        /// The top value of the bar
+        /// </param>
+        /// <param name="beginValue">
+        /// The begin value of the bar
+        /// </param>
+        /// <param name="endValue">
+        /// The end value of the bar
+        /// </param>
+        /// <returns>
+        /// The rectangle.
+        /// </returns>
+        protected override OxyRect GetRectangle(double baseValue, double topValue, double beginValue, double 
endValue)
+        {
+            return OxyRect.Create(this.Transform(beginValue, baseValue), this.Transform(endValue, topValue));
+        }
+
+        /// <summary>
+        /// Gets the value axis.
+        /// </summary>
+        /// <returns>
+        /// The value axis.
+        /// </returns>
+        protected override Axis GetValueAxis()
+        {
+            return this.YAxis;
+        }
+
+        /// <summary>
+        /// Draws the label.
+        /// </summary>
+        /// <param name="rc">
+        /// The render context.
+        /// </param>
+        /// <param name="clippingRect">
+        /// The clipping rect.
+        /// </param>
+        /// <param name="rect">
+        /// The rect.
+        /// </param>
+        /// <param name="value">
+        /// The value.
+        /// </param>
+        /// <param name="i">
+        /// The i.
+        /// </param>
+        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 --git a/oxyplot/OxyPlot/Series/BarSeries/ErrorColumnItem.cs 
b/oxyplot/OxyPlot/Series/BarSeries/ErrorColumnItem.cs
new file mode 100644
index 0000000..bc1e3ba
--- /dev/null
+++ b/oxyplot/OxyPlot/Series/BarSeries/ErrorColumnItem.cs
@@ -0,0 +1,96 @@
+// 
--------------------------------------------------------------------------------------------------------------------
+// <copyright file="ErrorColumnItem.cs" company="OxyPlot">
+//   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.
+// </copyright>
+// <summary>
+//   Represents an item used in the ErrorColumnSeries.
+// </summary>
+// 
--------------------------------------------------------------------------------------------------------------------
+namespace OxyPlot.Series
+{
+    /// <summary>
+    /// Represents an item used in the ErrorColumnSeries.
+    /// </summary>
+    public class ErrorColumnItem : ColumnItem
+    {
+        /// <summary>
+        /// Initializes a new instance of the <see cref="ErrorColumnItem"/> class.
+        /// </summary>
+        public ErrorColumnItem()
+        {
+        }
+
+        /// <summary>
+        /// Initializes a new instance of the <see cref="ErrorColumnItem"/> class.
+        /// </summary>
+        /// <param name="value">
+        /// The value.
+        /// </param>
+        /// <param name="error">
+        /// The error.
+        /// </param>
+        /// <param name="categoryIndex">
+        /// Index of the category.
+        /// </param>
+        /// <param name="color">
+        /// The color.
+        /// </param>
+        public ErrorColumnItem(double value, double error, int categoryIndex = -1, OxyColor color = null)
+        {
+            this.Value = value;
+            this.Error = error;
+            this.CategoryIndex = categoryIndex;
+            this.Color = color;
+        }
+
+        /// <summary>
+        /// Gets or sets the error of the item.
+        /// </summary>
+        public double Error { get; set; }
+
+        /// <summary>
+        /// Returns c# code that generates this instance.
+        /// </summary>
+        /// <returns>
+        /// C# code.
+        /// </returns>
+        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 --git a/oxyplot/OxyPlot/Series/BarSeries/ErrorColumnSeries.cs 
b/oxyplot/OxyPlot/Series/BarSeries/ErrorColumnSeries.cs
new file mode 100644
index 0000000..7ea97b7
--- /dev/null
+++ b/oxyplot/OxyPlot/Series/BarSeries/ErrorColumnSeries.cs
@@ -0,0 +1,240 @@
+// 
--------------------------------------------------------------------------------------------------------------------
+// <copyright file="ErrorColumnSeries.cs" company="OxyPlot">
+//   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.
+// </copyright>
+// <summary>
+//   Represents a series for clustered or stacked column charts with an error value.
+// </summary>
+// 
--------------------------------------------------------------------------------------------------------------------
+namespace OxyPlot.Series
+{
+    using System;
+    using System.Collections.Generic;
+    using System.Linq;
+
+    /// <summary>
+    /// Represents a series for clustered or stacked column charts with an error value.
+    /// </summary>
+    public class ErrorColumnSeries : ColumnSeries
+    {
+        /// <summary>
+        /// Initializes a new instance of the <see cref="ErrorColumnSeries"/> class.
+        /// </summary>
+        public ErrorColumnSeries()
+        {
+            this.ErrorWidth = 0.4;
+            this.ErrorStrokeThickness = 1;
+            this.TrackerFormatString = "{0}, {1}: {2}, Error: {Error}";
+        }
+
+        /// <summary>
+        /// Gets or sets the stroke thickness of the error line.
+        /// </summary>
+        /// <value>
+        /// The stroke thickness of the error line.
+        /// </value>
+        public double ErrorStrokeThickness { get; set; }
+
+        /// <summary>
+        /// Gets or sets the width of the error end lines.
+        /// </summary>
+        /// <value>
+        /// The width of the error end lines.
+        /// </value>
+        public double ErrorWidth { get; set; }
+
+        /// <summary>
+        /// Updates the maximum/minimum value on the value axis from the bar values.
+        /// </summary>
+        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;
+            }
+        }
+
+        /// <summary>
+        /// Renders the bar/column item.
+        /// </summary>
+        /// <param name="rc">
+        /// The render context.
+        /// </param>
+        /// <param name="clippingRect">
+        /// The clipping rectangle.
+        /// </param>
+        /// <param name="topValue">
+        /// The end value of the bar.
+        /// </param>
+        /// <param name="categoryValue">
+        /// The category value.
+        /// </param>
+        /// <param name="actualBarWidth">
+        /// The actual width of the bar.
+        /// </param>
+        /// <param name="item">
+        /// The item.
+        /// </param>
+        /// <param name="rect">
+        /// The rectangle of the bar.
+        /// </param>
+        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<ScreenPoint> { 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<ScreenPoint> { 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<ScreenPoint> { upperLeftErrorPoint, upperRightErrorPoint },
+                    clippingRect,
+                    0,
+                    this.StrokeColor,
+                    this.ErrorStrokeThickness,
+                    LineStyle.Solid,
+                    OxyPenLineJoin.Miter,
+                    true);
+            }
+        }
+
+    }
+}
\ No newline at end of file
diff --git a/oxyplot/OxyPlot/Series/BarSeries/IStackableSeries.cs 
b/oxyplot/OxyPlot/Series/BarSeries/IStackableSeries.cs
new file mode 100644
index 0000000..e1553b1
--- /dev/null
+++ b/oxyplot/OxyPlot/Series/BarSeries/IStackableSeries.cs
@@ -0,0 +1,50 @@
+// 
--------------------------------------------------------------------------------------------------------------------
+// <copyright file="IStackableSeries.cs" company="OxyPlot">
+//   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.
+// </copyright>
+// <summary>
+//   Specifies a series that can be stacked.
+// </summary>
+// 
--------------------------------------------------------------------------------------------------------------------
+namespace OxyPlot.Series
+{
+    /// <summary>
+    /// Defines properties for stacked series.
+    /// </summary>
+    public interface IStackableSeries
+    {
+        /// <summary>
+        /// Gets a value indicating whether this series is stacked.
+        /// </summary>
+        bool IsStacked { get; }
+
+        /// <summary>
+        /// Gets the stack group.
+        /// </summary>
+        /// <value>
+        /// The stack group.
+        /// </value>
+        string StackGroup { get; }
+    }
+}
\ No newline at end of file
diff --git a/oxyplot/OxyPlot/Series/BarSeries/IntervalBarItem.cs 
b/oxyplot/OxyPlot/Series/BarSeries/IntervalBarItem.cs
new file mode 100644
index 0000000..6fee3a5
--- /dev/null
+++ b/oxyplot/OxyPlot/Series/BarSeries/IntervalBarItem.cs
@@ -0,0 +1,110 @@
+// 
--------------------------------------------------------------------------------------------------------------------
+// <copyright file="IntervalBarItem.cs" company="OxyPlot">
+//   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.
+// </copyright>
+// <summary>
+//   Represents an item in an IntervalBarSeries.
+// </summary>
+// 
--------------------------------------------------------------------------------------------------------------------
+namespace OxyPlot.Series
+{
+    /// <summary>
+    /// Represents an item in an IntervalBarSeries.
+    /// </summary>
+    public class IntervalBarItem : CategorizedItem, ICodeGenerating
+    {
+        /// <summary>
+        /// Initializes a new instance of the <see cref="IntervalBarItem"/> class.
+        /// </summary>
+        public IntervalBarItem()
+        {
+        }
+
+        /// <summary>
+        /// Initializes a new instance of the <see cref="IntervalBarItem"/> class.
+        /// </summary>
+        /// <param name="start">
+        /// The start.
+        /// </param>
+        /// <param name="end">
+        /// The end.
+        /// </param>
+        /// <param name="title">
+        /// The title.
+        /// </param>
+        /// <param name="color">
+        /// The color.
+        /// </param>
+        public IntervalBarItem(double start, double end, string title = null, OxyColor color = null)
+        {
+            this.Start = start;
+            this.End = end;
+            this.Title = title;
+            this.Color = color;
+        }
+
+        /// <summary>
+        /// Gets or sets the color.
+        /// </summary>
+        public OxyColor Color { get; set; }
+
+        /// <summary>
+        /// Gets or sets the end value.
+        /// </summary>
+        public double End { get; set; }
+
+        /// <summary>
+        /// Gets or sets the start value.
+        /// </summary>
+        public double Start { get; set; }
+
+        /// <summary>
+        /// Gets or sets the title.
+        /// </summary>
+        public string Title { get; set; }
+
+        /// <summary>
+        /// Returns c# code that generates this instance.
+        /// </summary>
+        /// <returns>
+        /// C# code.
+        /// </returns>
+        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 --git a/oxyplot/OxyPlot/Series/BarSeries/IntervalBarSeries.cs 
b/oxyplot/OxyPlot/Series/BarSeries/IntervalBarSeries.cs
new file mode 100644
index 0000000..e84577e
--- /dev/null
+++ b/oxyplot/OxyPlot/Series/BarSeries/IntervalBarSeries.cs
@@ -0,0 +1,515 @@
+// 
--------------------------------------------------------------------------------------------------------------------
+// <copyright file="IntervalBarSeries.cs" company="OxyPlot">
+//   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.
+// </copyright>
+// <summary>
+//   Represents a series for bar charts defined by to/from values.
+// </summary>
+// 
--------------------------------------------------------------------------------------------------------------------
+namespace OxyPlot.Series
+{
+    using System;
+    using System.Collections.Generic;
+    using System.Linq;
+
+    using OxyPlot.Axes;
+
+    /// <summary>
+    /// Represents a series for bar charts defined by to/from values.
+    /// </summary>
+    public class IntervalBarSeries : CategorizedSeries, IStackableSeries
+    {
+        /// <summary>
+        /// The default fill color.
+        /// </summary>
+        private OxyColor defaultFillColor;
+
+        /// <summary>
+        /// Initializes a new instance of the <see cref="IntervalBarSeries"/> class.
+        /// </summary>
+        public IntervalBarSeries()
+        {
+            this.Items = new List<IntervalBarItem>();
+
+            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
+        }
+
+        /// <summary>
+        /// Gets or sets the width of the bars (as a fraction of the available width). The default value is 
0.5 (50%)
+        /// </summary>
+        /// <value>
+        /// The width of the bars.
+        /// </value>
+        public double BarWidth { get; set; }
+
+        /// <summary>
+        /// Gets or sets the default color of the interior of the Maximum bars.
+        /// </summary>
+        /// <value>
+        /// The color.
+        /// </value>
+        public OxyColor FillColor { get; set; }
+
+        /// <summary>
+        /// Gets the actual fill color.
+        /// </summary>
+        /// <value>The actual color.</value>
+        public OxyColor ActualFillColor
+        {
+            get { return this.FillColor ?? this.defaultFillColor; }
+        }
+
+        /// <summary>
+        /// Gets a value indicating whether IsStacked.
+        /// </summary>
+        public bool IsStacked
+        {
+            get
+            {
+                return true;
+            }
+        }
+
+        /// <summary>
+        /// Gets the range bar items.
+        /// </summary>
+        public IList<IntervalBarItem> Items { get; private set; }
+
+        /// <summary>
+        /// Gets or sets the label color.
+        /// </summary>
+        public OxyColor LabelColor { get; set; }
+
+        /// <summary>
+        /// Gets or sets the label field.
+        /// </summary>
+        public string LabelField { get; set; }
+
+        /// <summary>
+        /// Gets or sets the format string for the maximum labels.
+        /// </summary>
+        public string LabelFormatString { get; set; }
+
+        /// <summary>
+        /// Gets or sets the label margins.
+        /// </summary>
+        public double LabelMargin { get; set; }
+
+        /// <summary>
+        /// Gets or sets the maximum value field.
+        /// </summary>
+        public string MaximumField { get; set; }
+
+        /// <summary>
+        /// Gets or sets the minimum value field.
+        /// </summary>
+        public string MinimumField { get; set; }
+
+        /// <summary>
+        /// Gets StackGroup.
+        /// </summary>
+        public string StackGroup
+        {
+            get
+            {
+                return string.Empty;
+            }
+        }
+
+        /// <summary>
+        /// Gets or sets the color of the border around the bars.
+        /// </summary>
+        /// <value>
+        /// The color of the stroke.
+        /// </value>
+        public OxyColor StrokeColor { get; set; }
+
+        /// <summary>
+        /// Gets or sets the thickness of the bar border strokes.
+        /// </summary>
+        /// <value>
+        /// The stroke thickness.
+        /// </value>
+        public double StrokeThickness { get; set; }
+
+        /// <summary>
+        /// Gets or sets the actual rectangles for the maximum bars.
+        /// </summary>
+        protected internal IList<OxyRect> ActualBarRectangles { get; set; }
+
+        /// <summary>
+        /// Gets or sets the valid items
+        /// </summary>
+        protected internal IList<IntervalBarItem> ValidItems { get; set; }
+
+        /// <summary>
+        /// Gets or sets the dictionary which stores the index-inversion for the valid items
+        /// </summary>
+        protected internal Dictionary<int, int> ValidItemsIndexInversion { get; set; }
+
+        /// <summary>
+        /// Gets the point in the dataset that is nearest the specified point.
+        /// </summary>
+        /// <param name="point">
+        /// The point.
+        /// </param>
+        /// <param name="interpolate">
+        /// The interpolate.
+        /// </param>
+        /// <returns>
+        /// A TrackerHitResult for the current hit.
+        /// </returns>
+        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;
+        }
+
+        /// <summary>
+        /// Checks if the specified value is valid.
+        /// </summary>
+        /// <param name="v">
+        /// The value.
+        /// </param>
+        /// <param name="yaxis">
+        /// The y axis.
+        /// </param>
+        /// <returns>
+        /// True if the value is valid.
+        /// </returns>
+        public virtual bool IsValidPoint(double v, Axis yaxis)
+        {
+            return !double.IsNaN(v) && !double.IsInfinity(v);
+        }
+
+        /// <summary>
+        /// Renders the Series on the specified rendering context.
+        /// </summary>
+        /// <param name="rc">
+        /// The rendering context.
+        /// </param>
+        /// <param name="model">
+        /// The model.
+        /// </param>
+        public override void Render(IRenderContext rc, PlotModel model)
+        {
+            this.ActualBarRectangles = new List<OxyRect>();
+
+            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);
+                }
+            }
+        }
+
+        /// <summary>
+        /// Renders the legend symbol on the specified rendering context.
+        /// </summary>
+        /// <param name="rc">
+        /// The rendering context.
+        /// </param>
+        /// <param name="legendBox">
+        /// The legend rectangle.
+        /// </param>
+        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);
+        }
+
+        /// <summary>
+        /// Gets or sets the width/height of the columns/bars (as a fraction of the available space).
+        /// </summary>
+        /// <returns>
+        /// The fractional width.
+        /// </returns>
+        /// <value>
+        /// The width of the bars.
+        /// </value>
+        /// <remarks>
+        /// The available space will be determined by the GapWidth of the CategoryAxis used by this series.
+        /// </remarks>
+        internal override double GetBarWidth()
+        {
+            return this.BarWidth;
+        }
+
+        /// <summary>
+        /// Gets the items of this series.
+        /// </summary>
+        /// <returns>
+        /// The items.
+        /// </returns>
+        protected internal override IList<CategorizedItem> GetItems()
+        {
+            return this.Items.Cast<CategorizedItem>().ToList();
+        }
+
+        /// <summary>
+        /// Check if the data series is using the specified axis.
+        /// </summary>
+        /// <param name="axis">
+        /// An axis which should be checked if used
+        /// </param>
+        /// <returns>
+        /// True if the axis is in use.
+        /// </returns>
+        protected internal override bool IsUsing(Axis axis)
+        {
+            return this.XAxis == axis || this.YAxis == axis;
+        }
+
+        /// <summary>
+        /// The set default values.
+        /// </summary>
+        /// <param name="model">
+        /// The model.
+        /// </param>
+        protected internal override void SetDefaultValues(PlotModel model)
+        {
+            if (this.FillColor == null)
+            {
+                this.defaultFillColor = model.GetDefaultColor();
+            }
+        }
+
+        /// <summary>
+        /// Updates the axis maximum and minimum values.
+        /// </summary>
+        protected internal override void UpdateAxisMaxMin()
+        {
+            this.XAxis.Include(this.MinX);
+            this.XAxis.Include(this.MaxX);
+        }
+
+        /// <summary>
+        /// Updates the data.
+        /// </summary>
+        protected internal override void UpdateData()
+        {
+            if (this.ItemsSource != null)
+            {
+                this.Items.Clear();
+
+                var filler = new ListFiller<IntervalBarItem>();
+                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);
+            }
+        }
+
+        /// <summary>
+        /// Updates the maximum/minimum value on the value axis from the bar values.
+        /// </summary>
+        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;
+        }
+
+        /// <summary>
+        /// Updates the valid items
+        /// </summary>
+        protected internal override void UpdateValidData()
+        {
+            this.ValidItems = new List<IntervalBarItem>();
+            this.ValidItemsIndexInversion = new Dictionary<int, int>();
+            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);
+                }
+            }
+        }
+
+        /// <summary>
+        /// Gets the actual width/height of the items of this series.
+        /// </summary>
+        /// <returns>
+        /// The width or height.
+        /// </returns>
+        /// <remarks>
+        /// The actual width is also influenced by the GapWidth of the CategoryAxis used by this series.
+        /// </remarks>
+        protected override double GetActualBarWidth()
+        {
+            var categoryAxis = this.GetCategoryAxis();
+            return this.BarWidth / (1 + categoryAxis.GapWidth) / categoryAxis.MaxWidth;
+        }
+
+        /// <summary>
+        /// Gets the category axis.
+        /// </summary>
+        /// <returns>
+        /// The category axis.
+        /// </returns>
+        protected override CategoryAxis GetCategoryAxis()
+        {
+            var categoryAxis = this.YAxis as CategoryAxis;
+            if (categoryAxis == null)
+            {
+                throw new InvalidOperationException("No category axis defined.");
+            }
+
+            return categoryAxis;
+        }
+
+        /// <summary>
+        /// Gets the item at the specified index.
+        /// </summary>
+        /// <param name="i">
+        /// The index of the item.
+        /// </param>
+        /// <returns>
+        /// The item of the index.
+        /// </returns>
+        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];
+        }
+
+        /// <summary>
+        /// Gets the value axis.
+        /// </summary>
+        /// <returns>
+        /// The value axis.
+        /// </returns>
+        private Axis GetValueAxis()
+        {
+            return this.XAxis;
+        }
+
+    }
+}
\ No newline at end of file
diff --git a/oxyplot/OxyPlot/Series/BarSeries/LabelPlacement.cs 
b/oxyplot/OxyPlot/Series/BarSeries/LabelPlacement.cs
new file mode 100644
index 0000000..504fe3e
--- /dev/null
+++ b/oxyplot/OxyPlot/Series/BarSeries/LabelPlacement.cs
@@ -0,0 +1,57 @@
+// 
--------------------------------------------------------------------------------------------------------------------
+// <copyright file="LabelPlacement.cs" company="OxyPlot">
+//   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.
+// </copyright>
+// <summary>
+//   Placement of the labels.
+// </summary>
+// 
--------------------------------------------------------------------------------------------------------------------
+namespace OxyPlot.Series
+{
+    /// <summary>
+    /// Placement of the labels.
+    /// </summary>
+    public enum LabelPlacement
+    {
+        /// <summary>
+        /// Placed outside the bar.
+        /// </summary>
+        Outside,
+
+        /// <summary>
+        /// Placed inside the bar.
+        /// </summary>
+        Inside,
+
+        /// <summary>
+        /// Placed inside in the middle/center of the bar.
+        /// </summary>
+        Middle,
+
+        /// <summary>
+        /// Placed inside at the base of the bar.
+        /// </summary>
+        Base
+    }
+}
\ No newline at end of file
diff --git a/oxyplot/OxyPlot/Series/BarSeries/RectangleBarItem.cs 
b/oxyplot/OxyPlot/Series/BarSeries/RectangleBarItem.cs
new file mode 100644
index 0000000..7ce3baa
--- /dev/null
+++ b/oxyplot/OxyPlot/Series/BarSeries/RectangleBarItem.cs
@@ -0,0 +1,137 @@
+// 
--------------------------------------------------------------------------------------------------------------------
+// <copyright file="RectangleBarItem.cs" company="OxyPlot">
+//   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.
+// </copyright>
+// <summary>
+//   Represents a rectangle item in a RectangleBarSeries.
+// </summary>
+// 
--------------------------------------------------------------------------------------------------------------------
+namespace OxyPlot.Series
+{
+    /// <summary>
+    /// Represents a rectangle item in a RectangleBarSeries.
+    /// </summary>
+    public class RectangleBarItem : ICodeGenerating
+    {
+        /// <summary>
+        /// Initializes a new instance of the <see cref="RectangleBarItem"/> class.
+        /// </summary>
+        public RectangleBarItem()
+        {
+        }
+
+        /// <summary>
+        /// Initializes a new instance of the <see cref="RectangleBarItem"/> class.
+        /// </summary>
+        /// <param name="x0">
+        /// The x0.
+        /// </param>
+        /// <param name="y0">
+        /// The y0.
+        /// </param>
+        /// <param name="x1">
+        /// The x1.
+        /// </param>
+        /// <param name="y1">
+        /// The y1.
+        /// </param>
+        /// <param name="title">
+        /// The title.
+        /// </param>
+        /// <param name="color">
+        /// The color.
+        /// </param>
+        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;
+        }
+
+        /// <summary>
+        /// Gets or sets the color.
+        /// </summary>
+        public OxyColor Color { get; set; }
+
+        /// <summary>
+        /// Gets or sets the title.
+        /// </summary>
+        public string Title { get; set; }
+
+        /// <summary>
+        /// Gets or sets the x0 coordinate.
+        /// </summary>
+        public double X0 { get; set; }
+
+        /// <summary>
+        /// Gets or sets the x1 coordinate.
+        /// </summary>
+        public double X1 { get; set; }
+
+        /// <summary>
+        /// Gets or sets the y0 coordinate.
+        /// </summary>
+        public double Y0 { get; set; }
+
+        /// <summary>
+        /// Gets or sets the y1 coordinate.
+        /// </summary>
+        public double Y1 { get; set; }
+
+        /// <summary>
+        /// Returns c# code that generates this instance.
+        /// </summary>
+        /// <returns>
+        /// C# code.
+        /// </returns>
+        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 --git a/oxyplot/OxyPlot/Series/BarSeries/RectangleBarSeries.cs 
b/oxyplot/OxyPlot/Series/BarSeries/RectangleBarSeries.cs
new file mode 100644
index 0000000..7d22bb0
--- /dev/null
+++ b/oxyplot/OxyPlot/Series/BarSeries/RectangleBarSeries.cs
@@ -0,0 +1,337 @@
+// 
--------------------------------------------------------------------------------------------------------------------
+// <copyright file="RectangleBarSeries.cs" company="OxyPlot">
+//   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.
+// </copyright>
+// <summary>
+//   Represents a series for bar charts where the bars are defined by rectangles.
+// </summary>
+// 
--------------------------------------------------------------------------------------------------------------------
+namespace OxyPlot.Series
+{
+    using System;
+    using System.Collections.Generic;
+
+    /// <summary>
+    /// Represents a series for bar charts where the bars are defined by rectangles.
+    /// </summary>
+    public class RectangleBarSeries : XYAxisSeries
+    {
+        /// <summary>
+        /// The default fill color.
+        /// </summary>
+        private OxyColor defaultFillColor;
+
+        /// <summary>
+        /// Initializes a new instance of the <see cref="RectangleBarSeries"/> class.
+        /// </summary>
+        public RectangleBarSeries()
+        {
+            this.Items = new List<RectangleBarItem>();
+
+            this.StrokeColor = OxyColors.Black;
+            this.StrokeThickness = 1;
+
+            this.TrackerFormatString = "{0}";
+
+            this.LabelFormatString = "{4}"; // title
+
+            // this.LabelFormatString = "{0}-{1},{2}-{3}"; // X0-X1,Y0-Y1
+        }
+
+        /// <summary>
+        /// Gets or sets the default color of the interior of the rectangles.
+        /// </summary>
+        /// <value>
+        /// The color.
+        /// </value>
+        public OxyColor FillColor { get; set; }
+
+        /// <summary>
+        /// Gets the actual fill color.
+        /// </summary>
+        /// <value>The actual color.</value>
+        public OxyColor ActualFillColor
+        {
+            get { return this.FillColor ?? this.defaultFillColor; }
+        }
+
+        /// <summary>
+        /// Gets the rectangle bar items.
+        /// </summary>
+        public IList<RectangleBarItem> Items { get; private set; }
+
+        /// <summary>
+        /// Gets or sets the label color.
+        /// </summary>
+        public OxyColor LabelColor { get; set; }
+
+        /// <summary>
+        /// Gets or sets the format string for the labels.
+        /// </summary>
+        public string LabelFormatString { get; set; }
+
+        /// <summary>
+        /// Gets or sets the color of the border around the rectangles.
+        /// </summary>
+        /// <value>
+        /// The color of the stroke.
+        /// </value>
+        public OxyColor StrokeColor { get; set; }
+
+        /// <summary>
+        /// Gets or sets the thickness of the border around the rectangles.
+        /// </summary>
+        /// <value>
+        /// The stroke thickness.
+        /// </value>
+        public double StrokeThickness { get; set; }
+
+        /// <summary>
+        /// Gets or sets the actual rectangles for the rectangles.
+        /// </summary>
+        internal IList<OxyRect> ActualBarRectangles { get; set; }
+
+        /// <summary>
+        /// Gets the point in the dataset that is nearest the specified point.
+        /// </summary>
+        /// <param name="point">
+        /// The point.
+        /// </param>
+        /// <param name="interpolate">
+        /// Specifies whether to interpolate or not.
+        /// </param>
+        /// <returns>
+        /// A <see cref="TrackerHitResult"/> for the current hit.
+        /// </returns>
+        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;
+        }
+
+        /// <summary>
+        /// Checks if the specified value is valid.
+        /// </summary>
+        /// <param name="v">
+        /// The value.
+        /// </param>
+        /// <returns>
+        /// True if the value is valid.
+        /// </returns>
+        protected virtual bool IsValid(double v)
+        {
+            return !double.IsNaN(v) && !double.IsInfinity(v);
+        }
+
+        /// <summary>
+        /// Renders the Series on the specified rendering context.
+        /// </summary>
+        /// <param name="rc">
+        /// The rendering context.
+        /// </param>
+        /// <param name="model">
+        /// The model.
+        /// </param>
+        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<OxyRect>();
+
+            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++;
+            }
+        }
+
+        /// <summary>
+        /// Renders the legend symbol on the specified rendering context.
+        /// </summary>
+        /// <param name="rc">
+        /// The rendering context.
+        /// </param>
+        /// <param name="legendBox">
+        /// The legend rectangle.
+        /// </param>
+        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);
+        }
+
+        /// <summary>
+        /// Sets the default values.
+        /// </summary>
+        /// <param name="model">
+        /// The model.
+        /// </param>
+        protected internal override void SetDefaultValues(PlotModel model)
+        {
+            if (this.FillColor == null)
+            {
+                this.defaultFillColor = model.GetDefaultColor();
+            }
+        }
+
+        /// <summary>
+        /// Updates the data.
+        /// </summary>
+        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();
+        }
+
+        /// <summary>
+        /// Updates the maximum/minimum value on the value axis from the bar values.
+        /// </summary>
+        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 --git a/oxyplot/OxyPlot/Series/BarSeries/TornadoBarItem.cs 
b/oxyplot/OxyPlot/Series/BarSeries/TornadoBarItem.cs
new file mode 100644
index 0000000..5465beb
--- /dev/null
+++ b/oxyplot/OxyPlot/Series/BarSeries/TornadoBarItem.cs
@@ -0,0 +1,147 @@
+// 
--------------------------------------------------------------------------------------------------------------------
+// <copyright file="TornadoBarItem.cs" company="OxyPlot">
+//   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.
+// </copyright>
+// <summary>
+//   Represents an item for the TornadoBarSeries.
+// </summary>
+// 
--------------------------------------------------------------------------------------------------------------------
+namespace OxyPlot.Series
+{
+    /// <summary>
+    /// Represents an item for the TornadoBarSeries.
+    /// </summary>
+    public class TornadoBarItem : CategorizedItem, ICodeGenerating
+    {
+        /// <summary>
+        /// Initializes a new instance of the <see cref="TornadoBarItem"/> class.
+        /// </summary>
+        public TornadoBarItem()
+        {
+            this.Minimum = double.NaN;
+            this.Maximum = double.NaN;
+            this.BaseValue = double.NaN;
+            this.MinimumColor = null;
+            this.MaximumColor = null;
+        }
+
+        /// <summary>
+        /// Initializes a new instance of the <see cref="TornadoBarItem"/> class.
+        /// </summary>
+        /// <param name="minimum">
+        /// The minimum.
+        /// </param>
+        /// <param name="maximum">
+        /// The maximum.
+        /// </param>
+        /// <param name="baseValue">
+        /// The base value.
+        /// </param>
+        /// <param name="minimumColor">
+        /// The minimum color.
+        /// </param>
+        /// <param name="maximumColor">
+        /// The maximum color.
+        /// </param>
+        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;
+        }
+
+        /// <summary>
+        /// Gets or sets the base value.
+        /// </summary>
+        public double BaseValue { get; set; }
+
+        /// <summary>
+        /// Gets or sets the maximum.
+        /// </summary>
+        public double Maximum { get; set; }
+
+        /// <summary>
+        /// Gets or sets the color for the maximum bar.
+        /// </summary>
+        public OxyColor MaximumColor { get; set; }
+
+        /// <summary>
+        /// Gets or sets the minimum value.
+        /// </summary>
+        public double Minimum { get; set; }
+
+        /// <summary>
+        /// Gets or sets the color for the minimum bar.
+        /// </summary>
+        public OxyColor MinimumColor { get; set; }
+
+        /// <summary>
+        /// Returns c# code that generates this instance.
+        /// </summary>
+        /// <returns>
+        /// C# code.
+        /// </returns>
+        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 --git a/oxyplot/OxyPlot/Series/BarSeries/TornadoBarSeries.cs 
b/oxyplot/OxyPlot/Series/BarSeries/TornadoBarSeries.cs
new file mode 100644
index 0000000..520f00e
--- /dev/null
+++ b/oxyplot/OxyPlot/Series/BarSeries/TornadoBarSeries.cs
@@ -0,0 +1,590 @@
+// 
--------------------------------------------------------------------------------------------------------------------
+// <copyright file="TornadoBarSeries.cs" company="OxyPlot">
+//   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.
+// </copyright>
+// <summary>
+//   Represents a series that can be used to create tornado plots.
+// </summary>
+// 
--------------------------------------------------------------------------------------------------------------------
+namespace OxyPlot.Series
+{
+    using System;
+    using System.Collections.Generic;
+    using System.Linq;
+
+    using OxyPlot.Axes;
+
+    /// <summary>
+    /// Represents a series that can be used to create tornado plots.
+    /// </summary>
+    /// <remarks>
+    /// See http://en.wikipedia.org/wiki/Tornado_diagram.
+    /// </remarks>
+    public class TornadoBarSeries : CategorizedSeries
+    {
+        /// <summary>
+        /// The default fill color.
+        /// </summary>
+        private OxyColor defaultMaximumFillColor;
+
+        /// <summary>
+        /// The default minimum fill color.
+        /// </summary>
+        private OxyColor defaultMinimumFillColor;
+
+        /// <summary>
+        /// Initializes a new instance of the <see cref="TornadoBarSeries"/> class.
+        /// </summary>
+        public TornadoBarSeries()
+        {
+            this.Items = new List<TornadoBarItem>();
+
+            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}";
+        }
+
+        /// <summary>
+        /// Gets or sets the width of the bars (as a fraction of the available width). The default value is 
0.5 (50%)
+        /// </summary>
+        /// <value>
+        /// The width of the bars.
+        /// </value>
+        public double BarWidth { get; set; }
+
+        /// <summary>
+        /// Gets or sets the base value.
+        /// </summary>
+        /// <value>
+        /// The base value.
+        /// </value>
+        public double BaseValue { get; set; }
+
+        /// <summary>
+        /// Gets the tornado bar items.
+        /// </summary>
+        /// <value>
+        /// The items.
+        /// </value>
+        public IList<TornadoBarItem> Items { get; private set; }
+
+        /// <summary>
+        /// Gets or sets the label color.
+        /// </summary>
+        public OxyColor LabelColor { get; set; }
+
+        /// <summary>
+        /// Gets or sets the label field.
+        /// </summary>
+        public string LabelField { get; set; }
+
+        /// <summary>
+        /// Gets or sets the label margins.
+        /// </summary>
+        public double LabelMargin { get; set; }
+
+        /// <summary>
+        /// Gets or sets the maximum value field.
+        /// </summary>
+        public string MaximumField { get; set; }
+
+        /// <summary>
+        /// Gets or sets the color of the interior of the Maximum bars.
+        /// </summary>
+        /// <value>
+        /// The color.
+        /// </value>
+        public OxyColor MaximumFillColor { get; set; }
+
+        /// <summary>
+        /// Gets the actual fill color.
+        /// </summary>
+        /// <value>The actual color.</value>
+        public OxyColor ActualMaximumFillColor
+        {
+            get { return this.MaximumFillColor ?? this.defaultMaximumFillColor; }
+        }
+
+        /// <summary>
+        /// Gets or sets the format string for the maximum labels.
+        /// </summary>
+        public string MaximumLabelFormatString { get; set; }
+
+        /// <summary>
+        /// Gets or sets the minimum value field.
+        /// </summary>
+        public string MinimumField { get; set; }
+
+        /// <summary>
+        /// Gets or sets the default color of the interior of the Minimum bars.
+        /// </summary>
+        /// <value>
+        /// The color.
+        /// </value>
+        public OxyColor MinimumFillColor { get; set; }
+
+        /// <summary>
+        /// Gets the actual minimum fill color.
+        /// </summary>
+        /// <value>The actual color.</value>
+        public OxyColor ActualMinimumFillColor
+        {
+            get { return this.MinimumFillColor ?? this.defaultMinimumFillColor; }
+        }
+
+        /// <summary>
+        /// Gets or sets the format string for the minimum labels.
+        /// </summary>
+        public string MinimumLabelFormatString { get; set; }
+
+        /// <summary>
+        /// Gets or sets the color of the border around the bars.
+        /// </summary>
+        /// <value>
+        /// The color of the stroke.
+        /// </value>
+        public OxyColor StrokeColor { get; set; }
+
+        /// <summary>
+        /// Gets or sets the thickness of the bar border strokes.
+        /// </summary>
+        /// <value>
+        /// The stroke thickness.
+        /// </value>
+        public double StrokeThickness { get; set; }
+
+        /// <summary>
+        /// Gets or sets the actual rectangles for the maximum bars.
+        /// </summary>
+               protected internal IList<OxyRect> ActualMaximumBarRectangles { get; set; }
+
+        /// <summary>
+        /// Gets or sets the actual rectangles for the minimum bars.
+        /// </summary>
+               protected internal IList<OxyRect> ActualMinimumBarRectangles { get; set; }
+
+        /// <summary>
+        /// Gets or sets the valid items
+        /// </summary>
+               protected internal IList<TornadoBarItem> ValidItems { get; set; }
+
+        /// <summary>
+        /// Gets or sets the dictionary which stores the index-inversion for the valid items
+        /// </summary>
+        protected internal Dictionary<int, int> ValidItemsIndexInversion { get; set; }
+
+        /// <summary>
+        /// Gets the point in the dataset that is nearest the specified point.
+        /// </summary>
+        /// <param name="point">
+        /// The point.
+        /// </param>
+        /// <param name="interpolate">
+        /// The interpolate.
+        /// </param>
+        /// <returns>
+        /// A TrackerHitResult for the current hit.
+        /// </returns>
+        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;
+        }
+
+        /// <summary>
+        /// Checks if the specified value is valid.
+        /// </summary>
+        /// <param name="v">
+        /// The value.
+        /// </param>
+        /// <param name="yaxis">
+        /// The y axis.
+        /// </param>
+        /// <returns>
+        /// True if the value is valid.
+        /// </returns>
+        public virtual bool IsValidPoint(double v, Axis yaxis)
+        {
+            return !double.IsNaN(v) && !double.IsInfinity(v);
+        }
+
+        /// <summary>
+        /// Renders the Series on the specified rendering context.
+        /// </summary>
+        /// <param name="rc">
+        /// The rendering context.
+        /// </param>
+        /// <param name="model">
+        /// The model.
+        /// </param>
+        public override void Render(IRenderContext rc, PlotModel model)
+        {
+            this.ActualMinimumBarRectangles = new List<OxyRect>();
+            this.ActualMaximumBarRectangles = new List<OxyRect>();
+
+            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);
+                }
+            }
+        }
+
+        /// <summary>
+        /// Renders the legend symbol on the specified rendering context.
+        /// </summary>
+        /// <param name="rc">
+        /// The rendering context.
+        /// </param>
+        /// <param name="legendBox">
+        /// The legend rectangle.
+        /// </param>
+        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);
+        }
+
+        /// <summary>
+        /// Gets or sets the width/height of the columns/bars (as a fraction of the available space).
+        /// </summary>
+        /// <returns>
+        /// The fractional width.
+        /// </returns>
+        /// <value>
+        /// The width of the bars.
+        /// </value>
+        /// <remarks>
+        /// The available space will be determined by the GapWidth of the CategoryAxis used by this series.
+        /// </remarks>
+        internal override double GetBarWidth()
+        {
+            return this.BarWidth;
+        }
+
+        /// <summary>
+        /// Gets the items of this series.
+        /// </summary>
+        /// <returns>
+        /// The items.
+        /// </returns>
+        protected internal override IList<CategorizedItem> GetItems()
+        {
+            return this.Items.Cast<CategorizedItem>().ToList();
+        }
+
+        /// <summary>
+        /// Check if the data series is using the specified axis.
+        /// </summary>
+        /// <param name="axis">
+        /// An axis which should be checked if used
+        /// </param>
+        /// <returns>
+        /// True if the axis is in use.
+        /// </returns>
+        protected internal override bool IsUsing(Axis axis)
+        {
+            return this.XAxis == axis || this.YAxis == axis;
+        }
+
+        /// <summary>
+        /// The set default values.
+        /// </summary>
+        /// <param name="model">
+        /// The model.
+        /// </param>
+        protected internal override void SetDefaultValues(PlotModel model)
+        {
+            if (this.MaximumFillColor == null)
+            {
+                this.defaultMaximumFillColor = model.GetDefaultColor();
+            }
+
+            if (this.MinimumFillColor == null)
+            {
+                this.defaultMinimumFillColor = model.GetDefaultColor();
+            }
+        }
+
+        /// <summary>
+        /// Updates the axis maximum and minimum values.
+        /// </summary>
+        protected internal override void UpdateAxisMaxMin()
+        {
+            this.XAxis.Include(this.MinX);
+            this.XAxis.Include(this.MaxX);
+        }
+
+        /// <summary>
+        /// Updates the data.
+        /// </summary>
+        protected internal override void UpdateData()
+        {
+            if (this.ItemsSource != null)
+            {
+                this.Items.Clear();
+
+                var filler = new ListFiller<TornadoBarItem>();
+                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);
+            }
+        }
+
+        /// <summary>
+        /// Updates the maximum/minimum value on the value axis from the bar values.
+        /// </summary>
+        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;
+        }
+
+        /// <summary>
+        /// Updates the valid items
+        /// </summary>
+        protected internal override void UpdateValidData()
+        {
+            this.ValidItems = new List<TornadoBarItem>();
+            this.ValidItemsIndexInversion = new Dictionary<int, int>();
+            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);
+                }
+            }
+        }
+
+        /// <summary>
+        /// Gets the actual width/height of the items of this series.
+        /// </summary>
+        /// <returns>
+        /// The width or height.
+        /// </returns>
+        /// <remarks>
+        /// The actual width is also influenced by the GapWidth of the CategoryAxis used by this series.
+        /// </remarks>
+        protected override double GetActualBarWidth()
+        {
+            var categoryAxis = this.GetCategoryAxis();
+            return this.BarWidth / (1 + categoryAxis.GapWidth) / categoryAxis.MaxWidth;
+        }
+
+        /// <summary>
+        /// Gets the category axis.
+        /// </summary>
+        /// <returns>
+        /// The category axis.
+        /// </returns>
+        protected override CategoryAxis GetCategoryAxis()
+        {
+            var categoryAxis = this.YAxis as CategoryAxis;
+            if (categoryAxis == null)
+            {
+                throw new InvalidOperationException("No category axis defined.");
+            }
+
+            return categoryAxis;
+        }
+
+        /// <summary>
+        /// Gets the item at the specified index.
+        /// </summary>
+        /// <param name="i">
+        /// The index of the item.
+        /// </param>
+        /// <returns>
+        /// The item of the index.
+        /// </returns>
+        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];
+        }
+
+        /// <summary>
+        /// Gets the value axis.
+        /// </summary>
+        /// <returns>
+        /// The value axis.
+        /// </returns>
+        private Axis GetValueAxis()
+        {
+            return this.XAxis;
+        }
+
+    }
+}
\ No newline at end of file
diff --git a/oxyplot/OxyPlot/Series/BoxPlotItem.cs b/oxyplot/OxyPlot/Series/BoxPlotItem.cs
new file mode 100644
index 0000000..db0f0d8
--- /dev/null
+++ b/oxyplot/OxyPlot/Series/BoxPlotItem.cs
@@ -0,0 +1,167 @@
+// 
--------------------------------------------------------------------------------------------------------------------
+// <copyright file="BoxPlotItem.cs" company="OxyPlot">
+//   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.
+// </copyright>
+// <summary>
+//   Represents an item in a BoxPlotSeries.
+// </summary>
+// 
--------------------------------------------------------------------------------------------------------------------
+namespace OxyPlot.Series
+{
+    using System.Collections.Generic;
+
+    /// <summary>
+    /// Represents an item in a <see cref="BoxPlotSeries"/>.
+    /// </summary>
+    public struct BoxPlotItem
+    {
+        /// <summary>
+        /// Initializes a new instance of the <see cref="BoxPlotItem"/> struct.
+        /// </summary>
+        /// <param name="x">
+        /// The x.
+        /// </param>
+        /// <param name="lowerWhisker">
+        /// The lower whisker.
+        /// </param>
+        /// <param name="boxBottom">
+        /// The box bottom.
+        /// </param>
+        /// <param name="median">
+        /// The median.
+        /// </param>
+        /// <param name="boxTop">
+        /// The box top.
+        /// </param>
+        /// <param name="upperWhisker">
+        /// The upper whisker.
+        /// </param>
+        /// <param name="outliers">
+        /// The outliers.
+        /// </param>
+        /// <param name="tag">
+        /// The tag.
+        /// </param>
+        public BoxPlotItem(
+            double x,
+            double lowerWhisker,
+            double boxBottom,
+            double median,
+            double boxTop,
+            double upperWhisker,
+            IList<double> 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;
+        }
+
+        /// <summary>
+        /// Gets or sets the box bottom value (usually the 25th percentile, Q1).
+        /// </summary>
+        /// <value> The lower quartile value. </value>
+        public double BoxBottom { get; set; }
+
+        /// <summary>
+        /// Gets or sets the box top value (usually the 75th percentile, Q3)).
+        /// </summary>
+        /// <value> The box top value. </value>
+        public double BoxTop { get; set; }
+
+        /// <summary>
+        /// Gets or sets the lower whisker value.
+        /// </summary>
+        /// <value> The lower whisker value. </value>
+        public double LowerWhisker { get; set; }
+
+        /// <summary>
+        /// Gets or sets the median.
+        /// </summary>
+        /// <value> The median. </value>
+        public double Median { get; set; }
+
+        /// <summary>
+        /// Gets or sets the outliers.
+        /// </summary>
+        /// <value> The outliers. </value>
+        public IList<double> Outliers { get; set; }
+
+        /// <summary>
+        /// Gets or sets the tag.
+        /// </summary>
+        /// <value> The tag. </value>
+        public object Tag { get; set; }
+
+        /// <summary>
+        /// Gets or sets the upper whisker value.
+        /// </summary>
+        /// <value> The upper whisker value. </value>
+        public double UpperWhisker { get; set; }
+
+        /// <summary>
+        /// Gets a list of all the values in the item.
+        /// </summary>
+        public IList<double> Values
+        {
+            get
+            {
+                var values = new List<double> { this.LowerWhisker, this.BoxBottom, this.Median, this.BoxTop, 
this.UpperWhisker };
+                values.AddRange(this.Outliers);
+                return values;
+            }
+        }
+
+        /// <summary>
+        /// Gets or sets the X value.
+        /// </summary>
+        /// <value> The X value. </value>
+        public double X { get; set; }
+
+        /// <summary>
+        /// Returns a <see cref="System.String"/> that represents this instance.
+        /// </summary>
+        /// <returns>
+        /// A <see cref="System.String"/> that represents this instance.
+        /// </returns>
+        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 --git a/oxyplot/OxyPlot/Series/BoxPlotSeries.cs b/oxyplot/OxyPlot/Series/BoxPlotSeries.cs
new file mode 100644
index 0000000..f7d924e
--- /dev/null
+++ b/oxyplot/OxyPlot/Series/BoxPlotSeries.cs
@@ -0,0 +1,615 @@
+// 
--------------------------------------------------------------------------------------------------------------------
+// <copyright file="BoxPlotSeries.cs" company="OxyPlot">
+//   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.
+// </copyright>
+// <summary>
+//   Represents a series for box plots.
+// </summary>
+// 
--------------------------------------------------------------------------------------------------------------------
+
+namespace OxyPlot.Series
+{
+    using System.Collections.Generic;
+    using System.Linq;
+
+    using OxyPlot.Axes;
+
+    /// <summary>
+    /// Represents a series for box plots.
+    /// </summary>
+    public class BoxPlotSeries : XYAxisSeries
+    {
+        /// <summary>
+        /// Initializes a new instance of the <see cref="BoxPlotSeries"/> class.
+        /// </summary>
+        public BoxPlotSeries()
+        {
+            this.Items = new List<BoxPlotItem>();
+            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;
+        }
+
+        /// <summary>
+        /// Gets or sets the width of the boxes (specified in x-axis units).
+        /// </summary>
+        /// <value>
+        /// The width of the boxes.
+        /// </value>
+        public double BoxWidth { get; set; }
+
+        /// <summary>
+        /// Gets or sets the fill color. If null, this color will be automatically set.
+        /// </summary>
+        /// <value>
+        /// The fill color.
+        /// </value>
+        public OxyColor Fill { get; set; }
+
+        /// <summary>
+        /// Gets or sets the box plot items.
+        /// </summary>
+        /// <value>
+        /// The items.
+        /// </value>
+        public IList<BoxPlotItem> Items { get; set; }
+
+        /// <summary>
+        /// Gets or sets the line style.
+        /// </summary>
+        /// <value>
+        /// The line style.
+        /// </value>
+        public LineStyle LineStyle { get; set; }
+
+        /// <summary>
+        /// Gets or sets the size of the median point.
+        /// </summary>
+        /// <remarks>
+        /// This property is only used when MedianStyle = Dot.
+        /// </remarks>
+        public double MedianPointSize { get; set; }
+
+        /// <summary>
+        /// Gets or sets the median thickness, relative to the StrokeThickness.
+        /// </summary>
+        /// <value>
+        /// The median thickness.
+        /// </value>
+        public double MedianThickness { get; set; }
+
+        /// <summary>
+        /// Gets or sets the diameter of the outlier circles (specified in points).
+        /// </summary>
+        /// <value>
+        /// The size of the outlier.
+        /// </value>
+        public double OutlierSize { get; set; }
+
+        /// <summary>
+        /// Gets or sets the tracker format string for the outliers.
+        /// </summary>
+        /// <value>
+        /// The tracker format string for the outliers.
+        /// </value>
+        /// <remarks>
+        /// Use {0} for series title, {1} for x- and {2} for y-value.
+        /// </remarks>
+        public string OutlierTrackerFormatString { get; set; }
+
+        /// <summary>
+        /// Gets or sets the type of the outliers.
+        /// </summary>
+        /// <value>
+        /// The type of the outliers.
+        /// </value>
+        /// <remarks>
+        /// MarkerType.Custom is currently not supported.
+        /// </remarks>
+        public MarkerType OutlierType { get; set; }
+
+        /// <summary>
+        /// Gets or sets a value indicating whether to show the boxes.
+        /// </summary>
+        public bool ShowBox { get; set; }
+
+        /// <summary>
+        /// Gets or sets a value indicating whether to show the median as a dot.
+        /// </summary>
+        public bool ShowMedianAsDot { get; set; }
+
+        /// <summary>
+        /// Gets or sets the stroke.
+        /// </summary>
+        /// <value>
+        /// The stroke.
+        /// </value>
+        public OxyColor Stroke { get; set; }
+
+        /// <summary>
+        /// Gets or sets the stroke thickness.
+        /// </summary>
+        /// <value>
+        /// The stroke thickness.
+        /// </value>
+        public double StrokeThickness { get; set; }
+
+        /// <summary>
+        /// Gets or sets the width of the whiskers (relative to the BoxWidth).
+        /// </summary>
+        /// <value>
+        /// The width of the whiskers.
+        /// </value>
+        public double WhiskerWidth { get; set; }
+
+        /// <summary>
+        /// Gets the nearest point.
+        /// </summary>
+        /// <param name="point">
+        /// The point.
+        /// </param>
+        /// <param name="interpolate">
+        /// interpolate if set to <c>true</c> .
+        /// </param>
+        /// <returns>
+        /// A TrackerHitResult for the current hit.
+        /// </returns>
+        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;
+        }
+
+        /// <summary>
+        /// Determines whether the specified item contains a valid point.
+        /// </summary>
+        /// <param name="item">
+        /// The item.
+        /// </param>
+        /// <param name="xaxis">
+        /// The x axis.
+        /// </param>
+        /// <param name="yaxis">
+        /// The y axis.
+        /// </param>
+        /// <returns>
+        /// <c>true</c> if the point is valid; otherwise, <c>false</c> .
+        /// </returns>
+        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));
+        }
+
+        /// <summary>
+        /// Renders the series on the specified render context.
+        /// </summary>
+        /// <param name="rc">
+        /// The rendering context.
+        /// </param>
+        /// <param name="model">
+        /// The model.
+        /// </param>
+        public override void Render(IRenderContext rc, PlotModel model)
+        {
+            if (this.Items.Count == 0)
+            {
+                return;
+            }
+
+            var clippingRect = this.GetClippingRect();
+
+            var outlierScreenPoints = new List<ScreenPoint>();
+            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);
+        }
+
+        /// <summary>
+        /// Renders the legend symbol on the specified rendering context.
+        /// </summary>
+        /// <param name="rc">
+        /// The rendering context.
+        /// </param>
+        /// <param name="legendBox">
+        /// The legend rectangle.
+        /// </param>
+        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);
+            }
+        }
+
+        /// <summary>
+        /// Updates the max/minimum values.
+        /// </summary>
+        protected internal override void UpdateMaxMin()
+        {
+            base.UpdateMaxMin();
+            this.InternalUpdateMaxMin(this.Items);
+        }
+
+        /// <summary>
+        /// Updates the max and min of the series.
+        /// </summary>
+        /// <param name="items">
+        /// The items.
+        /// </param>
+        protected void InternalUpdateMaxMin(IList<BoxPlotItem> 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;
+        }
+
+        /// <summary>
+        /// Gets the screen rectangle for the box.
+        /// </summary>
+        /// <param name="item">
+        /// The box item.
+        /// </param>
+        /// <returns>
+        /// A rectangle.
+        /// </returns>
+        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 --git a/oxyplot/OxyPlot/Series/CandleStickSeries.cs b/oxyplot/OxyPlot/Series/CandleStickSeries.cs
new file mode 100644
index 0000000..9093ae5
--- /dev/null
+++ b/oxyplot/OxyPlot/Series/CandleStickSeries.cs
@@ -0,0 +1,201 @@
+// 
--------------------------------------------------------------------------------------------------------------------
+// <copyright file="CandleStickSeries.cs" company="OxyPlot">
+//   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.
+// </copyright>
+// <summary>
+//   Represents a series for candlestick charts.
+// </summary>
+// 
--------------------------------------------------------------------------------------------------------------------
+namespace OxyPlot.Series
+{
+    using System;
+
+    /// <summary>
+    /// Represents a series for candlestick charts.
+    /// </summary>
+    /// <remarks>
+    /// http://en.wikipedia.org/wiki/Candlestick_chart
+    /// http://www.mathworks.com/help/toolbox/finance/candle.html
+    /// </remarks>
+    public class CandleStickSeries : HighLowSeries
+    {
+        /// <summary>
+        /// Initializes a new instance of the <see cref = "CandleStickSeries" /> class.
+        /// </summary>
+        public CandleStickSeries()
+        {
+            this.CandleWidth = 10;
+        }
+
+        /// <summary>
+        /// Initializes a new instance of the <see cref="CandleStickSeries"/> class.
+        /// </summary>
+        /// <param name="title">
+        /// The title.
+        /// </param>
+        public CandleStickSeries(string title)
+            : this()
+        {
+            this.Title = title;
+        }
+
+        /// <summary>
+        /// Initializes a new instance of the <see cref="CandleStickSeries"/> class.
+        /// </summary>
+        /// <param name="color">
+        /// The color.
+        /// </param>
+        /// <param name="strokeThickness">
+        /// The stroke thickness.
+        /// </param>
+        /// <param name="title">
+        /// The title.
+        /// </param>
+        public CandleStickSeries(OxyColor color, double strokeThickness = 1, string title = null)
+            : this()
+        {
+            this.Color = color;
+            this.StrokeThickness = strokeThickness;
+            this.Title = title;
+        }
+
+        /// <summary>
+        /// Gets or sets the width of the candle.
+        /// </summary>
+        /// <value>The width of the candle.</value>
+        public double CandleWidth { get; set; }
+
+        /// <summary>
+        /// Renders the series on the specified rendering context.
+        /// </summary>
+        /// <param name="rc">
+        /// The rendering context.
+        /// </param>
+        /// <param name="model">
+        /// The owner plot model.
+        /// </param>
+        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);
+                    }
+                }
+            }
+        }
+
+        /// <summary>
+        /// Renders the legend symbol for the series on the specified rendering context.
+        /// </summary>
+        /// <param name="rc">
+        /// The rendering context.
+        /// </param>
+        /// <param name="legendBox">
+        /// The bounding rectangle of the legend box.
+        /// </param>
+        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 --git a/oxyplot/OxyPlot/Series/ContourSeries.cs b/oxyplot/OxyPlot/Series/ContourSeries.cs
new file mode 100644
index 0000000..f246b01
--- /dev/null
+++ b/oxyplot/OxyPlot/Series/ContourSeries.cs
@@ -0,0 +1,770 @@
+// 
--------------------------------------------------------------------------------------------------------------------
+// <copyright file="ContourSeries.cs" company="OxyPlot">
+//   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.
+// </copyright>
+// <summary>
+//   Represents a series for contour plots.
+// </summary>
+// 
--------------------------------------------------------------------------------------------------------------------
+namespace OxyPlot.Series
+{
+    using System;
+    using System.Collections.Generic;
+    using System.Linq;
+
+    /// <summary>
+    /// Represents a series that renders contours.
+    /// </summary>
+    /// <remarks>
+    /// See http://en.wikipedia.org/wiki/Contour_line and 
http://www.mathworks.se/help/techdoc/ref/contour.html.
+    /// </remarks>
+    public class ContourSeries : XYAxisSeries
+    {
+        /// <summary>
+        /// The contour collection.
+        /// </summary>
+        private List<Contour> contours;
+
+        /// <summary>
+        /// The temporary segment collection.
+        /// </summary>
+        private List<ContourSegment> segments;
+
+        /// <summary>
+        /// The default color.
+        /// </summary>
+        private OxyColor defaultColor;
+
+        /// <summary>
+        /// Initializes a new instance of the <see cref = "ContourSeries" /> class.
+        /// </summary>
+        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.####}";
+        }
+
+        /// <summary>
+        /// Gets or sets the color.
+        /// </summary>
+        /// <value>The color.</value>
+        public OxyColor Color { get; set; }
+
+        /// <summary>
+        /// Gets the actual color.
+        /// </summary>
+        /// <value>The actual color.</value>
+        public OxyColor ActualColor
+        {
+            get { return this.Color ?? this.defaultColor; }
+        }
+
+        /// <summary>
+        /// Gets or sets the column coordinates.
+        /// </summary>
+        /// <value>The column coordinates.</value>
+        public double[] ColumnCoordinates { get; set; }
+
+        /// <summary>
+        /// Gets or sets the contour level step size.
+        /// This property is not used if the ContourLevels vector is set.
+        /// </summary>
+        /// <value>The contour level step size.</value>
+        public double ContourLevelStep { get; set; }
+
+        /// <summary>
+        /// Gets or sets the contour levels.
+        /// </summary>
+        /// <value>The contour levels.</value>
+        public double[] ContourLevels { get; set; }
+
+        /// <summary>
+        /// Gets or sets the contour colors.
+        /// </summary>
+        /// <value>The contour colors.</value>
+        /// <remarks>
+        /// These colors will override the Color of the series.
+        /// If there are less colors than the number of contour levels, the colors will cycle.
+        /// </remarks>
+        public OxyColor[] ContourColors { get; set; }
+
+        /// <summary>
+        /// Gets or sets the data.
+        /// </summary>
+        /// <value>The data.</value>
+        public double[,] Data { get; set; }
+
+        /// <summary>
+        /// Gets or sets the text background color.
+        /// </summary>
+        /// <value>The text background color.</value>
+        public OxyColor LabelBackground { get; set; }
+
+        /// <summary>
+        /// Gets or sets the format string for contour values.
+        /// </summary>
+        /// <value>The format string.</value>
+        public string LabelFormatString { get; set; }
+
+        /// <summary>
+        /// Gets or sets the label spacing.
+        /// </summary>
+        /// <value>The label spacing.</value>
+        public double LabelSpacing { get; set; }
+
+        /// <summary>
+        /// Gets or sets the label step (number of contours per label).
+        /// </summary>
+        /// <value>The label step.</value>
+        public int LabelStep { get; set; }
+
+        /// <summary>
+        /// Gets or sets the line style.
+        /// </summary>
+        /// <value>The line style.</value>
+        public LineStyle LineStyle { get; set; }
+
+        /// <summary>
+        /// Gets or sets the row coordinates.
+        /// </summary>
+        /// <value>The row coordinates.</value>
+        public double[] RowCoordinates { get; set; }
+
+        /// <summary>
+        /// Gets or sets the stroke thickness.
+        /// </summary>
+        /// <value>The stroke thickness.</value>
+        public double StrokeThickness { get; set; }
+
+        /// <summary>
+        /// Calculates the contours.
+        /// </summary>
+        public void CalculateContours()
+        {
+            if (this.Data == null)
+            {
+                return;
+            }
+
+            double[] actualContourLevels = this.ContourLevels;
+
+            this.segments = new List<ContourSegment>();
+            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];
+                    }
+                }
+            }
+        }
+
+        /// <summary>
+        /// Gets the point in the dataset that is nearest the specified point.
+        /// </summary>
+        /// <param name="point">
+        /// The point.
+        /// </param>
+        /// <param name="interpolate">
+        /// The interpolate.
+        /// </param>
+        /// <returns>
+        /// A hit result object.
+        /// </returns>
+        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;
+        }
+
+        /// <summary>
+        /// Renders the series on the specified rendering context.
+        /// </summary>
+        /// <param name="rc">
+        /// The rendering context.
+        /// </param>
+        /// <param name="model">
+        /// The model.
+        /// </param>
+        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<ContourLabel>();
+
+            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);
+            }
+        }
+
+        /// <summary>
+        /// Sets default values from the plotmodel.
+        /// </summary>
+        /// <param name="model">
+        /// The plot model.
+        /// </param>
+        protected internal override void SetDefaultValues(PlotModel model)
+        {
+            if (this.Color == null)
+            {
+                this.LineStyle = model.GetDefaultLineStyle();
+                this.defaultColor = model.GetDefaultColor();
+            }
+        }
+
+        /// <summary>
+        /// Updates the max/min from the datapoints.
+        /// </summary>
+        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();
+        }
+
+        /// <summary>
+        /// Determines if two values are close.
+        /// </summary>
+        /// <param name="x1">
+        /// The first value.
+        /// </param>
+        /// <param name="x2">
+        /// The second value.
+        /// </param>
+        /// <param name="eps">
+        /// The squared tolerance.
+        /// </param>
+        /// <returns>
+        /// True if the values are close.
+        /// </returns>
+        private static bool AreClose(double x1, double x2, double eps = 1e-6)
+        {
+            double dx = x1 - x2;
+            return dx * dx < eps;
+        }
+
+        /// <summary>
+        /// Determines if two points are close.
+        /// </summary>
+        /// <param name="p0">
+        /// The first point.
+        /// </param>
+        /// <param name="p1">
+        /// The second point.
+        /// </param>
+        /// <param name="eps">
+        /// The squared tolerance.
+        /// </param>
+        /// <returns>
+        /// True if the points are close.
+        /// </returns>
+        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;
+        }
+
+        /// <summary>
+        /// Gets the index of item that is closest to the specified value.
+        /// </summary>
+        /// <param name="values">A list of values.</param>
+        /// <param name="value">A value.</param>
+        /// <returns>An index.</returns>
+        private static int IndexOf(IList<double> 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;
+        }
+
+        /// <summary>
+        /// The add contour labels.
+        /// </summary>
+        /// <param name="contour">
+        /// The contour.
+        /// </param>
+        /// <param name="pts">
+        /// The pts.
+        /// </param>
+        /// <param name="clippingRect">
+        /// The clipping rect.
+        /// </param>
+        /// <param name="contourLabels">
+        /// The contour labels.
+        /// </param>
+        private void AddContourLabels(
+            Contour contour, ScreenPoint[] pts, OxyRect clippingRect, List<ContourLabel> 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 });
+        }
+
+        /// <summary>
+        /// Finds the connected segment.
+        /// </summary>
+        /// <param name="point">
+        /// The point.
+        /// </param>
+        /// <param name="contourLevel">
+        /// The contour level.
+        /// </param>
+        /// <param name="eps">
+        /// The eps.
+        /// </param>
+        /// <param name="reverse">
+        /// reverse the segment if set to <c>true</c>.
+        /// </param>
+        /// <returns>
+        /// The connected segment, or null if no segment was found.
+        /// </returns>
+        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;
+        }
+
+        /// <summary>
+        /// Joins the contour segments.
+        /// </summary>
+        /// <param name="eps">
+        /// The tolerance for segment ends to connect (squared distance).
+        /// </param>
+        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<Contour>();
+            var contourPoints = new List<IDataPoint>();
+            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<IDataPoint>();
+                        contourPointsCount = 0;
+                    }
+
+                    if (segmentCount > 0)
+                    {
+                        firstSegment = this.segments.First();
+                        contourPoints.Add(firstSegment.StartPoint);
+                        contourPoints.Add(firstSegment.EndPoint);
+                        contourPointsCount += 2;
+                        this.segments.Remove(firstSegment);
+                        segmentCount--;
+                    }
+                }
+            }
+        }
+
+        /// <summary>
+        /// Renders the contour label.
+        /// </summary>
+        /// <param name="rc">
+        /// The render context.
+        /// </param>
+        /// <param name="cl">
+        /// The contour label.
+        /// </param>
+        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);
+            }
+        }
+
+        /// <summary>
+        /// Renders the contour label background.
+        /// </summary>
+        /// <param name="rc">
+        /// The render context.
+        /// </param>
+        /// <param name="cl">
+        /// The contour label.
+        /// </param>
+        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);
+            }
+        }
+
+        /// <summary>
+        /// Represents a contour.
+        /// </summary>
+        private class Contour
+        {
+            /// <summary>
+            /// Gets or sets the contour level.
+            /// </summary>
+            /// <value>The contour level.</value>
+            internal readonly double ContourLevel;
+
+            /// <summary>
+            /// Gets or sets the points.
+            /// </summary>
+            /// <value>The points.</value>
+            internal readonly IList<IDataPoint> Points;
+
+            /// <summary>
+            /// Initializes a new instance of the <see cref="Contour"/> class.
+            /// </summary>
+            /// <param name="points">
+            /// The points.
+            /// </param>
+            /// <param name="contourLevel">
+            /// The contour level.
+            /// </param>
+            public Contour(IList<IDataPoint> points, double contourLevel)
+            {
+                this.Points = points;
+                this.ContourLevel = contourLevel;
+            }
+
+            /// <summary>
+            /// Gets or sets the color of the contour.
+            /// </summary>
+            public OxyColor Color { get; set; }
+        }
+
+        /// <summary>
+        /// Represents a contour label.
+        /// </summary>
+        private class ContourLabel
+        {
+            /// <summary>
+            /// Gets or sets the angle.
+            /// </summary>
+            /// <value>The angle.</value>
+            public double Angle { get; set; }
+
+            /// <summary>
+            /// Gets or sets the position.
+            /// </summary>
+            /// <value>The position.</value>
+            public ScreenPoint Position { get; set; }
+
+            /// <summary>
+            /// Gets or sets the text.
+            /// </summary>
+            /// <value>The text.</value>
+            public string Text { get; set; }
+
+        }
+
+        /// <summary>
+        /// Represents a contour segment.
+        /// </summary>
+        private class ContourSegment
+        {
+            /// <summary>
+            /// The contour level.
+            /// </summary>
+            internal readonly double ContourLevel;
+
+            /// <summary>
+            /// The end point.
+            /// </summary>
+            internal readonly DataPoint EndPoint;
+
+            /// <summary>
+            /// The start point.
+            /// </summary>
+            internal readonly DataPoint StartPoint;
+
+            /// <summary>
+            /// Initializes a new instance of the <see cref="ContourSegment"/> class.
+            /// </summary>
+            /// <param name="startPoint">
+            /// The start point.
+            /// </param>
+            /// <param name="endPoint">
+            /// The end point.
+            /// </param>
+            /// <param name="contourLevel">
+            /// The contour level.
+            /// </param>
+            public ContourSegment(DataPoint startPoint, DataPoint endPoint, double contourLevel)
+            {
+                this.ContourLevel = contourLevel;
+                this.StartPoint = startPoint;
+                this.EndPoint = endPoint;
+            }
+
+        }
+    }
+}
\ No newline at end of file
diff --git a/oxyplot/OxyPlot/Series/DataPointSeries.cs b/oxyplot/OxyPlot/Series/DataPointSeries.cs
new file mode 100644
index 0000000..1efa50d
--- /dev/null
+++ b/oxyplot/OxyPlot/Series/DataPointSeries.cs
@@ -0,0 +1,325 @@
+// 
--------------------------------------------------------------------------------------------------------------------
+// <copyright file="DataPointSeries.cs" company="OxyPlot">
+//   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.
+// </copyright>
+// <summary>
+//   Base class for series that contain a collection of IDataPoints.
+// </summary>
+// 
--------------------------------------------------------------------------------------------------------------------
+namespace OxyPlot.Series
+{
+    using System;
+    using System.Collections;
+    using System.Collections.Generic;
+    using System.Reflection;
+
+    /// <summary>
+    /// Provides an abstract base class for series that contain a collection of <see cref="IDataPoint"/>s.
+    /// </summary>
+    public abstract class DataPointSeries : XYAxisSeries
+    {
+        /// <summary>
+        /// The list of data points.
+        /// </summary>
+        private IList<IDataPoint> points = new List<IDataPoint>();
+
+        /// <summary>
+        /// Initializes a new instance of the <see cref = "DataPointSeries" /> class.
+        /// </summary>
+        protected DataPointSeries()
+        {
+            this.DataFieldX = null;
+            this.DataFieldY = null;
+        }
+
+        /// <summary>
+        /// Gets or sets a value indicating whether the tracker can interpolate points.
+        /// </summary>
+        public bool CanTrackerInterpolatePoints { get; set; }
+
+        /// <summary>
+        /// Gets or sets the data field X.
+        /// </summary>
+        /// <value>The data field X.</value>
+        public string DataFieldX { get; set; }
+
+        /// <summary>
+        /// Gets or sets the data field Y.
+        /// </summary>
+        /// <value>The data field Y.</value>
+        public string DataFieldY { get; set; }
+
+        /// <summary>
+        /// Gets or sets the mapping delegate.
+        /// Example: series1.Mapping = item => new DataPoint(((MyType)item).Time,((MyType)item).Value);
+        /// </summary>
+        /// <value>The mapping.</value>
+        public Func<object, IDataPoint> Mapping { get; set; }
+
+        /// <summary>
+        /// Gets or sets the points list.
+        /// </summary>
+        /// <value>The points list.</value>
+        public IList<IDataPoint> Points
+        {
+            get
+            {
+                return this.points;
+            }
+
+            set
+            {
+                this.points = value;
+            }
+        }
+
+        /// <summary>
+        /// Gets or sets a value indicating whether this <see cref = "DataPointSeries" /> is smooth.
+        /// </summary>
+        /// <value><c>true</c> if smooth; otherwise, <c>false</c>.</value>
+        public bool Smooth { get; set; }
+
+        /// <summary>
+        /// Gets the point on the series that is nearest the specified point.
+        /// </summary>
+        /// <param name="point">The point.</param>
+        /// <param name="interpolate">Interpolate the series if this flag is set to <c>true</c>.</param>
+        /// <returns>
+        /// A TrackerHitResult for the current hit.
+        /// </returns>
+        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);
+        }
+
+        /// <summary>
+        /// Gets the item at the specified index.
+        /// </summary>
+        /// <param name="i">The index of the item.</param>
+        /// <returns>The item of the index.</returns>
+        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);
+        }
+
+        /// <summary>
+        /// The update data.
+        /// </summary>
+        protected internal override void UpdateData()
+        {
+            if (this.ItemsSource == null)
+            {
+                return;
+            }
+
+            this.AddDataPoints(this.Points);
+        }
+
+        /// <summary>
+        /// Updates the max/min from the datapoints.
+        /// </summary>
+        protected internal override void UpdateMaxMin()
+        {
+            base.UpdateMaxMin();
+            this.InternalUpdateMaxMin(this.Points);
+        }
+
+        /// <summary>
+        /// The add data points.
+        /// </summary>
+        /// <param name="pts">
+        /// The points.
+        /// </param>
+        protected void AddDataPoints(IList<IDataPoint> 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);
+            }
+        }
+
+        /// <summary>
+        /// The add data points.
+        /// </summary>
+        /// <param name="dest">
+        /// The dest.
+        /// </param>
+        /// <param name="itemsSource">
+        /// The items source.
+        /// </param>
+        /// <param name="dataFieldX">
+        /// The data field x.
+        /// </param>
+        /// <param name="dataFieldY">
+        /// The data field y.
+        /// </param>
+        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<DataPoint>();
+            //filler.Add(dataFieldX, (item, value) => item.X = this.ToDouble(value));
+            //filler.Add(dataFieldY, (item, value) => item.Y = this.ToDouble(value));
+            //filler.Fill(dest, itemsSource);
+        }
+
+        /// <summary>
+        /// Updates the Max/Min limits from the specified point list.
+        /// </summary>
+        /// <param name="pts">
+        /// The points.
+        /// </param>
+        protected void InternalUpdateMaxMin(IList<IDataPoint> 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 --git a/oxyplot/OxyPlot/Series/DataSeries.cs b/oxyplot/OxyPlot/Series/DataSeries.cs
new file mode 100644
index 0000000..f9b17d6
--- /dev/null
+++ b/oxyplot/OxyPlot/Series/DataSeries.cs
@@ -0,0 +1,391 @@
+// 
--------------------------------------------------------------------------------------------------------------------
+// <copyright file="DataSeries.cs" company="OxyPlot">
+//   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.
+// </copyright>
+// <summary>
+//   DataPointProvider interface.
+// </summary>
+// 
--------------------------------------------------------------------------------------------------------------------
+using System;
+using System.Collections;
+using System.Collections.Generic;
+using System.Collections.ObjectModel;
+using System.ComponentModel;
+using System.Linq;
+using System.Reflection;
+
+namespace OxyPlot
+{
+    /// <summary>
+    /// DataPointProvider interface.
+    /// </summary>
+    public interface IDataPointProvider
+    {
+        /// <summary>
+        /// Gets the data point.
+        /// </summary>
+        /// <returns></returns>
+        DataPoint GetDataPoint();
+    }
+
+    public abstract class DataSeries : PlotSeriesBase
+    {
+        protected IList<DataPoint> points;
+
+        protected DataSeries()
+        {
+            points = new Collection<DataPoint>();
+            DataFieldX = "X";
+            DataFieldY = "Y";
+            CanTrackerInterpolatePoints = false;
+        }
+
+        /// <summary>
+        /// Gets or sets the items source.
+        /// </summary>
+        /// <value>The items source.</value>
+        public IEnumerable ItemsSource { get; set; }
+
+        /// <summary>
+        /// Gets or sets the data field X.
+        /// </summary>
+        /// <value>The data field X.</value>
+        public string DataFieldX { get; set; }
+
+        /// <summary>
+        /// Gets or sets the data field Y.
+        /// </summary>
+        /// <value>The data field Y.</value>
+        public string DataFieldY { get; set; }
+
+        /// <summary>
+        /// Gets or sets the mapping deleagte.
+        /// Example: series1.Mapping = item => new DataPoint(((MyType)item).Time,((MyType)item).Value);
+        /// </summary>
+        /// <value>The mapping.</value>
+        public Func<object, DataPoint> Mapping { get; set; }
+
+        /// <summary>
+        /// Gets or sets the points.
+        /// </summary>
+        /// <value>The points.</value>
+        [Browsable(false)]
+        public IList<DataPoint> Points
+        {
+            get { return points; }
+            set { points = value; }
+        }
+
+        /// <summary>
+        /// Gets or sets a value indicating whether this <see cref = "DataSeries" /> is smooth.
+        /// </summary>
+        /// <value><c>true</c> if smooth; otherwise, <c>false</c>.</value>
+        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);
+        }
+
+        /// <summary>
+        /// 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
+        /// </summary>
+        /// <param name="value">The value.</param>
+        /// <returns></returns>
+        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);
+        }
+
+        /// <summary>
+        /// Updates the max/min from the datapoints.
+        /// </summary>
+        public override void UpdateMaxMin()
+        {
+            base.UpdateMaxMin();
+            InternalUpdateMaxMin(points);
+        }
+
+        /// <summary>
+        /// Gets the point in the dataset that is nearest the specified point.
+        /// </summary>
+        /// <param name = "point">The point.</param>
+        /// <param name = "dpn">The nearest point (data coordinates).</param>
+        /// <param name = "spn">The nearest point (screen coordinates).</param>
+        /// <returns></returns>
+        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;
+        }
+
+        /// <summary>
+        /// Gets the point on the curve that is nearest the specified point.
+        /// </summary>
+        /// <param name = "point">The point.</param>
+        /// <param name = "dpn">The nearest point (data coordinates).</param>
+        /// <param name = "spn">The nearest point (screen coordinates).</param>
+        /// <returns></returns>
+        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<DataPoint> 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);
+            }
+        }
+
+        /// <summary>
+        /// Updates the Max/Min limits from the specified point list.
+        /// </summary>
+        /// <param name="pts">The PTS.</param>
+        protected void InternalUpdateMaxMin(IList<DataPoint> 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);
+        }
+
+        /// <summary>
+        /// Gets the value from the specified X.
+        /// </summary>
+        /// <param name = "x">The x.</param>
+        /// <returns></returns>
+        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 --git a/oxyplot/OxyPlot/Series/FunctionSeries.cs b/oxyplot/OxyPlot/Series/FunctionSeries.cs
new file mode 100644
index 0000000..ced024e
--- /dev/null
+++ b/oxyplot/OxyPlot/Series/FunctionSeries.cs
@@ -0,0 +1,157 @@
+// 
--------------------------------------------------------------------------------------------------------------------
+// <copyright file="FunctionSeries.cs" company="OxyPlot">
+//   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.
+// </copyright>
+// <summary>
+//   Represents a line series that generates its dataset from a function.
+// </summary>
+// 
--------------------------------------------------------------------------------------------------------------------
+namespace OxyPlot.Series
+{
+    using System;
+
+    /// <summary>
+    /// Represents a line series that generates its dataset from a function.
+    /// </summary>
+    /// <remarks>
+    /// 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].
+    /// </remarks>
+    public class FunctionSeries : LineSeries
+    {
+        /// <summary>
+        /// Initializes a new instance of the <see cref = "FunctionSeries" /> class.
+        /// </summary>
+        public FunctionSeries()
+        {
+        }
+
+        /// <summary>
+        /// Initializes a new instance of the <see cref="FunctionSeries"/> class.
+        /// </summary>
+        /// <param name="f">
+        /// The function f(x).
+        /// </param>
+        /// <param name="x0">
+        /// The start x value.
+        /// </param>
+        /// <param name="x1">
+        /// The end x value.
+        /// </param>
+        /// <param name="dx">
+        /// The increment in x.
+        /// </param>
+        /// <param name="title">
+        /// The title (optional).
+        /// </param>
+        public FunctionSeries(Func<double, double> 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)));
+            }
+        }
+
+        /// <summary>
+        /// Initializes a new instance of the <see cref="FunctionSeries"/> class.
+        /// </summary>
+        /// <param name="f">
+        /// The function f(x).
+        /// </param>
+        /// <param name="x0">
+        /// The start x value.
+        /// </param>
+        /// <param name="x1">
+        /// The end x value.
+        /// </param>
+        /// <param name="n">
+        /// The number of points.
+        /// </param>
+        /// <param name="title">
+        /// The title (optional).
+        /// </param>
+        public FunctionSeries(Func<double, double> f, double x0, double x1, int n, string title = null)
+            : this(f, x0, x1, (x1 - x0) / (n - 1), title)
+        {
+        }
+
+        /// <summary>
+        /// Initializes a new instance of the <see cref="FunctionSeries"/> class.
+        /// </summary>
+        /// <param name="fx">
+        /// The function fx(t).
+        /// </param>
+        /// <param name="fy">
+        /// The function fy(t).
+        /// </param>
+        /// <param name="t0">
+        /// The t0.
+        /// </param>
+        /// <param name="t1">
+        /// The t1.
+        /// </param>
+        /// <param name="dt">
+        /// The increment dt.
+        /// </param>
+        /// <param name="title">
+        /// The title.
+        /// </param>
+        public FunctionSeries(Func<double, double> fx, Func<double, double> 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)));
+            }
+        }
+
+        /// <summary>
+        /// Initializes a new instance of the <see cref="FunctionSeries"/> class.
+        /// </summary>
+        /// <param name="fx">
+        /// The function fx(t).
+        /// </param>
+        /// <param name="fy">
+        /// The function fy(t).
+        /// </param>
+        /// <param name="t0">
+        /// The t0.
+        /// </param>
+        /// <param name="t1">
+        /// The t1.
+        /// </param>
+        /// <param name="n">
+        /// The number of points.
+        /// </param>
+        /// <param name="title">
+        /// The title.
+        /// </param>
+        public FunctionSeries(
+            Func<double, double> fx, Func<double, double> 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 --git a/oxyplot/OxyPlot/Series/HeatMapSeries.cs b/oxyplot/OxyPlot/Series/HeatMapSeries.cs
new file mode 100644
index 0000000..1170537
--- /dev/null
+++ b/oxyplot/OxyPlot/Series/HeatMapSeries.cs
@@ -0,0 +1,238 @@
+// 
--------------------------------------------------------------------------------------------------------------------
+// <copyright file="HeatMapSeries.cs" company="OxyPlot">
+//   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.
+// </copyright>
+// <summary>
+//   The heat map series.
+// </summary>
+// 
--------------------------------------------------------------------------------------------------------------------
+
+namespace OxyPlot.Series
+{
+    using System;
+    using System.Collections.Generic;
+    using System.Linq;
+
+    using OxyPlot.Axes;
+
+    /// <summary>
+    /// The heat map series.
+    /// </summary>
+    /// <remarks>
+    /// Does not work with Silverlight. Silverlight does not support bitmaps, only PNG and JPG.
+    /// </remarks>
+    public class HeatMapSeries : XYAxisSeries
+    {
+        /// <summary>
+        /// The hash code of the current data.
+        /// </summary>
+        private int dataHash;
+
+        /// <summary>
+        /// The image
+        /// </summary>
+        private OxyImage image;
+
+        /// <summary>
+        /// Gets or sets the x 0.
+        /// </summary>
+        public double X0 { get; set; }
+
+        /// <summary>
+        /// Gets or sets the x 1.
+        /// </summary>
+        public double X1 { get; set; }
+
+        /// <summary>
+        /// Gets or sets the y 0.
+        /// </summary>
+        public double Y0 { get; set; }
+
+        /// <summary>
+        /// Gets or sets the y 1.
+        /// </summary>
+        public double Y1 { get; set; }
+
+        /// <summary>
+        /// Gets or sets the data.
+        /// </summary>
+        public double[,] Data { get; set; }
+
+        /// <summary>
+        /// Gets or sets the minimum value of the dataset.
+        /// </summary>
+        public double MinValue { get; protected set; }
+
+        /// <summary>
+        /// Gets or sets the maximum value of the dataset.
+        /// </summary>
+        public double MaxValue { get; protected set; }
+
+        /// <summary>
+        /// Gets or sets the color axis.
+        /// </summary>
+        /// <value>
+        /// The color axis.
+        /// </value>
+        public ColorAxis ColorAxis { get; protected set; }
+
+        /// <summary>
+        /// Gets or sets the color axis key.
+        /// </summary>
+        /// <value> The color axis key. </value>
+        public string ColorAxisKey { get; set; }
+
+        /// <summary>
+        /// Renders the series on the specified render context.
+        /// </summary>
+        /// <param name="rc">
+        /// The rendering context.
+        /// </param>
+        /// <param name="model">
+        /// The model.
+        /// </param>
+        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);
+            }
+        }
+
+        /// <summary>
+        /// Gets the point on the series that is nearest the specified point.
+        /// </summary>
+        /// <param name="point">
+        /// The point.
+        /// </param>
+        /// <param name="interpolate">
+        /// Interpolate the series if this flag is set to <c>true</c>.
+        /// </param>
+        /// <returns>
+        /// A TrackerHitResult for the current hit.
+        /// </returns>
+        public override TrackerHitResult GetNearestPoint(ScreenPoint point, bool interpolate)
+        {
+            return null;
+        }
+
+        /// <summary>
+        /// Ensures that the axes of the series is defined.
+        /// </summary>
+        protected internal override void EnsureAxes()
+        {
+            base.EnsureAxes();
+
+            this.ColorAxis =
+                this.PlotModel.GetAxisOrDefault(this.ColorAxisKey, this.PlotModel.DefaultColorAxis) as 
ColorAxis;
+        }
+
+        /// <summary>
+        /// Updates the max/minimum values.
+        /// </summary>
+        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);
+        }
+
+        /// <summary>
+        /// Gets the data as a sequence (LINQ-friendly).
+        /// </summary>
+        /// <returns>The sequence of data.</returns>
+        protected IEnumerable<double> 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];
+                }
+            }
+        }
+
+        /// <summary>
+        /// Updates the image.
+        /// </summary>
+        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 --git a/oxyplot/OxyPlot/Series/HighLowItem.cs b/oxyplot/OxyPlot/Series/HighLowItem.cs
new file mode 100644
index 0000000..e3bcf99
--- /dev/null
+++ b/oxyplot/OxyPlot/Series/HighLowItem.cs
@@ -0,0 +1,187 @@
+// 
--------------------------------------------------------------------------------------------------------------------
+// <copyright file="HighLowItem.cs" company="OxyPlot">
+//   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.
+// </copyright>
+// <summary>
+//   Represents an item in a HighLowSeries.
+// </summary>
+// 
--------------------------------------------------------------------------------------------------------------------
+namespace OxyPlot.Series
+{
+    /// <summary>
+    /// Represents an item in a <see cref="HighLowSeries"/>.
+    /// </summary>
+    public class HighLowItem
+    {
+        /// <summary>
+        /// The undefined.
+        /// </summary>
+        public static readonly HighLowItem Undefined = new HighLowItem(double.NaN, double.NaN, double.NaN);
+
+        /// <summary>
+        /// The close.
+        /// </summary>
+        private double close;
+
+        /// <summary>
+        /// The high.
+        /// </summary>
+        private double high;
+
+        /// <summary>
+        /// The low.
+        /// </summary>
+        private double low;
+
+        /// <summary>
+        /// The open.
+        /// </summary>
+        private double open;
+
+        /// <summary>
+        /// The x.
+        /// </summary>
+        private double x;
+
+        /// <summary>
+        /// Initializes a new instance of the <see cref="HighLowItem"/> class.
+        /// </summary>
+        public HighLowItem()
+        {
+        }
+
+        /// <summary>
+        /// Initializes a new instance of the <see cref="HighLowItem"/> struct.
+        /// </summary>
+        /// <param name="x">
+        /// The x value.
+        /// </param>
+        /// <param name="high">
+        /// The high value.
+        /// </param>
+        /// <param name="low">
+        /// The low value.
+        /// </param>
+        /// <param name="open">
+        /// The open value.
+        /// </param>
+        /// <param name="close">
+        /// The close value.
+        /// </param>
+        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;
+        }
+
+        /// <summary>
+        /// Gets or sets the close value.
+        /// </summary>
+        /// <value>The close value.</value>
+        public double Close
+        {
+            get
+            {
+                return this.close;
+            }
+
+            set
+            {
+                this.close = value;
+            }
+        }
+
+        /// <summary>
+        /// Gets or sets the high value.
+        /// </summary>
+        /// <value>The high value.</value>
+        public double High
+        {
+            get
+            {
+                return this.high;
+            }
+
+            set
+            {
+                this.high = value;
+            }
+        }
+
+        /// <summary>
+        /// Gets or sets the low value.
+        /// </summary>
+        /// <value>The low value.</value>
+        public double Low
+        {
+            get
+            {
+                return this.low;
+            }
+
+            set
+            {
+                this.low = value;
+            }
+        }
+
+        /// <summary>
+        /// Gets or sets the open value.
+        /// </summary>
+        /// <value>The open value.</value>
+        public double Open
+        {
+            get
+            {
+                return this.open;
+            }
+
+            set
+            {
+                this.open = value;
+            }
+        }
+
+        /// <summary>
+        /// Gets or sets the X value (time).
+        /// </summary>
+        /// <value>The X value.</value>
+        public double X
+        {
+            get
+            {
+                return this.x;
+            }
+
+            set
+            {
+                this.x = value;
+            }
+        }
+
+    }
+}
\ No newline at end of file
diff --git a/oxyplot/OxyPlot/Series/HighLowSeries.cs b/oxyplot/OxyPlot/Series/HighLowSeries.cs
new file mode 100644
index 0000000..88914ba
--- /dev/null
+++ b/oxyplot/OxyPlot/Series/HighLowSeries.cs
@@ -0,0 +1,502 @@
+// 
--------------------------------------------------------------------------------------------------------------------
+// <copyright file="HighLowSeries.cs" company="OxyPlot">
+//   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.
+// </copyright>
+// <summary>
+//   Represents a series for high-low plots.
+// </summary>
+// 
--------------------------------------------------------------------------------------------------------------------
+namespace OxyPlot.Series
+{
+    using System;
+    using System.Collections.Generic;
+
+    using OxyPlot.Axes;
+
+    /// <summary>
+    /// Represents a series for high-low plots.
+    /// </summary>
+    /// <remarks>
+    /// See http://www.mathworks.com/help/toolbox/finance/highlowfts.html
+    /// </remarks>
+    public class HighLowSeries : XYAxisSeries
+    {
+        /// <summary>
+        /// High/low items
+        /// </summary>
+        private IList<HighLowItem> items;
+
+        /// <summary>
+        /// The default color.
+        /// </summary>
+        private OxyColor defaultColor;
+
+        /// <summary>
+        /// Initializes a new instance of the <see cref = "HighLowSeries" /> class.
+        /// </summary>
+        public HighLowSeries()
+        {
+            this.items = new List<HighLowItem>();
+            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}";
+        }
+
+        /// <summary>
+        /// Initializes a new instance of the <see cref="HighLowSeries"/> class.
+        /// </summary>
+        /// <param name="title">
+        /// The title.
+        /// </param>
+        public HighLowSeries(string title)
+            : this()
+        {
+            this.Title = title;
+        }
+
+        /// <summary>
+        /// Initializes a new instance of the <see cref="HighLowSeries"/> class.
+        /// </summary>
+        /// <param name="color">
+        /// The color.
+        /// </param>
+        /// <param name="strokeThickness">
+        /// The stroke thickness.
+        /// </param>
+        /// <param name="title">
+        /// The title.
+        /// </param>
+        public HighLowSeries(OxyColor color, double strokeThickness = 1, string title = null)
+            : this()
+        {
+            this.Color = color;
+            this.StrokeThickness = strokeThickness;
+            this.Title = title;
+        }
+
+        /// <summary>
+        /// Gets or sets the color of the curve.
+        /// </summary>
+        /// <value>The color.</value>
+        public OxyColor Color { get; set; }
+
+        /// <summary>
+        /// Gets the actual color.
+        /// </summary>
+        /// <value>The actual color.</value>
+        public OxyColor ActualColor
+        {
+            get { return this.Color ?? this.defaultColor; }
+        }
+
+        /// <summary>
+        /// Gets or sets the dashes array.
+        /// If this is not null it overrides the LineStyle property.
+        /// </summary>
+        /// <value>The dashes.</value>
+        public double[] Dashes { get; set; }
+
+        /// <summary>
+        /// Gets or sets the data field for the Close value.
+        /// </summary>
+        public string DataFieldClose { get; set; }
+
+        /// <summary>
+        /// Gets or sets the data field for the High value.
+        /// </summary>
+        public string DataFieldHigh { get; set; }
+
+        /// <summary>
+        /// Gets or sets the data field for the Low value.
+        /// </summary>
+        public string DataFieldLow { get; set; }
+
+        /// <summary>
+        /// Gets or sets the data field for the Open value.
+        /// </summary>
+        public string DataFieldOpen { get; set; }
+
+        /// <summary>
+        /// Gets or sets the x data field (time).
+        /// </summary>
+        public string DataFieldX { get; set; }
+
+        /// <summary>
+        /// Gets or sets the points.
+        /// </summary>
+        /// <value>The points.</value>
+        public IList<HighLowItem> Items
+        {
+            get
+            {
+                return this.items;
+            }
+
+            set
+            {
+                this.items = value;
+            }
+        }
+
+        /// <summary>
+        /// Gets or sets the line join.
+        /// </summary>
+        /// <value>The line join.</value>
+        public OxyPenLineJoin LineJoin { get; set; }
+
+        /// <summary>
+        /// Gets or sets the line style.
+        /// </summary>
+        /// <value>The line style.</value>
+        public LineStyle LineStyle { get; set; }
+
+        /// <summary>
+        /// Gets or sets the mapping deleagte.
+        /// Example: series1.Mapping = item => new HighLowItem(((MyType)item).Time,((MyType)item).Value);
+        /// </summary>
+        /// <value>The mapping.</value>
+        public Func<object, HighLowItem> Mapping { get; set; }
+
+        /// <summary>
+        /// Gets or sets the thickness of the curve.
+        /// </summary>
+        /// <value>The stroke thickness.</value>
+        public double StrokeThickness { get; set; }
+
+        /// <summary>
+        /// Gets or sets the length of the open/close ticks (screen coordinates).
+        /// </summary>
+        /// <value>The length of the open/close ticks.</value>
+        public double TickLength { get; set; }
+
+        /// <summary>
+        /// Gets the point on the series that is nearest the specified point.
+        /// </summary>
+        /// <param name="point">The point.</param>
+        /// <param name="interpolate">Interpolate the series if this flag is set to <c>true</c>.</param>
+        /// <returns>
+        /// A TrackerHitResult for the current hit.
+        /// </returns>
+        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<DataPoint, HighLowItem, int> 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;
+        }
+
+        /// <summary>
+        /// Determines whether the point is valid.
+        /// </summary>
+        /// <param name="pt">The point.</param>
+        /// <param name="xaxis">The x axis.</param>
+        /// <param name="yaxis">The y axis.</param>
+        /// <returns>
+        ///  <c>true</c> if [is valid point] [the specified pt]; otherwise, <c>false</c>.
+        /// </returns>
+        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);
+        }
+
+        /// <summary>
+        /// Renders the series on the specified rendering context.
+        /// </summary>
+        /// <param name="rc">
+        /// The rendering context.
+        /// </param>
+        /// <param name="model">
+        /// The owner plot model.
+        /// </param>
+        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);
+                    }
+                }
+            }
+        }
+
+        /// <summary>
+        /// Renders the legend symbol for the series on the specified rendering context.
+        /// </summary>
+        /// <param name="rc">
+        /// The rendering context.
+        /// </param>
+        /// <param name="legendBox">
+        /// The bounding rectangle of the legend box.
+        /// </param>
+        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);
+        }
+
+        /// <summary>
+        /// Sets the default values.
+        /// </summary>
+        /// <param name="model">
+        /// The model.
+        /// </param>
+        protected internal override void SetDefaultValues(PlotModel model)
+        {
+            if (this.Color == null)
+            {
+                this.LineStyle = model.GetDefaultLineStyle();
+                this.defaultColor = model.GetDefaultColor();
+            }
+        }
+
+        /// <summary>
+        /// Updates the data.
+        /// </summary>
+        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<HighLowItem>();
+            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);
+        }
+
+        /// <summary>
+        /// Updates the max/min values.
+        /// </summary>
+        protected internal override void UpdateMaxMin()
+        {
+            base.UpdateMaxMin();
+            this.InternalUpdateMaxMin(this.items);
+        }
+
+        /// <summary>
+        /// Updates the Max/Min limits from the specified point list.
+        /// </summary>
+        /// <param name="pts">
+        /// The PTS.
+        /// </param>
+        protected void InternalUpdateMaxMin(IList<HighLowItem> 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 --git a/oxyplot/OxyPlot/Series/ITrackableSeries.cs b/oxyplot/OxyPlot/Series/ITrackableSeries.cs
new file mode 100644
index 0000000..06f0f52
--- /dev/null
+++ b/oxyplot/OxyPlot/Series/ITrackableSeries.cs
@@ -0,0 +1,67 @@
+// 
--------------------------------------------------------------------------------------------------------------------
+// <copyright file="ITrackableSeries.cs" company="OxyPlot">
+//   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.
+// </copyright>
+// <summary>
+//   Interface for Series that can be 'tracked'
+// </summary>
+// 
--------------------------------------------------------------------------------------------------------------------
+namespace OxyPlot.Series
+{
+    /// <summary>
+    /// Provides functionality to return data for a tracker control.
+    /// </summary>
+    /// <remarks>
+    /// The plot control will show a tracker with the current value when moving the mouse over the data.
+    /// </remarks>
+    public interface ITrackableSeries
+    {
+        /// <summary>
+        /// Gets a format string used for the tracker.
+        /// </summary>
+        /// <remarks>
+        /// The fields that can be used in the format string depends on the series.
+        /// </remarks>
+        string TrackerFormatString { get; }
+
+        /// <summary>
+        /// Gets the tracker key.
+        /// </summary>
+        string TrackerKey { get; }
+
+        /// <summary>
+        /// Gets the point on the series that is nearest the specified point.
+        /// </summary>
+        /// <param name="point">
+        /// The point.
+        /// </param>
+        /// <param name="interpolate">
+        /// Interpolate the series if this flag is set to <c>true</c>.
+        /// </param>
+        /// <returns>
+        /// A TrackerHitResult for the current hit.
+        /// </returns>
+        TrackerHitResult GetNearestPoint(ScreenPoint point, bool interpolate);
+    }
+}
\ No newline at end of file
diff --git a/oxyplot/OxyPlot/Series/ItemsSeries.cs b/oxyplot/OxyPlot/Series/ItemsSeries.cs
new file mode 100644
index 0000000..76399f6
--- /dev/null
+++ b/oxyplot/OxyPlot/Series/ItemsSeries.cs
@@ -0,0 +1,96 @@
+// 
--------------------------------------------------------------------------------------------------------------------
+// <copyright file="ItemsSeries.cs" company="OxyPlot">
+//   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.
+// </copyright>
+// <summary>
+//   Abstract base class for series that can contain items.
+// </summary>
+// 
--------------------------------------------------------------------------------------------------------------------
+namespace OxyPlot.Series
+{
+    using System.Collections;
+    using System.Linq;
+
+    /// <summary>
+    /// Abstract base class for series that can contain items.
+    /// </summary>
+    public abstract class ItemsSeries : Series
+    {
+        /// <summary>
+        /// Gets or sets the items source.
+        /// </summary>
+        /// <value> The items source. </value>
+        [CodeGeneration(false)]
+        public IEnumerable ItemsSource { get; set; }
+
+        /// <summary>
+        /// Updates the valid items
+        /// </summary>
+        protected internal override void UpdateValidData()
+        {
+        }
+
+        /// <summary>
+        /// Gets the item for the specified index.
+        /// </summary>
+        /// <param name="itemsSource"> The items source. </param>
+        /// <param name="index"> The index. </param>
+        /// <returns> The get item. </returns>
+        /// <remarks>
+        /// Returns null if ItemsSource is not set, or the index is outside the boundaries.
+        /// </remarks>
+        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<object>().FirstOrDefault(item => i++ == index);
+        }
+
+        /// <summary>
+        /// Gets the item at the specified index.
+        /// </summary>
+        /// <param name="i"> The index of the item. </param>
+        /// <returns> The item of the index. </returns>
+        protected virtual object GetItem(int i)
+        {
+            return GetItem(this.ItemsSource, i);
+        }
+
+    }
+}
\ No newline at end of file
diff --git a/oxyplot/OxyPlot/Series/LineLegendPosition.cs b/oxyplot/OxyPlot/Series/LineLegendPosition.cs
new file mode 100644
index 0000000..c726271
--- /dev/null
+++ b/oxyplot/OxyPlot/Series/LineLegendPosition.cs
@@ -0,0 +1,52 @@
+// 
--------------------------------------------------------------------------------------------------------------------
+// <copyright file="LineLegendPosition.cs" company="OxyPlot">
+//   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.
+// </copyright>
+// <summary>
+//   Specifies the position of legends rendered on a line series.
+// </summary>
+// 
--------------------------------------------------------------------------------------------------------------------
+namespace OxyPlot.Series
+{
+    /// <summary>
+    /// Specifies the position of legends rendered on a <see cref="LineSeries"/>.
+    /// </summary>
+    public enum LineLegendPosition
+    {
+        /// <summary>
+        /// Do not render legend on the line.
+        /// </summary>
+        None,
+
+        /// <summary>
+        /// Render legend at the start of the line.
+        /// </summary>
+        Start,
+
+        /// <summary>
+        /// Render legend at the end of the line.
+        /// </summary>
+        End
+    }
+}
\ No newline at end of file
diff --git a/oxyplot/OxyPlot/Series/LineSeries.cs b/oxyplot/OxyPlot/Series/LineSeries.cs
new file mode 100644
index 0000000..02db0bc
--- /dev/null
+++ b/oxyplot/OxyPlot/Series/LineSeries.cs
@@ -0,0 +1,644 @@
+// 
--------------------------------------------------------------------------------------------------------------------
+// <copyright file="LineSeries.cs" company="OxyPlot">
+//   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.
+// </copyright>
+// <summary>
+//   Represents a line series.
+// </summary>
+// 
--------------------------------------------------------------------------------------------------------------------
+
+namespace OxyPlot.Series
+{
+    using System;
+    using System.Collections.Generic;
+
+    /// <summary>
+    /// Represents a line series.
+    /// </summary>
+    public class LineSeries : DataPointSeries
+    {
+        /// <summary>
+        /// The divisor value used to calculate tolerance for line smoothing.
+        /// </summary>
+        private const double ToleranceDivisor = 200;
+
+        /// <summary>
+        /// The default color.
+        /// </summary>
+        private OxyColor defaultColor;
+
+        /// <summary>
+        /// The smoothed points.
+        /// </summary>
+        private IList<IDataPoint> smoothedPoints;
+
+        /// <summary>
+        /// Initializes a new instance of the <see cref = "LineSeries" /> class.
+        /// </summary>
+        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;
+        }
+
+        /// <summary>
+        /// Initializes a new instance of the <see cref="LineSeries"/> class.
+        /// </summary>
+        /// <param name="title">
+        /// The title.
+        /// </param>
+        public LineSeries(string title)
+            : this()
+        {
+            this.Title = title;
+        }
+
+        /// <summary>
+        /// Initializes a new instance of the <see cref="LineSeries"/> class.
+        /// </summary>
+        /// <param name="color">
+        /// The color of the line stroke.
+        /// </param>
+        /// <param name="strokeThickness">
+        /// The stroke thickness (optional).
+        /// </param>
+        /// <param name="title">
+        /// The title (optional).
+        /// </param>
+        public LineSeries(OxyColor color, double strokeThickness = 1, string title = null)
+            : this()
+        {
+            this.Color = color;
+            this.StrokeThickness = strokeThickness;
+            this.BrokenLineThickness = 0;
+            this.Title = title;
+        }
+
+        /// <summary>
+        /// Gets or sets the color of the curve.
+        /// </summary>
+        /// <value>The color.</value>
+        public OxyColor Color { get; set; }
+
+        /// <summary>
+        /// Gets or sets the color of the broken line segments.
+        /// </summary>
+        /// <remarks>
+        /// Add <c>DataPoint.Undefined</c> in the Points collection to create breaks in the line.
+        /// </remarks>
+        public OxyColor BrokenLineColor { get; set; }
+
+        /// <summary>
+        /// Gets or sets the broken line style.
+        /// </summary>
+        public LineStyle BrokenLineStyle { get; set; }
+
+        /// <summary>
+        /// Gets or sets the broken line thickness.
+        /// </summary>
+        public double BrokenLineThickness { get; set; }
+
+        /// <summary>
+        /// Gets or sets the dashes array.
+        /// If this is not null it overrides the LineStyle property.
+        /// </summary>
+        /// <value>The dashes.</value>
+        public double[] Dashes { get; set; }
+
+        /// <summary>
+        /// Gets or sets the label format string.
+        /// </summary>
+        /// <value> The label format string. </value>
+        public string LabelFormatString { get; set; }
+
+        /// <summary>
+        /// Gets or sets the label margins.
+        /// </summary>
+        public double LabelMargin { get; set; }
+
+        /// <summary>
+        /// Gets or sets the line join.
+        /// </summary>
+        /// <value>The line join.</value>
+        public OxyPenLineJoin LineJoin { get; set; }
+
+        /// <summary>
+        /// Gets or sets the line style.
+        /// </summary>
+        /// <value>The line style.</value>
+        public LineStyle LineStyle { get; set; }
+
+        /// <summary>
+        /// Gets or sets a value specifying the position of a legend rendered on the line.
+        /// </summary>
+        /// <value>A value specifying the position of the legend.</value>
+        public LineLegendPosition LineLegendPosition { get; set; }
+
+        /// <summary>
+        /// Gets or sets the marker fill color.
+        /// </summary>
+        /// <value>The marker fill.</value>
+        public OxyColor MarkerFill { get; set; }
+
+        /// <summary>
+        /// Gets or sets the marker outline polygon.
+        /// If this property is set, the MarkerType will not be used.
+        /// </summary>
+        /// <value>The marker outline.</value>
+        public ScreenPoint[] MarkerOutline { get; set; }
+
+        /// <summary>
+        /// Gets or sets the size of the marker.
+        /// </summary>
+        /// <value>The size of the marker.</value>
+        public double MarkerSize { get; set; }
+
+        /// <summary>
+        /// Gets or sets the marker stroke.
+        /// </summary>
+        /// <value>The marker stroke.</value>
+        public OxyColor MarkerStroke { get; set; }
+
+        /// <summary>
+        /// Gets or sets the marker stroke thickness.
+        /// </summary>
+        /// <value>The marker stroke thickness.</value>
+        public double MarkerStrokeThickness { get; set; }
+
+        /// <summary>
+        /// Gets or sets the type of the marker.
+        /// </summary>
+        /// <value>The type of the marker.</value>
+        /// <remarks>
+        /// If MarkerType.Custom is used, the MarkerOutline property must be specified.
+        /// </remarks>
+        public MarkerType MarkerType { get; set; }
+
+        /// <summary>
+        /// Gets or sets the minimum length of the segment.
+        /// Increasing this number will increase performance,
+        /// but make the curve less accurate.
+        /// </summary>
+        /// <value>The minimum length of the segment.</value>
+        public double MinimumSegmentLength { get; set; }
+
+        /// <summary>
+        /// Gets or sets the thickness of the curve.
+        /// </summary>
+        /// <value>The stroke thickness.</value>
+        public double StrokeThickness { get; set; }
+
+        /// <summary>
+        /// Gets the actual color.
+        /// </summary>
+        /// <value>The actual color.</value>
+        protected OxyColor ActualColor
+        {
+            get
+            {
+                return this.Color ?? this.defaultColor;
+            }
+        }
+
+        /// <summary>
+        /// Gets the actual line style.
+        /// </summary>
+        /// <value>
+        /// The actual line style.
+        /// </value>
+        protected LineStyle ActualLineStyle
+        {
+            get
+            {
+                return this.LineStyle != LineStyle.Undefined ? this.LineStyle : LineStyle.Solid;
+            }
+        }
+        
+        /// <summary>
+        /// Gets the smoothed points.
+        /// </summary>
+        /// <value>The smoothed points.</value>
+        protected IList<IDataPoint> SmoothedPoints
+        {
+            get
+            {
+                return this.smoothedPoints;
+            }
+        }
+
+        /// <summary>
+        /// Gets the point on the series that is nearest the specified point.
+        /// </summary>
+        /// <param name="point">The point.</param>
+        /// <param name="interpolate">Interpolate the series if this flag is set to <c>true</c>.</param>
+        /// <returns>
+        /// A TrackerHitResult for the current hit.
+        /// </returns>
+        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);
+        }
+
+        /// <summary>
+        /// Renders the series on the specified rendering context.
+        /// </summary>
+        /// <param name="rc">
+        /// The rendering context.
+        /// </param>
+        /// <param name="model">
+        /// The owner plot model.
+        /// </param>
+        public override void Render(IRenderContext rc, PlotModel model)
+        {
+            if (this.Points.Count == 0)
+            {
+                return;
+            }
+
+            this.VerifyAxes();
+
+            var clippingRect = this.GetClippingRect();
+            var transformedPoints = new List<ScreenPoint>();
+            var lineBreakSegments = new List<ScreenPoint>();
+
+            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);
+            }
+        }
+
+        /// <summary>
+        /// Renders the legend symbol for the line series on the
+        /// specified rendering context.
+        /// </summary>
+        /// <param name="rc">
+        /// The rendering context.
+        /// </param>
+        /// <param name="legendBox">
+        /// The bounding rectangle of the legend box.
+        /// </param>
+        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);
+        }
+
+        /// <summary>
+        /// The set default values.
+        /// </summary>
+        /// <param name="model">
+        /// The model.
+        /// </param>
+        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;
+                }
+            }
+        }
+
+        /// <summary>
+        /// Updates the axes to include the max and min of this series.
+        /// </summary>
+        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();
+            }
+        }
+
+        /// <summary>
+        /// Renders the point labels.
+        /// </summary>
+        /// <param name="rc">The render context.</param>
+        /// <param name="clippingRect">The clipping rectangle.</param>
+        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);
+            }
+        }
+
+        /// <summary>
+        /// Renders a legend on the line.
+        /// </summary>
+        /// <param name="rc">The render context.</param>
+        /// <param name="clippingRect">The clipping rectangle.</param>
+        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);
+        }
+
+        /// <summary>
+        /// Renders the transformed points.
+        /// </summary>
+        /// <param name="rc">
+        /// The render context.
+        /// </param>
+        /// <param name="clippingRect">
+        /// The clipping rectangle.
+        /// </param>
+        /// <param name="pointsToRender">
+        /// The points to render.
+        /// </param>
+        protected void RenderPoints(IRenderContext rc, OxyRect clippingRect, IList<ScreenPoint> 
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);
+            }
+        }
+
+        /// <summary>
+        /// Renders the (smoothed) line.
+        /// </summary>
+        /// <param name="rc">
+        /// The render context.
+        /// </param>
+        /// <param name="clippingRect">
+        /// The clipping rectangle.
+        /// </param>
+        /// <param name="pointsToRender">
+        /// The points to render.
+        /// </param>
+        protected virtual void RenderSmoothedLine(
+            IRenderContext rc, OxyRect clippingRect, IList<ScreenPoint> pointsToRender)
+        {
+            rc.DrawClippedLine(
+                pointsToRender, 
+                clippingRect, 
+                this.MinimumSegmentLength * this.MinimumSegmentLength, 
+                this.GetSelectableColor(this.ActualColor), 
+                this.StrokeThickness, 
+                this.ActualLineStyle, 
+                this.LineJoin, 
+                false);
+        }
+
+        /// <summary>
+        /// Force the smoothed points to be re-evaluated.
+        /// </summary>
+        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 --git a/oxyplot/OxyPlot/Series/PieSeries.cs b/oxyplot/OxyPlot/Series/PieSeries.cs
new file mode 100644
index 0000000..9c66c78
--- /dev/null
+++ b/oxyplot/OxyPlot/Series/PieSeries.cs
@@ -0,0 +1,481 @@
+// 
--------------------------------------------------------------------------------------------------------------------
+// <copyright file="PieSeries.cs" company="OxyPlot">
+//   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.
+// </copyright>
+// <summary>
+//   Represents a series for pie/circle/doughnut charts.
+// </summary>
+// 
--------------------------------------------------------------------------------------------------------------------
+namespace OxyPlot.Series
+{
+    using System;
+    using System.Collections.Generic;
+    using System.Linq;
+
+    using OxyPlot.Axes;
+
+    /// <summary>
+    /// Represents a series for pie/circle/doughnut charts.
+    /// </summary>
+    /// <remarks>
+    /// The arc length/central angle/area of each slice is proportional to the quantity it represents. See 
http://en.wikipedia.org/wiki/Pie_chart
+    /// </remarks>
+    public class PieSeries : ItemsSeries
+    {
+        /// <summary>
+        /// The slices.
+        /// </summary>
+        private IList<PieSlice> slices;
+
+        /// <summary>
+        /// Initializes a new instance of the <see cref="PieSeries"/> class.
+        /// </summary>
+        public PieSeries()
+        {
+            this.slices = new List<PieSlice>();
+
+            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;
+        }
+
+        /// <summary>
+        /// Gets or sets AngleIncrement.
+        /// </summary>
+        public double AngleIncrement { get; set; }
+
+        /// <summary>
+        /// Gets or sets AngleSpan.
+        /// </summary>
+        public double AngleSpan { get; set; }
+
+        /// <summary>
+        /// Gets or sets a value indicating whether AreInsideLabelsAngled.
+        /// </summary>
+        public bool AreInsideLabelsAngled { get; set; }
+
+        /// <summary>
+        /// Gets or sets the name of the property containing the color.
+        /// </summary>
+        /// <value> The color field. </value>
+        public string ColorField { get; set; }
+
+        /// <summary>
+        /// Gets or sets the diameter.
+        /// </summary>
+        /// <value> The diameter. </value>
+        public double Diameter { get; set; }
+
+        /// <summary>
+        /// Gets or sets the exploded distance.
+        /// </summary>
+        /// <value> The exploded distance. </value>
+        public double ExplodedDistance { get; set; }
+
+        /// <summary>
+        /// Gets or sets the inner diameter.
+        /// </summary>
+        /// <value> The inner diameter. </value>
+        public double InnerDiameter { get; set; }
+
+        /// <summary>
+        /// Gets or sets the inside label format.
+        /// </summary>
+        /// <value> The inside label format. </value>
+        public string InsideLabelFormat { get; set; }
+
+        /// <summary>
+        /// Gets or sets the inside label position.
+        /// </summary>
+        /// <value> The inside label position. </value>
+        public double InsideLabelPosition { get; set; }
+
+        /// <summary>
+        /// Gets or sets the is exploded field.
+        /// </summary>
+        /// <value> The is exploded field. </value>
+        public string IsExplodedField { get; set; }
+
+        /// <summary>
+        /// Gets or sets the label field.
+        /// </summary>
+        /// <value> The label field. </value>
+        public string LabelField { get; set; }
+
+        /// <summary>
+        /// Gets or sets the legend format.
+        /// </summary>
+        /// <value> The legend format. </value>
+        public string LegendFormat { get; set; }
+
+        /// <summary>
+        /// Gets or sets the outside label format.
+        /// </summary>
+        /// <value> The outside label format. </value>
+        public string OutsideLabelFormat { get; set; }
+
+        /// <summary>
+        /// Gets or sets the slices.
+        /// </summary>
+        /// <value> The slices. </value>
+        public IList<PieSlice> Slices
+        {
+            get
+            {
+                return this.slices;
+            }
+
+            set
+            {
+                this.slices = value;
+            }
+        }
+
+        /// <summary>
+        /// Gets or sets the start angle.
+        /// </summary>
+        /// <value> The start angle. </value>
+        public double StartAngle { get; set; }
+
+        /// <summary>
+        /// Gets or sets the stroke.
+        /// </summary>
+        /// <value> The stroke. </value>
+        public OxyColor Stroke { get; set; }
+
+        /// <summary>
+        /// Gets or sets the stroke thickness.
+        /// </summary>
+        /// <value> The stroke thickness. </value>
+        public double StrokeThickness { get; set; }
+
+        /// <summary>
+        /// Gets or sets the tick distance.
+        /// </summary>
+        /// <value> The tick distance. </value>
+        public double TickDistance { get; set; }
+
+        /// <summary>
+        /// Gets or sets the length of the horizontal part of the tick.
+        /// </summary>
+        /// <value> The length. </value>
+        public double TickHorizontalLength { get; set; }
+
+        /// <summary>
+        /// Gets or sets the tick label distance.
+        /// </summary>
+        /// <value> The tick label distance. </value>
+        public double TickLabelDistance { get; set; }
+
+        /// <summary>
+        /// Gets or sets the length of the tick radial.
+        /// </summary>
+        /// <value> The length of the tick radial. </value>
+        public double TickRadialLength { get; set; }
+
+        /// <summary>
+        /// Gets or sets the name of the property containing the value.
+        /// </summary>
+        /// <value> The value field. </value>
+        public string ValueField { get; set; }
+
+        /// <summary>
+        /// Gets the point on the series that is nearest the specified point.
+        /// </summary>
+        /// <param name="point">
+        /// The point.
+        /// </param>
+        /// <param name="interpolate">
+        /// Interpolate the series if this flag is set to <c>true</c> .
+        /// </param>
+        /// <returns>
+        /// A TrackerHitResult for the current hit.
+        /// </returns>
+        public override TrackerHitResult GetNearestPoint(ScreenPoint point, bool interpolate)
+        {
+            return null;
+        }
+
+        /// <summary>
+        /// Renders the series on the specified render context.
+        /// </summary>
+        /// <param name="rc">
+        /// The rendering context.
+        /// </param>
+        /// <param name="model">
+        /// The model.
+        /// </param>
+        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<ScreenPoint>();
+                var innerPoints = new List<ScreenPoint>();
+
+                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);
+                }
+            }
+        }
+
+        /// <summary>
+        /// Renders the legend symbol on the specified render context.
+        /// </summary>
+        /// <param name="rc">
+        /// The rendering context.
+        /// </param>
+        /// <param name="legendBox">
+        /// The legend rectangle.
+        /// </param>
+        public override void RenderLegend(IRenderContext rc, OxyRect legendBox)
+        {
+        }
+
+        /// <summary>
+        /// Check if this data series requires X/Y axes. (e.g. Pie series do not require axes)
+        /// </summary>
+        /// <returns>
+        /// True if no axes are required.
+        /// </returns>
+        protected internal override bool AreAxesRequired()
+        {
+            return false;
+        }
+
+        /// <summary>
+        /// Ensures that the axes of the series is defined.
+        /// </summary>
+        protected internal override void EnsureAxes()
+        {
+        }
+
+        /// <summary>
+        /// Check if the data series is using the specified axis.
+        /// </summary>
+        /// <param name="axis">
+        /// An axis.
+        /// </param>
+        /// <returns>
+        /// True if the axis is in use.
+        /// </returns>
+        protected internal override bool IsUsing(Axis axis)
+        {
+            return false;
+        }
+
+        /// <summary>
+        /// The set default values.
+        /// </summary>
+        /// <param name="model">
+        /// The model.
+        /// </param>
+        protected internal override void SetDefaultValues(PlotModel model)
+        {
+            foreach (var slice in this.Slices)
+            {
+                if (slice.Fill == null)
+                {
+                    slice.DefaultFillColor = model.GetDefaultColor();
+                }
+            }
+        }
+
+        /// <summary>
+        /// The update axis max min.
+        /// </summary>
+        protected internal override void UpdateAxisMaxMin()
+        {
+        }
+
+        /// <summary>
+        /// Updates the data.
+        /// </summary>
+        protected internal override void UpdateData()
+        {
+            if (this.ItemsSource == null)
+            {
+                return;
+            }
+
+            this.slices.Clear();
+
+            var filler = new ListFiller<PieSlice>();
+            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);
+        }
+
+        /// <summary>
+        /// The update max min.
+        /// </summary>
+        protected internal override void UpdateMaxMin()
+        {
+        }
+
+    }
+}
\ No newline at end of file
diff --git a/oxyplot/OxyPlot/Series/PieSlice.cs b/oxyplot/OxyPlot/Series/PieSlice.cs
new file mode 100644
index 0000000..7520f60
--- /dev/null
+++ b/oxyplot/OxyPlot/Series/PieSlice.cs
@@ -0,0 +1,99 @@
+// 
--------------------------------------------------------------------------------------------------------------------
+// <copyright file="PieSlice.cs" company="OxyPlot">
+//   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.
+// </copyright>
+// <summary>
+//   Represent a slice of a PieSeries.
+// </summary>
+// 
--------------------------------------------------------------------------------------------------------------------
+namespace OxyPlot.Series
+{
+    /// <summary>
+    /// Represent a slice of a <see cref="PieSeries"/>.
+    /// </summary>
+    public class PieSlice
+    {
+        /// <summary>
+        /// Initializes a new instance of the <see cref = "PieSlice" /> class.
+        /// </summary>
+        public PieSlice()
+        {
+        }
+
+        /// <summary>
+        /// Initializes a new instance of the <see cref="PieSlice"/> class.
+        /// </summary>
+        /// <param name="label">
+        /// The label.
+        /// </param>
+        /// <param name="value">
+        /// The value.
+        /// </param>
+        /// <param name="fill">
+        /// The fill.
+        /// </param>
+        public PieSlice(string label, double value, OxyColor fill = null)
+        {
+            this.Label = label;
+            this.Value = value;
+            this.Fill = fill;
+        }
+
+        /// <summary>
+        /// Gets or sets Fill.
+        /// </summary>
+        public OxyColor Fill { get; set; }
+
+        /// <summary>
+        /// Gets the actual fill color.
+        /// </summary>
+        /// <value>The actual color.</value>
+        public OxyColor ActualFillColor
+        {
+            get { return this.Fill ?? this.DefaultFillColor; }
+        }
+
+        /// <summary>
+        /// Gets or sets a value indicating whether IsExploded.
+        /// </summary>
+        public bool IsExploded { get; set; }
+
+        /// <summary>
+        /// Gets or sets Label.
+        /// </summary>
+        public string Label { get; set; }
+
+        /// <summary>
+        /// Gets or sets Value.
+        /// </summary>
+        public double Value { get; set; }
+
+        /// <summary>
+        /// Gets or sets the default fill color.
+        /// </summary>
+        /// <value>The default fill color.</value>
+        internal OxyColor DefaultFillColor { get; set; }
+
+    }
+}
\ No newline at end of file
diff --git a/oxyplot/OxyPlot/Series/PlotSeriesBase.cs b/oxyplot/OxyPlot/Series/PlotSeriesBase.cs
new file mode 100644
index 0000000..fc1ca95
--- /dev/null
+++ b/oxyplot/OxyPlot/Series/PlotSeriesBase.cs
@@ -0,0 +1,302 @@
+// 
--------------------------------------------------------------------------------------------------------------------
+// <copyright file="PlotSeriesBase.cs" company="OxyPlot">
+//   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.
+// </copyright>
+// <summary>
+//   Abstract base class for Series that contains an X-axis and Y-axis
+// </summary>
+// 
--------------------------------------------------------------------------------------------------------------------
+namespace OxyPlot
+{
+    using System;
+    using System.Collections;
+    using System.Collections.Generic;
+    using System.Collections.ObjectModel;
+    using System.Linq;
+
+    /// <summary>
+    /// Abstract base class for Series that contains an X-axis and Y-axis
+    /// </summary>
+    public abstract class PlotSeriesBase : ItemsSeries
+    {
+        /// <summary>
+        /// Gets or sets the maximum x-coordinate of the dataset.
+        /// </summary>
+        /// <value>The maximum x-coordinate.</value>
+        public double MaxX { get; protected set; }
+
+        /// <summary>
+        /// Gets or sets the maximum y-coordinate of the dataset.
+        /// </summary>
+        /// <value>The maximum y-coordinate.</value>
+        public double MaxY { get; protected set; }
+
+        /// <summary>
+        /// Gets or sets the minimum x-coordinate of the dataset.
+        /// </summary>
+        /// <value>The minimum x-coordinate.</value>
+        public double MinX { get; protected set; }
+
+        /// <summary>
+        /// Gets or sets the minimum y-coordinate of the dataset.
+        /// </summary>
+        /// <value>The minimum y-coordinate.</value>
+        public double MinY { get; protected set; }
+
+        /// <summary>
+        /// Gets or sets the x-axis.
+        /// </summary>
+        /// <value>The x-axis.</value>
+        public IAxis XAxis { get; set; }
+
+        /// <summary>
+        /// Gets or sets the x-axis key.
+        /// </summary>
+        /// <value>The x-axis key.</value>
+        public string XAxisKey { get; set; }
+
+        /// <summary>
+        /// Gets or sets the y-axis.
+        /// </summary>
+        /// <value>The y-axis.</value>
+        public IAxis YAxis { get; set; }
+
+        /// <summary>
+        /// Gets or sets the y-axis key.
+        /// </summary>
+        /// <value>The y-axis key.</value>
+        public string YAxisKey { get; set; }
+
+        /// <summary>
+        /// Check if this data series requires X/Y axes.
+        /// (e.g. Pie series do not require axes)
+        /// </summary>
+        /// <returns></returns>
+        public override bool AreAxesRequired()
+        {
+            return true;
+        }
+
+        public override void EnsureAxes(Collection<IAxis> 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;
+            }
+        }
+
+        /// <summary>
+        /// Gets the rectangle the series uses on the screen (screen coordinates).
+        /// </summary>
+        /// <returns></returns>
+        public OxyRect GetScreenRectangle()
+        {
+            return this.GetClippingRect();
+        }
+
+        public override bool IsUsing(IAxis axis)
+        {
+            return this.XAxis == axis || this.YAxis == axis;
+        }
+
+        /// <summary>
+        /// Renders the Series on the specified rendering context.
+        /// </summary>
+        /// <param name = "rc">The rendering context.</param>
+        /// <param name = "model">The model.</param>
+        public override void Render(IRenderContext rc, PlotModel model)
+        {
+        }
+
+        /// <summary>
+        /// Renders the legend symbol on the specified rendering context.
+        /// </summary>
+        /// <param name = "rc">The rendering context.</param>
+        /// <param name = "legendBox">The legend rectangle.</param>
+        public override void RenderLegend(IRenderContext rc, OxyRect legendBox)
+        {
+        }
+
+        public override void SetDefaultValues(PlotModel model)
+        {
+        }
+
+        public override void UpdateData()
+        {
+        }
+
+        /// <summary>
+        /// Updates the max/minimum values.
+        /// </summary>
+        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);
+        }
+
+        /// <summary>
+        /// Gets the point on the curve that is nearest the specified point.
+        /// </summary>
+        /// <param name = "point">The point.</param>
+        /// <param name = "dpn">The nearest point (data coordinates).</param>
+        /// <param name = "spn">The nearest point (screen coordinates).</param>
+        /// <returns></returns>
+        protected bool GetNearestInterpolatedPointInternal(
+            IList<IDataPoint> 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<IDataPoint> 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;
+        }
+
+        /// <summary>
+        /// 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
+        /// </summary>
+        /// <param name="value">The value.</param>
+        /// <returns></returns>
+        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 --git a/oxyplot/OxyPlot/Series/ScatterPoint.cs b/oxyplot/OxyPlot/Series/ScatterPoint.cs
new file mode 100644
index 0000000..c976ee9
--- /dev/null
+++ b/oxyplot/OxyPlot/Series/ScatterPoint.cs
@@ -0,0 +1,232 @@
+// 
--------------------------------------------------------------------------------------------------------------------
+// <copyright file="ScatterPoint.cs" company="OxyPlot">
+//   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.
+// </copyright>
+// <summary>
+//   Represents a point in a ScatterSeries.
+// </summary>
+// 
--------------------------------------------------------------------------------------------------------------------
+namespace OxyPlot.Series
+{
+    using System.Diagnostics.CodeAnalysis;
+
+    /// <summary>
+    /// Represents a point in a <see cref="ScatterSeries"/>.
+    /// </summary>
+    public class ScatterPoint : IDataPoint
+    {
+        // ReSharper disable InconsistentNaming
+
+        /// <summary>
+        /// The size.
+        /// </summary>
+        [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;
+
+        /// <summary>
+        /// The tag.
+        /// </summary>
+        [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;
+
+        /// <summary>
+        /// The value.
+        /// </summary>
+        [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;
+
+        /// <summary>
+        /// The x.
+        /// </summary>
+        [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;
+
+        /// <summary>
+        /// The y.
+        /// </summary>
+        [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
+        /// <summary>
+        /// Initializes a new instance of the <see cref="ScatterPoint"/> class.
+        /// </summary>
+        public ScatterPoint()
+        {
+            this.Size = double.NaN;
+            this.Value = double.NaN;
+        }
+
+        /// <summary>
+        /// Initializes a new instance of the <see cref="ScatterPoint"/> class.
+        /// </summary>
+        /// <param name="x">
+        /// The x.
+        /// </param>
+        /// <param name="y">
+        /// The y.
+        /// </param>
+        /// <param name="size">
+        /// The size.
+        /// </param>
+        /// <param name="value">
+        /// The value.
+        /// </param>
+        /// <param name="tag">
+        /// The tag.
+        /// </param>
+        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;
+        }
+
+        /// <summary>
+        /// Gets or sets the size.
+        /// </summary>
+        /// <value>The size.</value>
+        public double Size
+        {
+            get
+            {
+                return this.size;
+            }
+
+            set
+            {
+                this.size = value;
+            }
+        }
+
+        /// <summary>
+        /// Gets or sets the tag.
+        /// </summary>
+        /// <value>The tag.</value>
+        public object Tag
+        {
+            get
+            {
+                return this.tag;
+            }
+
+            set
+            {
+                this.tag = value;
+            }
+        }
+
+        /// <summary>
+        /// Gets or sets the value.
+        /// </summary>
+        /// <value>The value.</value>
+        public double Value
+        {
+            get
+            {
+                return this.value;
+            }
+
+            set
+            {
+                this.value = value;
+            }
+        }
+
+        /// <summary>
+        /// Gets or sets the X.
+        /// </summary>
+        /// <value>The X.</value>
+        public double X
+        {
+            get
+            {
+                return this.x;
+            }
+
+            set
+            {
+                this.x = value;
+            }
+        }
+
+        /// <summary>
+        /// Gets or sets the Y.
+        /// </summary>
+        /// <value>The Y.</value>
+        public double Y
+        {
+            get
+            {
+                return this.y;
+            }
+
+            set
+            {
+                this.y = value;
+            }
+        }
+
+        /// <summary>
+        /// Returns C# code that generates this instance.
+        /// </summary>
+        /// <returns>
+        /// C# code.
+        /// </returns>
+        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);
+        }
+
+        /// <summary>
+        /// Returns a <see cref="System.String"/> that represents this instance.
+        /// </summary>
+        /// <returns>
+        /// A <see cref="System.String"/> that represents this instance.
+        /// </returns>
+        public override string ToString()
+        {
+            return this.x + " " + this.y;
+        }
+
+    }
+}
\ No newline at end of file
diff --git a/oxyplot/OxyPlot/Series/ScatterSeries.cs b/oxyplot/OxyPlot/Series/ScatterSeries.cs
new file mode 100644
index 0000000..48d18ff
--- /dev/null
+++ b/oxyplot/OxyPlot/Series/ScatterSeries.cs
@@ -0,0 +1,621 @@
+// 
--------------------------------------------------------------------------------------------------------------------
+// <copyright file="ScatterSeries.cs" company="OxyPlot">
+//   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.
+// </copyright>
+// <summary>
+//   Represents a series for scatter plots.
+// </summary>
+// 
--------------------------------------------------------------------------------------------------------------------
+
+namespace OxyPlot.Series
+{
+    using System;
+    using System.Collections;
+    using System.Collections.Generic;
+
+    using OxyPlot.Axes;
+
+    /// <summary>
+    /// Represents a series for scatter plots.
+    /// </summary>
+    /// <remarks>
+    /// See http://en.wikipedia.org/wiki/Scatter_plot
+    /// </remarks>
+    public class ScatterSeries : DataPointSeries
+    {
+        /// <summary>
+        /// The default fill color.
+        /// </summary>
+        private OxyColor defaultMarkerFillColor;
+
+        /// <summary>
+        /// Initializes a new instance of the <see cref="ScatterSeries"/> class.
+        /// </summary>
+        /// <param name="title">
+        /// The title.
+        /// </param>
+        /// <param name="markerFill">
+        /// The marker fill color.
+        /// </param>
+        /// <param name="markerSize">
+        /// Size of the markers (If ScatterPoint.Size is set, this value will be overridden).
+        /// </param>
+        public ScatterSeries(string title, OxyColor markerFill = null, double markerSize = 5)
+            : this()
+        {
+            this.MarkerFill = markerFill;
+            this.MarkerSize = markerSize;
+            this.Title = title;
+        }
+
+        /// <summary>
+        /// Initializes a new instance of the <see cref="ScatterSeries"/> class.
+        /// </summary>
+        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;
+        }
+
+        /// <summary>
+        /// 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.
+        /// </summary>
+        public int BinSize { get; set; }
+
+        /// <summary>
+        /// Gets or sets the color map.
+        /// </summary>
+        /// <value> The color map. </value>
+        /// <remarks>
+        /// This is used to map scatter point values to colors.
+        /// </remarks>
+        public ColorAxis ColorAxis { get; set; }
+
+        /// <summary>
+        /// Gets or sets the color axis key.
+        /// </summary>
+        /// <value> The color axis key. </value>
+        public string ColorAxisKey { get; set; }
+
+        /// <summary>
+        /// Gets or sets the data field for the size.
+        /// </summary>
+        /// <value> The size data field. </value>
+        public string DataFieldSize { get; set; }
+
+        /// <summary>
+        /// Gets or sets the tag data field.
+        /// </summary>
+        /// <value> The tag data field. </value>
+        public string DataFieldTag { get; set; }
+
+        /// <summary>
+        /// Gets or sets the value data field.
+        /// </summary>
+        /// <value> The value data field. </value>
+        public string DataFieldValue { get; set; }
+
+        /// <summary>
+        /// Gets or sets the marker fill color. If null, this color will be automatically set.
+        /// </summary>
+        /// <value> The marker fill color. </value>
+        public OxyColor MarkerFill { get; set; }
+
+        /// <summary>
+        /// Gets the actual fill color.
+        /// </summary>
+        /// <value>The actual color.</value>
+        public OxyColor ActualMarkerFillColor
+        {
+            get { return this.MarkerFill ?? this.defaultMarkerFillColor; }
+        }
+
+        /// <summary>
+        /// Gets or sets the marker outline polygon. Set MarkerType to Custom to use this.
+        /// </summary>
+        /// <value> The marker outline. </value>
+        public ScreenPoint[] MarkerOutline { get; set; }
+
+        /// <summary>
+        /// Gets or sets the size of the marker (same size for all items).
+        /// </summary>
+        /// <value> The size of the markers. </value>
+        public double MarkerSize { get; set; }
+
+        /// <summary>
+        /// Gets or sets the marker stroke.
+        /// </summary>
+        /// <value> The marker stroke. </value>
+        public OxyColor MarkerStroke { get; set; }
+
+        /// <summary>
+        /// Gets or sets the marker stroke thickness.
+        /// </summary>
+        /// <value> The marker stroke thickness. </value>
+        public double MarkerStrokeThickness { get; set; }
+
+        /// <summary>
+        /// Gets or sets the type of the marker.
+        /// </summary>
+        /// <value> The type of the marker. </value>
+        /// <remarks>
+        /// If MarkerType.Custom is used, the MarkerOutline property must be specified.
+        /// </remarks>
+        public MarkerType MarkerType { get; set; }
+
+        /// <summary>
+        /// Gets the max value of the points.
+        /// </summary>
+        public double MaxValue { get; private set; }
+
+        /// <summary>
+        /// Gets the min value of the points.
+        /// </summary>
+        public double MinValue { get; private set; }
+
+        /// <summary>
+        /// Gets the nearest point.
+        /// </summary>
+        /// <param name="point">
+        /// The point.
+        /// </param>
+        /// <param name="interpolate">
+        /// interpolate if set to <c>true</c> .
+        /// </param>
+        /// <returns>
+        /// A TrackerHitResult for the current hit.
+        /// </returns>
+        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;
+        }
+
+        /// <summary>
+        /// Determines whether the specified point is valid.
+        /// </summary>
+        /// <param name="pt">
+        /// The point.
+        /// </param>
+        /// <param name="xaxis">
+        /// The x axis.
+        /// </param>
+        /// <param name="yaxis">
+        /// The y axis.
+        /// </param>
+        /// <returns>
+        /// <c>true</c> if the point is valid; otherwise, <c>false</c> .
+        /// </returns>
+        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));
+        }
+
+        /// <summary>
+        /// Renders the series on the specified rendering context.
+        /// </summary>
+        /// <param name="rc">
+        /// The rendering context.
+        /// </param>
+        /// <param name="model">
+        /// The owner plot model.
+        /// </param>
+        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<int, IList<ScreenPoint>>();
+            var groupSizes = new Dictionary<int, IList<double>>();
+
+            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<ScreenPoint>());
+                            groupSizes.Add(group, new List<double>());
+                        }
+
+                        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);
+            }
+        }
+
+        /// <summary>
+        /// Renders the legend symbol for the line series on the specified rendering context.
+        /// </summary>
+        /// <param name="rc">
+        /// The rendering context.
+        /// </param>
+        /// <param name="legendBox">
+        /// The bounding rectangle of the legend box.
+        /// </param>
+        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);
+        }
+
+        /// <summary>
+        /// Ensures that the axes of the series is defined.
+        /// </summary>
+        protected internal override void EnsureAxes()
+        {
+            base.EnsureAxes();
+
+            this.ColorAxis = PlotModel.GetAxisOrDefault(this.ColorAxisKey, PlotModel.DefaultColorAxis) as 
ColorAxis;
+        }
+
+        /// <summary>
+        /// Sets the default values.
+        /// </summary>
+        /// <param name="model">
+        /// The model.
+        /// </param>
+        protected internal override void SetDefaultValues(PlotModel model)
+        {
+            if (this.MarkerFill == null)
+            {
+                this.defaultMarkerFillColor = model.GetDefaultColor();
+            }
+        }
+
+        /// <summary>
+        /// The update data.
+        /// </summary>
+        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<IDataPoint>();
+
+            // Using reflection to add points
+            var filler = new ListFiller<ScatterPoint>();
+            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;
+        }
+
+        /// <summary>
+        /// Updates the max/min from the data points.
+        /// </summary>
+        protected internal override void UpdateMaxMin()
+        {
+            base.UpdateMaxMin();
+            this.InternalUpdateMaxMinValue(this.Points);
+        }
+
+        /// <summary>
+        /// Adds scatter points specified by a items source and data fields.
+        /// </summary>
+        /// <param name="dest">
+        /// The destination collection.
+        /// </param>
+        /// <param name="itemsSource">
+        /// The items source.
+        /// </param>
+        /// <param name="dataFieldX">
+        /// The data field x.
+        /// </param>
+        /// <param name="dataFieldY">
+        /// The data field y.
+        /// </param>
+        /// <param name="dataFieldSize">
+        /// The data field size.
+        /// </param>
+        /// <param name="dataFieldValue">
+        /// The data field value.
+        /// </param>
+        /// <param name="dataFieldTag">
+        /// The data field tag.
+        /// </param>
+        protected void AddScatterPoints(
+            IList<ScatterPoint> dest,
+            IEnumerable itemsSource,
+            string dataFieldX,
+            string dataFieldY,
+            string dataFieldSize,
+            string dataFieldValue,
+            string dataFieldTag)
+        {
+            var filler = new ListFiller<ScatterPoint>();
+            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);
+        }
+
+        /// <summary>
+        /// Updates the Max/Min limits from the values in the specified point list.
+        /// </summary>
+        /// <param name="pts">
+        /// The points.
+        /// </param>
+        protected void InternalUpdateMaxMinValue(IList<IDataPoint> 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 --git a/oxyplot/OxyPlot/Series/Series.cs b/oxyplot/OxyPlot/Series/Series.cs
new file mode 100644
index 0000000..bf441c9
--- /dev/null
+++ b/oxyplot/OxyPlot/Series/Series.cs
@@ -0,0 +1,204 @@
+// 
--------------------------------------------------------------------------------------------------------------------
+// <copyright file="Series.cs" company="OxyPlot">
+//   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.
+// </copyright>
+// <summary>
+//   Abstract base class for all series.
+// </summary>
+// 
--------------------------------------------------------------------------------------------------------------------
+namespace OxyPlot.Series
+{
+    using System.Globalization;
+
+    using OxyPlot.Axes;
+
+    /// <summary>
+    /// Provides an abstract base class for plot series.
+    /// </summary>
+    /// <remarks>
+    /// This class contains internal methods that should be called only from the PlotModel.
+    /// </remarks>
+    public abstract class Series : UIPlotElement, ITrackableSeries
+    {
+        /// <summary>
+        /// Initializes a new instance of the <see cref="Series" /> class.
+        /// </summary>
+        protected Series()
+        {
+            this.IsVisible = true;
+        }
+
+        /// <summary>
+        /// Gets the actual culture.
+        /// </summary>
+        /// <remarks>
+        /// The culture is defined in the parent PlotModel.
+        /// </remarks>
+        public CultureInfo ActualCulture
+        {
+            get
+            {
+                return this.PlotModel != null ? this.PlotModel.ActualCulture : CultureInfo.CurrentCulture;
+            }
+        }
+
+        /// <summary>
+        /// Gets or sets the background color of the series. The background area is defined by the x and y 
axes.
+        /// </summary>
+        /// <value> The background color. </value>
+        public OxyColor Background { get; set; }
+
+        /// <summary>
+        /// Gets or sets a value indicating whether this series is visible.
+        /// </summary>
+        public bool IsVisible { get; set; }
+
+        /// <summary>
+        /// Gets or sets the title of the Series.
+        /// </summary>
+        /// <value> The title. </value>
+        public string Title { get; set; }
+
+        /// <summary>
+        /// Gets or sets a format string used for the tracker.
+        /// </summary>
+        public string TrackerFormatString { get; set; }
+
+        /// <summary>
+        /// Gets or sets the key for the tracker to use on this series.
+        /// </summary>
+        public string TrackerKey { get; set; }
+
+        /// <summary>
+        /// Gets the point on the series that is nearest the specified point.
+        /// </summary>
+        /// <param name="point">The point.</param>
+        /// <param name="interpolate">Interpolate the series if this flag is set to <c>true</c>.</param>
+        /// <returns>
+        /// A TrackerHitResult for the current hit.
+        /// </returns>
+        public abstract TrackerHitResult GetNearestPoint(ScreenPoint point, bool interpolate);
+
+        /// <summary>
+        /// Renders the series on the specified render context.
+        /// </summary>
+        /// <param name="rc">
+        /// The rendering context.
+        /// </param>
+        /// <param name="model">
+        /// The model.
+        /// </param>
+        public abstract void Render(IRenderContext rc, PlotModel model);
+
+        /// <summary>
+        /// Renders the legend symbol on the specified render context.
+        /// </summary>
+        /// <param name="rc">
+        /// The rendering context.
+        /// </param>
+        /// <param name="legendBox">
+        /// The legend rectangle.
+        /// </param>
+        public abstract void RenderLegend(IRenderContext rc, OxyRect legendBox);
+
+        /// <summary>
+        /// Tests if the plot element is hit by the specified point.
+        /// </summary>
+        /// <param name="point">The point.</param>
+        /// <param name="tolerance">The tolerance.</param>
+        /// <returns>
+        /// A hit test result.
+        /// </returns>
+        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;
+        }
+
+        /// <summary>
+        /// Check if this data series requires X/Y axes. (e.g. Pie series do not require axes)
+        /// </summary>
+        /// <returns>
+        /// True if no axes are required.
+        /// </returns>
+        protected internal abstract bool AreAxesRequired();
+
+        /// <summary>
+        /// Ensures that the axes of the series is defined.
+        /// </summary>
+        protected internal abstract void EnsureAxes();
+
+        /// <summary>
+        /// Check if the data series is using the specified axis.
+        /// </summary>
+        /// <param name="axis">
+        /// An axis which should be checked if used
+        /// </param>
+        /// <returns>
+        /// True if the axis is in use.
+        /// </returns>
+        protected internal abstract bool IsUsing(Axis axis);
+
+        /// <summary>
+        /// Sets default values (colors, line style etc) from the plot model.
+        /// </summary>
+        /// <param name="model">
+        /// A plot model.
+        /// </param>
+        protected internal abstract void SetDefaultValues(PlotModel model);
+
+        /// <summary>
+        /// Updates the axis maximum and minimum values.
+        /// </summary>
+        protected internal abstract void UpdateAxisMaxMin();
+
+        /// <summary>
+        /// Updates the data.
+        /// </summary>
+        protected internal abstract void UpdateData();
+
+        /// <summary>
+        /// Updates the valid data.
+        /// </summary>
+        protected internal abstract void UpdateValidData();
+
+        /// <summary>
+        /// Updates the maximum and minimum of the series.
+        /// </summary>
+        protected internal abstract void UpdateMaxMin();
+
+    }
+}
\ No newline at end of file
diff --git a/oxyplot/OxyPlot/Series/StairStepSeries.cs b/oxyplot/OxyPlot/Series/StairStepSeries.cs
new file mode 100644
index 0000000..610a4d1
--- /dev/null
+++ b/oxyplot/OxyPlot/Series/StairStepSeries.cs
@@ -0,0 +1,291 @@
+// 
--------------------------------------------------------------------------------------------------------------------
+// <copyright file="StairStepSeries.cs" company="OxyPlot">
+//   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.
+// </copyright>
+// <summary>
+//   Represents a series for stair step graphs.
+// </summary>
+// 
--------------------------------------------------------------------------------------------------------------------
+namespace OxyPlot.Series
+{
+    using System;
+    using System.Collections.Generic;
+
+    /// <summary>
+    /// Represents a series for stair step graphs.
+    /// </summary>
+    public class StairStepSeries : LineSeries
+    {
+        /// <summary>
+        /// Initializes a new instance of the <see cref = "StairStepSeries" /> class.
+        /// </summary>
+        public StairStepSeries()
+        {
+            this.VerticalStrokeThickness = double.NaN;
+            this.VerticalLineStyle = this.LineStyle;
+        }
+
+        /// <summary>
+        /// Initializes a new instance of the <see cref="StairStepSeries"/> class.
+        /// </summary>
+        /// <param name="title">
+        /// The title.
+        /// </param>
+        public StairStepSeries(string title)
+            : base(title)
+        {
+            this.VerticalStrokeThickness = double.NaN;
+            this.VerticalLineStyle = this.LineStyle;
+            this.Title = title;
+        }
+
+        /// <summary>
+        /// Initializes a new instance of the <see cref="StairStepSeries"/> class.
+        /// </summary>
+        /// <param name="color">
+        /// The color.
+        /// </param>
+        /// <param name="strokeThickness">
+        /// The stroke thickness.
+        /// </param>
+        /// <param name="title">
+        /// The title.
+        /// </param>
+        public StairStepSeries(OxyColor color, double strokeThickness = 1, string title = null)
+            : base(color, strokeThickness, title)
+        {
+            this.VerticalStrokeThickness = double.NaN;
+            this.VerticalLineStyle = this.LineStyle;
+        }
+
+        /// <summary>
+        /// Gets or sets the stroke thickness of the vertical line segments.
+        /// </summary>
+        /// <remarks>
+        /// 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.
+        /// </remarks>
+        /// <value>The vertical stroke thickness.</value>
+        public double VerticalStrokeThickness { get; set; }
+
+        /// <summary>
+        /// Gets or sets the line style of the vertical line segments.
+        /// </summary>
+        /// <value>The vertical line style.</value>
+        public LineStyle VerticalLineStyle { get; set; }
+
+        /// <summary>
+        /// Gets the nearest point.
+        /// </summary>
+        /// <param name="point">
+        /// The point.
+        /// </param>
+        /// <param name="interpolate">
+        /// interpolate if set to <c>true</c> .
+        /// </param>
+        /// <returns>
+        /// A TrackerHitResult for the current hit.
+        /// </returns>
+        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;
+        }
+
+        /// <summary>
+        /// Renders the LineSeries on the specified rendering context.
+        /// </summary>
+        /// <param name="rc">
+        /// The rendering context.
+        /// </param>
+        /// <param name="model">
+        /// The owner plot model.
+        /// </param>
+        public override void Render(IRenderContext rc, PlotModel model)
+        {
+            if (this.Points.Count == 0)
+            {
+                return;
+            }
+
+            this.VerifyAxes();
+
+            var clippingRect = this.GetClippingRect();
+
+            Action<IList<ScreenPoint>, IList<ScreenPoint>> 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<ScreenPoint>();
+                            var vlpts = new List<ScreenPoint>();
+                            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<ScreenPoint>();
+            var markerPoints = new List<ScreenPoint>();
+            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 --git a/oxyplot/OxyPlot/Series/StemSeries.cs b/oxyplot/OxyPlot/Series/StemSeries.cs
new file mode 100644
index 0000000..c7b3230
--- /dev/null
+++ b/oxyplot/OxyPlot/Series/StemSeries.cs
@@ -0,0 +1,212 @@
+// 
--------------------------------------------------------------------------------------------------------------------
+// <copyright file="StemSeries.cs" company="OxyPlot">
+//   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.
+// </copyright>
+// <summary>
+//   Represents a series that plots discrete data in a stem plot.
+// </summary>
+// 
--------------------------------------------------------------------------------------------------------------------
+namespace OxyPlot.Series
+{
+    using System.Collections.Generic;
+
+    /// <summary>
+    /// Represents a series that plots discrete data in a stem plot.
+    /// </summary>
+    /// <remarks>
+    /// See <a href="http://en.wikipedia.org/wiki/Stemplot";>Stem plot</a> and
+    /// <a href="http://www.mathworks.com/help/techdoc/ref/stem.html";>stem</a>.
+    /// </remarks>
+    public class StemSeries : LineSeries
+    {
+        /// <summary>
+        /// Initializes a new instance of the <see cref = "StemSeries" /> class.
+        /// </summary>
+        public StemSeries()
+        {
+            this.Base = 0;
+        }
+
+        /// <summary>
+        /// Initializes a new instance of the <see cref="StemSeries"/> class.
+        /// </summary>
+        /// <param name="title">
+        /// The title.
+        /// </param>
+        public StemSeries(string title)
+            : base(title)
+        {
+            this.Title = title;
+        }
+
+        /// <summary>
+        /// Initializes a new instance of the <see cref="StemSeries"/> class.
+        /// </summary>
+        /// <param name="color">
+        /// The color of the line stroke.
+        /// </param>
+        /// <param name="strokeThickness">
+        /// The stroke thickness (optional).
+        /// </param>
+        /// <param name="title">
+        /// The title (optional).
+        /// </param>
+        public StemSeries(OxyColor color, double strokeThickness = 1, string title = null)
+            : base(color, strokeThickness, title)
+        {
+        }
+
+        /// <summary>
+        /// Gets or sets Base.
+        /// </summary>
+        public double Base { get; set; }
+
+        /// <summary>
+        /// Gets the point on the series that is nearest the specified point.
+        /// </summary>
+        /// <param name="point">
+        /// The point.
+        /// </param>
+        /// <param name="interpolate">
+        /// Interpolate the series if this flag is set to <c>true</c>.
+        /// </param>
+        /// <returns>
+        /// A TrackerHitResult for the current hit.
+        /// </returns>
+        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;
+        }
+
+        /// <summary>
+        /// Renders the LineSeries on the specified rendering context.
+        /// </summary>
+        /// <param name="rc">
+        /// The rendering context.
+        /// </param>
+        /// <param name="model">
+        /// The owner plot model.
+        /// </param>
+        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<ScreenPoint>();
+            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 --git a/oxyplot/OxyPlot/Series/TwoColorLineSeries.cs b/oxyplot/OxyPlot/Series/TwoColorLineSeries.cs
new file mode 100644
index 0000000..dc9ad47
--- /dev/null
+++ b/oxyplot/OxyPlot/Series/TwoColorLineSeries.cs
@@ -0,0 +1,163 @@
+// 
--------------------------------------------------------------------------------------------------------------------
+// <copyright file="TwoColorLineSeries.cs" company="OxyPlot">
+//   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.
+// </copyright>
+// <summary>
+//   Represents a two-color line series.
+// </summary>
+// 
--------------------------------------------------------------------------------------------------------------------
+namespace OxyPlot.Series
+{
+    using System.Collections.Generic;
+
+    /// <summary>
+    /// Represents a two-color line series.
+    /// </summary>
+    public class TwoColorLineSeries : LineSeries
+    {
+        /// <summary>
+        /// The default second color.
+        /// </summary>
+        private OxyColor defaultColor2;
+
+        /// <summary>
+        /// Initializes a new instance of the <see cref = "TwoColorLineSeries" /> class.
+        /// </summary>
+        public TwoColorLineSeries()
+        {
+            this.Limit = 0.0;
+            this.Color2 = OxyColors.Blue;
+            this.LineStyle2 = LineStyle.Solid;
+        }
+
+        /// <summary>
+        /// Gets or sets the color for the part of the line that is below the limit.
+        /// </summary>
+        public OxyColor Color2 { get; set; }
+
+        /// <summary>
+        /// Gets the actual second color.
+        /// </summary>
+        /// <value>The actual color.</value>
+        public OxyColor ActualColor2
+        {
+            get { return this.Color2 ?? this.defaultColor2; }
+        }
+
+        /// <summary>
+        /// Gets or sets the limit.
+        /// </summary>
+        /// <remarks>
+        /// 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.
+        /// </remarks>
+        public double Limit { get; set; }
+
+        /// <summary>
+        /// Gets or sets the line style for the part of the line that is below the limit.
+        /// </summary>
+        /// <value>The line style.</value>
+        public LineStyle LineStyle2 { get; set; }
+
+        /// <summary>
+        /// Gets the actual line style for the part of the line that is below the limit.
+        /// </summary>
+        /// <value>The line style.</value>
+        public LineStyle ActualLineStyle2
+        {
+            get
+            {
+                return this.LineStyle2 != LineStyle.Undefined ? this.LineStyle2 : LineStyle.Solid;
+            }
+        }
+
+        /// <summary>
+        /// The set default values.
+        /// </summary>
+        /// <param name="model">
+        /// The model.
+        /// </param>
+        protected internal override void SetDefaultValues(PlotModel model)
+        {
+            if (this.Color2 == null)
+            {
+                this.LineStyle2 = model.GetDefaultLineStyle();
+                this.defaultColor2 = model.GetDefaultColor();
+            }
+        }
+
+        /// <summary>
+        /// Renders the smoothed line.
+        /// </summary>
+        /// <param name="rc">
+        /// The render context.
+        /// </param>
+        /// <param name="clippingRect">
+        /// The clipping rect.
+        /// </param>
+        /// <param name="pointsToRender">
+        /// The points.
+        /// </param>
+        protected override void RenderSmoothedLine(IRenderContext rc, OxyRect clippingRect, 
IList<ScreenPoint> 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 --git a/oxyplot/OxyPlot/Series/XYAxisSeries.cs b/oxyplot/OxyPlot/Series/XYAxisSeries.cs
new file mode 100644
index 0000000..e0fe92a
--- /dev/null
+++ b/oxyplot/OxyPlot/Series/XYAxisSeries.cs
@@ -0,0 +1,424 @@
+// 
--------------------------------------------------------------------------------------------------------------------
+// <copyright file="XYAxisSeries.cs" company="OxyPlot">
+//   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.
+// </copyright>
+// <summary>
+//   Abstract base class for series that contains an X-axis and Y-axis.
+// </summary>
+// 
--------------------------------------------------------------------------------------------------------------------
+
+namespace OxyPlot.Series
+{
+    using System;
+    using System.Collections.Generic;
+
+    using OxyPlot.Axes;
+
+    /// <summary>
+    /// Provides an abstract base class for series that are related to an X-axis and a Y-axis.
+    /// </summary>
+    public abstract class XYAxisSeries : ItemsSeries
+    {
+        /// <summary>
+        /// Gets or sets the maximum x-coordinate of the dataset.
+        /// </summary>
+        /// <value> The maximum x-coordinate. </value>
+        public double MaxX { get; protected set; }
+
+        /// <summary>
+        /// Gets or sets the maximum y-coordinate of the dataset.
+        /// </summary>
+        /// <value> The maximum y-coordinate. </value>
+        public double MaxY { get; protected set; }
+
+        /// <summary>
+        /// Gets or sets the minimum x-coordinate of the dataset.
+        /// </summary>
+        /// <value> The minimum x-coordinate. </value>
+        public double MinX { get; protected set; }
+
+        /// <summary>
+        /// Gets or sets the minimum y-coordinate of the dataset.
+        /// </summary>
+        /// <value> The minimum y-coordinate. </value>
+        public double MinY { get; protected set; }
+
+        /// <summary>
+        /// Gets the x-axis.
+        /// </summary>
+        /// <value> The x-axis. </value>
+        public Axis XAxis { get; private set; }
+
+        /// <summary>
+        /// Gets or sets the x-axis key.
+        /// </summary>
+        /// <value> The x-axis key. </value>
+        public string XAxisKey { get; set; }
+
+        /// <summary>
+        /// Gets the y-axis.
+        /// </summary>
+        /// <value> The y-axis. </value>
+        public Axis YAxis { get; private set; }
+
+        /// <summary>
+        /// Gets or sets the y-axis key.
+        /// </summary>
+        /// <value> The y-axis key. </value>
+        public string YAxisKey { get; set; }
+
+        /// <summary>
+        /// Gets the rectangle the series uses on the screen (screen coordinates).
+        /// </summary>
+        /// <returns>
+        /// The rectangle.
+        /// </returns>
+        public OxyRect GetScreenRectangle()
+        {
+            return this.GetClippingRect();
+        }
+
+        /// <summary>
+        /// Renders the legend symbol on the specified rendering context.
+        /// </summary>
+        /// <param name="rc">
+        /// The rendering context.
+        /// </param>
+        /// <param name="legendBox">
+        /// The legend rectangle.
+        /// </param>
+        public override void RenderLegend(IRenderContext rc, OxyRect legendBox)
+        {
+        }
+
+        /// <summary>
+        /// Transforms from a screen point to a data point by the axes of this series.
+        /// </summary>
+        /// <param name="p">
+        /// The screen point.
+        /// </param>
+        /// <returns>
+        /// A data point.
+        /// </returns>
+        public DataPoint InverseTransform(ScreenPoint p)
+        {
+            return this.XAxis.InverseTransform(p.X, p.Y, this.YAxis);
+        }
+
+        /// <summary>
+        /// Transforms the specified coordinates to a screen point by the axes of this series.
+        /// </summary>
+        /// <param name="x">
+        /// The x coordinate.
+        /// </param>
+        /// <param name="y">
+        /// The y coordinate.
+        /// </param>
+        /// <returns>
+        /// A screen point.
+        /// </returns>
+        public ScreenPoint Transform(double x, double y)
+        {
+            return this.XAxis.Transform(x, y, this.YAxis);
+        }
+
+        /// <summary>
+        /// Transforms the specified data point to a screen point by the axes of this series.
+        /// </summary>
+        /// <param name="p">
+        /// The point.
+        /// </param>
+        /// <returns>
+        /// A screen point.
+        /// </returns>
+        public ScreenPoint Transform(IDataPoint p)
+        {
+            return this.XAxis.Transform(p.X, p.Y, this.YAxis);
+        }
+
+        /// <summary>
+        /// Check if this data series requires X/Y axes. (e.g. Pie series do not require axes)
+        /// </summary>
+        /// <returns>
+        /// The are axes required.
+        /// </returns>
+        protected internal override bool AreAxesRequired()
+        {
+            return true;
+        }
+
+        /// <summary>
+        /// Ensures that the axes of the series is defined.
+        /// </summary>
+        protected internal override void EnsureAxes()
+        {
+            this.XAxis = PlotModel.GetAxisOrDefault(this.XAxisKey, PlotModel.DefaultXAxis);
+            this.YAxis = PlotModel.GetAxisOrDefault(this.YAxisKey, PlotModel.DefaultYAxis);
+        }
+
+        /// <summary>
+        /// Check if the data series is using the specified axis.
+        /// </summary>
+        /// <param name="axis">
+        /// An axis.
+        /// </param>
+        /// <returns>
+        /// True if the axis is in use.
+        /// </returns>
+        protected internal override bool IsUsing(Axis axis)
+        {
+            return false;
+        }
+
+        /// <summary>
+        /// Sets default values from the plot model.
+        /// </summary>
+        /// <param name="model">
+        /// The plot model.
+        /// </param>
+        protected internal override void SetDefaultValues(PlotModel model)
+        {
+        }
+
+        /// <summary>
+        /// Updates the axes to include the max and min of this series.
+        /// </summary>
+        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);
+        }
+
+        /// <summary>
+        /// Updates the data.
+        /// </summary>
+        protected internal override void UpdateData()
+        {
+        }
+
+        /// <summary>
+        /// Updates the max/minimum values.
+        /// </summary>
+        protected internal override void UpdateMaxMin()
+        {
+            this.MinX = this.MinY = this.MaxX = this.MaxY = double.NaN;
+        }
+
+        /// <summary>
+        /// Gets the clipping rectangle.
+        /// </summary>
+        /// <returns>
+        /// The clipping rectangle.
+        /// </returns>
+        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);
+        }
+
+        /// <summary>
+        /// Gets the point on the curve that is nearest the specified point.
+        /// </summary>
+        /// <param name="points">
+        /// The point list.
+        /// </param>
+        /// <param name="point">
+        /// The point.
+        /// </param>
+        /// <returns>
+        /// A tracker hit result if a point was found.
+        /// </returns>
+        protected TrackerHitResult GetNearestInterpolatedPointInternal(IList<IDataPoint> 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;
+        }
+
+        /// <summary>
+        /// Gets the nearest point.
+        /// </summary>
+        /// <param name="points">
+        /// The points (data coordinates).
+        /// </param>
+        /// <param name="point">
+        /// The point (screen coordinates).
+        /// </param>
+        /// <returns>
+        /// A <see cref="TrackerHitResult"/> if a point was found, null otherwise.
+        /// </returns>
+        protected TrackerHitResult GetNearestPointInternal(IEnumerable<IDataPoint> 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;
+        }
+
+        /// <summary>
+        /// Determines whether the specified point is valid.
+        /// </summary>
+        /// <param name="pt">
+        /// The point.
+        /// </param>
+        /// <param name="xaxis">
+        /// The x axis.
+        /// </param>
+        /// <param name="yaxis">
+        /// The y axis.
+        /// </param>
+        /// <returns>
+        /// <c>true</c> if the point is valid; otherwise, <c>false</c> .
+        /// </returns>
+        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));
+        }
+
+        /// <summary>
+        /// 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
+        /// </summary>
+        /// <param name="value">
+        /// The value.
+        /// </param>
+        /// <returns>
+        /// The floating point number value.
+        /// </returns>
+        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);
+        }
+
+        /// <summary>
+        /// Verifies that both axes are defined.
+        /// </summary>
+        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 --git a/oxyplot/OxyPlot/Svg/NativeMethods.cs b/oxyplot/OxyPlot/Svg/NativeMethods.cs
new file mode 100644
index 0000000..0b6bc1c
--- /dev/null
+++ b/oxyplot/OxyPlot/Svg/NativeMethods.cs
@@ -0,0 +1,246 @@
+// 
--------------------------------------------------------------------------------------------------------------------
+// <copyright file="NativeMethods.cs" company="OxyPlot">
+//   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.
+// </copyright>
+// <summary>
+//   Interface to GDI32 native methods.
+// </summary>
+// 
--------------------------------------------------------------------------------------------------------------------
+namespace OxyPlot
+{
+    using System;
+    using System.Runtime.InteropServices;
+    using System.Text.RegularExpressions;
+
+    /// <summary>
+    /// Provides access to native graphics methods.
+    /// </summary>
+    public class NativeMethods
+    {
+        /// <summary>
+        /// The delete dc.
+        /// </summary>
+        /// <param name="hdc">
+        /// The hdc.
+        /// </param>
+        /// <returns>
+        /// The delete dc.
+        /// </returns>
+        [DllImport("gdi32.dll")]
+        internal static extern bool DeleteDC(IntPtr hdc);
+
+        /// <summary>
+        /// The delete object.
+        /// </summary>
+        /// <param name="hgdiobj">
+        /// The hgdiobj.
+        /// </param>
+        /// <returns>
+        /// The delete object.
+        /// </returns>
+        [DllImport("gdi32.dll")]
+        internal static extern int DeleteObject(IntPtr hgdiobj);
+
+        /// <summary>
+        /// The get dc.
+        /// </summary>
+        /// <param name="hWnd">
+        /// The h wnd.
+        /// </param>
+        /// <returns>
+        /// </returns>
+        [DllImport("user32.dll")]
+        internal static extern IntPtr GetDC(IntPtr hWnd);
+
+        /// <summary>
+        /// The get text extent point 32.
+        /// </summary>
+        /// <param name="hdc">
+        /// The hdc.
+        /// </param>
+        /// <param name="str">
+        /// The str.
+        /// </param>
+        /// <param name="len">
+        /// The len.
+        /// </param>
+        /// <param name="siz">
+        /// The siz.
+        /// </param>
+        /// <returns>
+        /// The get text extent point 32.
+        /// </returns>
+        [DllImport("gdi32.dll", CharSet = CharSet.Unicode)]
+        internal static extern int GetTextExtentPoint32(IntPtr hdc, string str, int len, ref Size siz);
+
+        /// <summary>
+        /// The measure string.
+        /// </summary>
+        /// <param name="faceName">
+        /// The font face name.
+        /// </param>
+        /// <param name="height">
+        /// The height.
+        /// </param>
+        /// <param name="weight">
+        /// The weight.
+        /// </param>
+        /// <param name="str">
+        /// The string.
+        /// </param>
+        /// <returns>
+        /// The size of the rendered string.
+        /// </returns>
+        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;
+        }
+
+        /// <summary>
+        /// The select object.
+        /// </summary>
+        /// <param name="hdc">
+        /// The hdc.
+        /// </param>
+        /// <param name="hgdiObj">
+        /// The hgdi obj.
+        /// </param>
+        /// <returns>
+        /// </returns>
+        [DllImport("gdi32.dll")]
+        internal static extern IntPtr SelectObject(IntPtr hdc, IntPtr hgdiObj);
+
+        /// <summary>
+        /// The create font.
+        /// </summary>
+        /// <param name="nHeight">
+        /// The n height.
+        /// </param>
+        /// <param name="nWidth">
+        /// The n width.
+        /// </param>
+        /// <param name="nEscapement">
+        /// The n escapement.
+        /// </param>
+        /// <param name="nOrientation">
+        /// The n orientation.
+        /// </param>
+        /// <param name="fnWeight">
+        /// The fn weight.
+        /// </param>
+        /// <param name="fdwItalic">
+        /// The fdw italic.
+        /// </param>
+        /// <param name="fdwUnderline">
+        /// The fdw underline.
+        /// </param>
+        /// <param name="fdwStrikeOut">
+        /// The fdw strike out.
+        /// </param>
+        /// <param name="fdwCharSet">
+        /// The fdw char set.
+        /// </param>
+        /// <param name="fdwOutputPrecision">
+        /// The fdw output precision.
+        /// </param>
+        /// <param name="fdwClipPrecision">
+        /// The fdw clip precision.
+        /// </param>
+        /// <param name="fdwQuality">
+        /// The fdw quality.
+        /// </param>
+        /// <param name="fdwPitchAndFamily">
+        /// The fdw pitch and family.
+        /// </param>
+        /// <param name="lpszFace">
+        /// The lpsz face.
+        /// </param>
+        /// <returns>
+        /// </returns>
+        [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);
+
+        /// <summary>
+        /// Gets the text extent.
+        /// </summary>
+        /// <param name="hdc">The HDC.</param>
+        /// <param name="str">The STR.</param>
+        /// <returns></returns>
+        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);
+        }
+
+        /// <summary>
+        /// The size.
+        /// </summary>
+        [StructLayout(LayoutKind.Sequential)]
+        public struct Size
+        {
+            /// <summary>
+            /// The cx.
+            /// </summary>
+            public int cx;
+
+            /// <summary>
+            /// The cy.
+            /// </summary>
+            public int cy;
+        }
+    }
+}
\ No newline at end of file
diff --git a/oxyplot/OxyPlot/Svg/SvgExporter.cs b/oxyplot/OxyPlot/Svg/SvgExporter.cs
new file mode 100644
index 0000000..ef733e6
--- /dev/null
+++ b/oxyplot/OxyPlot/Svg/SvgExporter.cs
@@ -0,0 +1,85 @@
+// 
--------------------------------------------------------------------------------------------------------------------
+// <copyright file="SvgExporter.cs" company="OxyPlot">
+//   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.
+// </copyright>
+// <summary>
+//   Exports plot models to svg.
+// </summary>
+// 
--------------------------------------------------------------------------------------------------------------------
+namespace OxyPlot
+{
+    using System.IO;
+
+    /// <summary>
+    /// Exports plots to scalable vector graphics.
+    /// </summary>
+    public static class SvgExporter
+    {
+        /// <summary>
+        /// Exports the specified model to a stream.
+        /// </summary>
+        /// <param name="model">The model.</param>
+        /// <param name="stream">The output stream.</param>
+        /// <param name="width">The width (points).</param>
+        /// <param name="height">The height (points).</param>
+        /// <param name="isDocument">if set to <c>true</c>, the xml headers will be included (?xml and 
!DOCTYPE).</param>
+        /// <param name="textMeasurer">The text measurer.</param>
+        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();
+            }
+        }
+
+        /// <summary>
+        /// Exports to string.
+        /// </summary>
+        /// <param name="model">The model.</param>
+        /// <param name="width">The width (points).</param>
+        /// <param name="height">The height (points).</param>
+        /// <param name="isDocument">if set to <c>true</c>, the xml headers will be included (?xml and 
!DOCTYPE).</param>
+        /// <param name="textMeasurer">The text measurer.</param>
+        /// <returns>
+        /// The plot as a svg string.
+        /// </returns>
+        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 --git a/oxyplot/OxyPlot/Svg/SvgRenderContext.cs b/oxyplot/OxyPlot/Svg/SvgRenderContext.cs
new file mode 100644
index 0000000..9aa03ae
--- /dev/null
+++ b/oxyplot/OxyPlot/Svg/SvgRenderContext.cs
@@ -0,0 +1,278 @@
+// 
--------------------------------------------------------------------------------------------------------------------
+// <copyright file="SvgRenderContext.cs" company="OxyPlot">
+//   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.
+// </copyright>
+// <summary>
+//   The svg render context.
+// </summary>
+// 
--------------------------------------------------------------------------------------------------------------------
+namespace OxyPlot
+{
+    using System;
+    using System.Collections.Generic;
+    using System.IO;
+    using System.Text.RegularExpressions;
+
+    /// <summary>
+    /// Provides a render context for scalable vector graphics output.
+    /// </summary>
+    public class SvgRenderContext : RenderContextBase, IDisposable
+    {
+        /// <summary>
+        /// The writer.
+        /// </summary>
+        private readonly SvgWriter w;
+
+        /// <summary>
+        /// The disposed flag.
+        /// </summary>
+        private bool disposed;
+
+        /// <summary>
+        /// Initializes a new instance of the <see cref="SvgRenderContext" /> class.
+        /// </summary>
+        /// <param name="s">The s.</param>
+        /// <param name="width">The width.</param>
+        /// <param name="height">The height.</param>
+        /// <param name="isDocument">Create an SVG document if set to <c>true</c>.</param>
+        /// <param name="textMeasurer">The text measurer.</param>
+        /// <param name="background">The background.</param>
+        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));
+            }
+        }
+
+        /// <summary>
+        /// Gets or sets the text measurer.
+        /// </summary>
+        /// <value>
+        /// The text measurer.
+        /// </value>
+        public IRenderContext TextMeasurer { get; set; }
+
+        /// <summary>
+        /// Closes the svg writer.
+        /// </summary>
+        public void Close()
+        {
+            this.w.Close();
+        }
+
+        /// <summary>
+        /// Completes the svg element.
+        /// </summary>
+        public void Complete()
+        {
+            this.w.Complete();
+        }
+
+        /// <summary>
+        /// Performs application-defined tasks associated with freeing, releasing, or resetting unmanaged 
resources.
+        /// </summary>
+        public void Dispose()
+        {
+            this.Dispose(true);
+            GC.SuppressFinalize(this);
+        }
+
+        /// <summary>
+        /// Draws an ellipse.
+        /// </summary>
+        /// <param name="rect">The rectangle.</param>
+        /// <param name="fill">The fill color.</param>
+        /// <param name="stroke">The stroke color.</param>
+        /// <param name="thickness">The thickness.</param>
+        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));
+        }
+
+        /// <summary>
+        /// Draws the polyline from the specified points.
+        /// </summary>
+        /// <param name="points">The points.</param>
+        /// <param name="stroke">The stroke color.</param>
+        /// <param name="thickness">The stroke thickness.</param>
+        /// <param name="dashArray">The dash array.</param>
+        /// <param name="lineJoin">The line join type.</param>
+        /// <param name="aliased">if set to <c>true</c> the shape will be aliased.</param>
+        public override void DrawLine(
+            IList<ScreenPoint> points,
+            OxyColor stroke,
+            double thickness,
+            double[] dashArray,
+            OxyPenLineJoin lineJoin,
+            bool aliased)
+        {
+            this.w.WritePolyline(points, this.w.CreateStyle(null, stroke, thickness, dashArray, lineJoin));
+        }
+
+        /// <summary>
+        /// Draws the polygon from the specified points. The polygon can have stroke and/or fill.
+        /// </summary>
+        /// <param name="points">The points.</param>
+        /// <param name="fill">The fill color.</param>
+        /// <param name="stroke">The stroke color.</param>
+        /// <param name="thickness">The stroke thickness.</param>
+        /// <param name="dashArray">The dash array.</param>
+        /// <param name="lineJoin">The line join type.</param>
+        /// <param name="aliased">if set to <c>true</c> the shape will be aliased.</param>
+        public override void DrawPolygon(
+            IList<ScreenPoint> 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));
+        }
+
+        /// <summary>
+        /// Draws the rectangle.
+        /// </summary>
+        /// <param name="rect">The rectangle.</param>
+        /// <param name="fill">The fill color.</param>
+        /// <param name="stroke">The stroke color.</param>
+        /// <param name="thickness">The stroke thickness.</param>
+        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));
+        }
+
+        /// <summary>
+        /// Draws the text.
+        /// </summary>
+        /// <param name="p">The p.</param>
+        /// <param name="text">The text.</param>
+        /// <param name="c">The c.</param>
+        /// <param name="fontFamily">The font family.</param>
+        /// <param name="fontSize">Size of the font.</param>
+        /// <param name="fontWeight">The font weight.</param>
+        /// <param name="rotate">The rotate.</param>
+        /// <param name="halign">The horizontal alignment.</param>
+        /// <param name="valign">The vertical alignment.</param>
+        /// <param name="maxSize">Size of the max.</param>
+        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;
+                }
+            }
+        }
+
+        /// <summary>
+        /// Flushes this instance.
+        /// </summary>
+        public void Flush()
+        {
+            this.w.Flush();
+        }
+
+        /// <summary>
+        /// Measures the text.
+        /// </summary>
+        /// <param name="text">The text.</param>
+        /// <param name="fontFamily">The font family.</param>
+        /// <param name="fontSize">Size of the font.</param>
+        /// <param name="fontWeight">The font weight.</param>
+        /// <returns>
+        /// The text size.
+        /// </returns>
+        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);
+        }
+
+        /// <summary>
+        /// Releases unmanaged and - optionally - managed resources
+        /// </summary>
+        /// <param name="disposing"><c>true</c> to release both managed and unmanaged resources; 
<c>false</c> to release only unmanaged resources.</param>
+        private void Dispose(bool disposing)
+        {
+            if (!this.disposed)
+            {
+                if (disposing)
+                {
+                    this.w.Dispose();
+                }
+            }
+
+            this.disposed = true;
+        }
+    }
+}
\ No newline at end of file
diff --git a/oxyplot/OxyPlot/Svg/SvgWriter.cs b/oxyplot/OxyPlot/Svg/SvgWriter.cs
new file mode 100644
index 0000000..ef0b4af
--- /dev/null
+++ b/oxyplot/OxyPlot/Svg/SvgWriter.cs
@@ -0,0 +1,502 @@
+// 
--------------------------------------------------------------------------------------------------------------------
+// <copyright file="SvgWriter.cs" company="OxyPlot">
+//   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.
+// </copyright>
+// <summary>
+//   Scalable Vector Graphics writer.
+// </summary>
+// 
--------------------------------------------------------------------------------------------------------------------
+namespace OxyPlot
+{
+    using System;
+    using System.Collections.Generic;
+    using System.Globalization;
+    using System.IO;
+    using System.Text;
+
+    /// <summary>
+    /// Represents a writer that provides easy generation of Scalable Vector Graphics files.
+    /// </summary>
+    public class SvgWriter : XmlWriterBase
+    {
+        /// <summary>
+        /// The end is written.
+        /// </summary>
+        private bool endIsWritten;
+
+        /// <summary>
+        /// Initializes a new instance of the <see cref="SvgWriter"/> class.
+        /// </summary>
+        /// <param name="stream">
+        /// The stream.
+        /// </param>
+        /// <param name="width">
+        /// The width.
+        /// </param>
+        /// <param name="height">
+        /// The height.
+        /// </param>
+        /// <param name="isDocument">
+        /// if set to <c>true</c>, the writer will write the xml headers (?xml and !DOCTYPE).
+        /// </param>
+        public SvgWriter(Stream stream, double width, double height, bool isDocument = true)
+            : base(stream)
+        {
+            this.IsDocument = isDocument;
+            this.NumberFormat = "0.####";
+            this.WriteHeader(width, height);
+        }
+
+        /// <summary>
+        /// Gets or sets a value indicating whether this writer should produce a stand-alone document.
+        /// </summary>
+        public bool IsDocument { get; set; }
+
+        /// <summary>
+        /// Gets or sets the number format.
+        /// </summary>
+        /// <value>The number format.</value>
+        public string NumberFormat { get; set; }
+
+        /// <summary>
+        /// Closes the svg document.
+        /// </summary>
+        public override void Close()
+        {
+            if (!this.endIsWritten)
+            {
+                this.Complete();
+            }
+
+            base.Close();
+        }
+
+        /// <summary>
+        /// Writes the end of the document.
+        /// </summary>
+        public void Complete()
+        {
+            this.WriteEndElement();
+            if (this.IsDocument)
+            {
+                this.WriteEndDocument();
+            }
+
+            this.endIsWritten = true;
+        }
+
+        /// <summary>
+        /// Creates a style.
+        /// </summary>
+        /// <param name="fill">
+        /// The fill color.
+        /// </param>
+        /// <param name="stroke">
+        /// The stroke color.
+        /// </param>
+        /// <param name="thickness">
+        /// The stroke thickness.
+        /// </param>
+        /// <param name="dashArray">
+        /// The line dash array.
+        /// </param>
+        /// <param name="lineJoin">
+        /// The line join type.
+        /// </param>
+        /// <returns>
+        /// A style string.
+        /// </returns>
+        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();
+        }
+
+        /// <summary>
+        /// Writes an ellipse.
+        /// </summary>
+        /// <param name="x">
+        /// The x coordinate of the center.
+        /// </param>
+        /// <param name="y">
+        /// The y coordinate of the center.
+        /// </param>
+        /// <param name="width">
+        /// The width.
+        /// </param>
+        /// <param name="height">
+        /// The height.
+        /// </param>
+        /// <param name="style">
+        /// The style.
+        /// </param>
+        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();
+        }
+
+        /// <summary>
+        /// Writes a line.
+        /// </summary>
+        /// <param name="p1">
+        /// The first point.
+        /// </param>
+        /// <param name="p2">
+        /// The second point.
+        /// </param>
+        /// <param name="style">
+        /// The style.
+        /// </param>
+        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();
+        }
+
+        /// <summary>
+        /// Writes a polygon.
+        /// </summary>
+        /// <param name="points">
+        /// The points.
+        /// </param>
+        /// <param name="style">
+        /// The style.
+        /// </param>
+        public void WritePolygon(IEnumerable<ScreenPoint> 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();
+        }
+
+        /// <summary>
+        /// Writes a polyline.
+        /// </summary>
+        /// <param name="pts">
+        /// The points.
+        /// </param>
+        /// <param name="style">
+        /// The style.
+        /// </param>
+        public void WritePolyline(IEnumerable<ScreenPoint> 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();
+        }
+
+        /// <summary>
+        /// Writes a rectangle.
+        /// </summary>
+        /// <param name="x">
+        /// The x coordinate.
+        /// </param>
+        /// <param name="y">
+        /// The y coordinate.
+        /// </param>
+        /// <param name="width">
+        /// The width.
+        /// </param>
+        /// <param name="height">
+        /// The height.
+        /// </param>
+        /// <param name="style">
+        /// The style.
+        /// </param>
+        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();
+        }
+
+        /// <summary>
+        /// Writes text.
+        /// </summary>
+        /// <param name="position">
+        /// The position.
+        /// </param>
+        /// <param name="text">
+        /// The text.
+        /// </param>
+        /// <param name="fill">
+        /// The text color.
+        /// </param>
+        /// <param name="fontFamily">
+        /// The font family.
+        /// </param>
+        /// <param name="fontSize">
+        /// The font size.
+        /// </param>
+        /// <param name="fontWeight">
+        /// The font weight.
+        /// </param>
+        /// <param name="rotate">
+        /// The rotation angle.
+        /// </param>
+        /// <param name="halign">
+        /// The horizontal alignment.
+        /// </param>
+        /// <param name="valign">
+        /// The vertical alignment.
+        /// </param>
+        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();
+        }
+
+        /// <summary>
+        /// Converts a color to a svg color string.
+        /// </summary>
+        /// <param name="color">The color.</param>
+        /// <returns>The color string.</returns>
+        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);
+        }
+
+        /// <summary>
+        /// The write attribute string.
+        /// </summary>
+        /// <param name="name">
+        /// The name.
+        /// </param>
+        /// <param name="value">
+        /// The value.
+        /// </param>
+        protected void WriteAttributeString(string name, double value)
+        {
+            this.WriteAttributeString(name, value.ToString(this.NumberFormat, CultureInfo.InvariantCulture));
+        }
+
+        /// <summary>
+        /// Converts a value to a string or to the specified "auto" string if the value is NaN.
+        /// </summary>
+        /// <param name="value">The value.</param>
+        /// <param name="auto">The string to return if value is NaN.</param>
+        /// <returns>A string.</returns>
+        private string GetAutoValue(double value, string auto)
+        {
+            if (double.IsNaN(value))
+            {
+                return auto;
+            }
+
+            return value.ToString(this.NumberFormat, CultureInfo.InvariantCulture);
+        }
+
+        /// <summary>
+        /// Converts a list of points to a string.
+        /// </summary>
+        /// <param name="points">The points.</param>
+        /// <returns>A string.</returns>
+        private string PointsToString(IEnumerable<ScreenPoint> 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();
+        }
+
+        /// <summary>
+        /// The write header.
+        /// </summary>
+        /// <param name="width">
+        /// The width.
+        /// </param>
+        /// <param name="height">
+        /// The height.
+        /// </param>
+        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
diff --git a/oxyplot/OxyPlotMono.sln b/oxyplot/OxyPlotMono.sln
new file mode 100644
index 0000000..bad015e
--- /dev/null
+++ b/oxyplot/OxyPlotMono.sln
@@ -0,0 +1,20 @@
+
+Microsoft Visual Studio Solution File, Format Version 11.00
+# Visual Studio 2010
+Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "OxyPlotMono", "OxyPlotMono\OxyPlotMono.csproj", 
"{2CE0AF61-3E7D-43A8-ADD2-DAA38DFD5173}"
+EndProject
+Global
+       GlobalSection(SolutionConfigurationPlatforms) = preSolution
+               Debug|Any CPU = Debug|Any CPU
+               Release|Any CPU = Release|Any CPU
+       EndGlobalSection
+       GlobalSection(ProjectConfigurationPlatforms) = postSolution
+               {2CE0AF61-3E7D-43A8-ADD2-DAA38DFD5173}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
+               {2CE0AF61-3E7D-43A8-ADD2-DAA38DFD5173}.Debug|Any CPU.Build.0 = Debug|Any CPU
+               {2CE0AF61-3E7D-43A8-ADD2-DAA38DFD5173}.Release|Any CPU.ActiveCfg = Release|Any CPU
+               {2CE0AF61-3E7D-43A8-ADD2-DAA38DFD5173}.Release|Any CPU.Build.0 = Release|Any CPU
+       EndGlobalSection
+       GlobalSection(MonoDevelopProperties) = preSolution
+               StartupItem = OxyPlotMono\OxyPlotMono.csproj
+       EndGlobalSection
+EndGlobal
diff --git a/oxyplot/OxyPlotMono/OxyPlotMono.csproj b/oxyplot/OxyPlotMono/OxyPlotMono.csproj
new file mode 100644
index 0000000..3aa832b
--- /dev/null
+++ b/oxyplot/OxyPlotMono/OxyPlotMono.csproj
@@ -0,0 +1,562 @@
+<?xml version="1.0" encoding="utf-8"?>
+<Project DefaultTargets="Build" ToolsVersion="4.0" 
xmlns="http://schemas.microsoft.com/developer/msbuild/2003";>
+  <PropertyGroup>
+    <Configuration Condition=" '$(Configuration)' == '' ">Debug</Configuration>
+    <Platform Condition=" '$(Platform)' == '' ">AnyCPU</Platform>
+    <ProductVersion>10.0.0</ProductVersion>
+    <SchemaVersion>2.0</SchemaVersion>
+    <ProjectGuid>{2CE0AF61-3E7D-43A8-ADD2-DAA38DFD5173}</ProjectGuid>
+    <OutputType>Library</OutputType>
+    <RootNamespace>OxyPlotMono</RootNamespace>
+    <AssemblyName>OxyPlotMono</AssemblyName>
+  </PropertyGroup>
+  <PropertyGroup Condition=" '$(Configuration)|$(Platform)' == 'Debug|AnyCPU' ">
+    <DebugSymbols>true</DebugSymbols>
+    <DebugType>full</DebugType>
+    <Optimize>false</Optimize>
+    <OutputPath>bin\Debug</OutputPath>
+    <DefineConstants>DEBUG;</DefineConstants>
+    <ErrorReport>prompt</ErrorReport>
+    <WarningLevel>4</WarningLevel>
+    <ConsolePause>false</ConsolePause>
+  </PropertyGroup>
+  <PropertyGroup Condition=" '$(Configuration)|$(Platform)' == 'Release|AnyCPU' ">
+    <DebugType>none</DebugType>
+    <Optimize>true</Optimize>
+    <OutputPath>bin\Release</OutputPath>
+    <ErrorReport>prompt</ErrorReport>
+    <WarningLevel>4</WarningLevel>
+    <ConsolePause>false</ConsolePause>
+  </PropertyGroup>
+  <ItemGroup>
+    <Reference Include="System" />
+    <Reference Include="System.Xml" />
+  </ItemGroup>
+  <Import Project="$(MSBuildBinPath)\Microsoft.CSharp.targets" />
+  <ItemGroup>
+    <Compile Include="..\OxyPlot\LibraryDoc.cs">
+      <Link>LibraryDoc.cs</Link>
+    </Compile>
+    <Compile Include="..\OxyPlot\NamespaceDoc.cs">
+      <Link>NamespaceDoc.cs</Link>
+    </Compile>
+    <Compile Include="..\OxyPlot\Annotations\Annotation.cs">
+      <Link>Annotations\Annotation.cs</Link>
+    </Compile>
+    <Compile Include="..\OxyPlot\Annotations\AnnotationLayer.cs">
+      <Link>Annotations\AnnotationLayer.cs</Link>
+    </Compile>
+    <Compile Include="..\OxyPlot\Annotations\ArrowAnnotation.cs">
+      <Link>Annotations\ArrowAnnotation.cs</Link>
+    </Compile>
+    <Compile Include="..\OxyPlot\Annotations\EllipseAnnotation.cs">
+      <Link>Annotations\EllipseAnnotation.cs</Link>
+    </Compile>
+    <Compile Include="..\OxyPlot\Annotations\ImageAnnotation.cs">
+      <Link>Annotations\ImageAnnotation.cs</Link>
+    </Compile>
+    <Compile Include="..\OxyPlot\Annotations\LineAnnotation.cs">
+      <Link>Annotations\LineAnnotation.cs</Link>
+    </Compile>
+    <Compile Include="..\OxyPlot\Annotations\LineAnnotationType.cs">
+      <Link>Annotations\LineAnnotationType.cs</Link>
+    </Compile>
+    <Compile Include="..\OxyPlot\Annotations\PolygonAnnotation.cs">
+      <Link>Annotations\PolygonAnnotation.cs</Link>
+    </Compile>
+    <Compile Include="..\OxyPlot\Annotations\RectangleAnnotation.cs">
+      <Link>Annotations\RectangleAnnotation.cs</Link>
+    </Compile>
+    <Compile Include="..\OxyPlot\Annotations\TextAnnotation.cs">
+      <Link>Annotations\TextAnnotation.cs</Link>
+    </Compile>
+    <Compile Include="..\OxyPlot\Annotations\TextualAnnotation.cs">
+      <Link>Annotations\TextualAnnotation.cs</Link>
+    </Compile>
+    <Compile Include="..\OxyPlot\Annotations\TileMapAnnotation.cs">
+      <Link>Annotations\TileMapAnnotation.cs</Link>
+    </Compile>
+    <Compile Include="..\OxyPlot\Axes\AngleAxis.cs">
+      <Link>Axes\AngleAxis.cs</Link>
+    </Compile>
+    <Compile Include="..\OxyPlot\Axes\Axis.cs">
+      <Link>Axes\Axis.cs</Link>
+    </Compile>
+    <Compile Include="..\OxyPlot\Axes\AxisChangeTypes.cs">
+      <Link>Axes\AxisChangeTypes.cs</Link>
+    </Compile>
+    <Compile Include="..\OxyPlot\Axes\AxisChangedEventArgs.cs">
+      <Link>Axes\AxisChangedEventArgs.cs</Link>
+    </Compile>
+    <Compile Include="..\OxyPlot\Axes\AxisLayer.cs">
+      <Link>Axes\AxisLayer.cs</Link>
+    </Compile>
+    <Compile Include="..\OxyPlot\Axes\AxisPosition.cs">
+      <Link>Axes\AxisPosition.cs</Link>
+    </Compile>
+    <Compile Include="..\OxyPlot\Axes\CategoryAxis.cs">
+      <Link>Axes\CategoryAxis.cs</Link>
+    </Compile>
+    <Compile Include="..\OxyPlot\Axes\ColorAxis.cs">
+      <Link>Axes\ColorAxis.cs</Link>
+    </Compile>
+    <Compile Include="..\OxyPlot\Axes\DateTimeAxis.cs">
+      <Link>Axes\DateTimeAxis.cs</Link>
+    </Compile>
+    <Compile Include="..\OxyPlot\Axes\DateTimeIntervalType.cs">
+      <Link>Axes\DateTimeIntervalType.cs</Link>
+    </Compile>
+    <Compile Include="..\OxyPlot\Axes\LinearAxis.cs">
+      <Link>Axes\LinearAxis.cs</Link>
+    </Compile>
+    <Compile Include="..\OxyPlot\Axes\LogarithmicAxis.cs">
+      <Link>Axes\LogarithmicAxis.cs</Link>
+    </Compile>
+    <Compile Include="..\OxyPlot\Axes\MagnitudeAxis.cs">
+      <Link>Axes\MagnitudeAxis.cs</Link>
+    </Compile>
+    <Compile Include="..\OxyPlot\Axes\TickStyle.cs">
+      <Link>Axes\TickStyle.cs</Link>
+    </Compile>
+    <Compile Include="..\OxyPlot\Axes\TimeSpanAxis.cs">
+      <Link>Axes\TimeSpanAxis.cs</Link>
+    </Compile>
+    <Compile Include="..\OxyPlot\Foundation\ArrayHelper.cs">
+      <Link>Foundation\ArrayHelper.cs</Link>
+    </Compile>
+    <Compile Include="..\OxyPlot\Foundation\CanonicalSplineHelper.cs">
+      <Link>Foundation\CanonicalSplineHelper.cs</Link>
+    </Compile>
+    <Compile Include="..\OxyPlot\Foundation\CohenSutherlandClipping.cs">
+      <Link>Foundation\CohenSutherlandClipping.cs</Link>
+    </Compile>
+    <Compile Include="..\OxyPlot\Foundation\Conrec.cs">
+      <Link>Foundation\Conrec.cs</Link>
+    </Compile>
+    <Compile Include="..\OxyPlot\Foundation\DataPoint.cs">
+      <Link>Foundation\DataPoint.cs</Link>
+    </Compile>
+    <Compile Include="..\OxyPlot\Foundation\DoubleExtensions.cs">
+      <Link>Foundation\DoubleExtensions.cs</Link>
+    </Compile>
+    <Compile Include="..\OxyPlot\Foundation\FontWeights.cs">
+      <Link>Foundation\FontWeights.cs</Link>
+    </Compile>
+    <Compile Include="..\OxyPlot\Foundation\FractionHelper.cs">
+      <Link>Foundation\FractionHelper.cs</Link>
+    </Compile>
+    <Compile Include="..\OxyPlot\Foundation\HorizontalAlignment.cs">
+      <Link>Foundation\HorizontalAlignment.cs</Link>
+    </Compile>
+    <Compile Include="..\OxyPlot\Foundation\IDataPoint.cs">
+      <Link>Foundation\IDataPoint.cs</Link>
+    </Compile>
+    <Compile Include="..\OxyPlot\Foundation\IDataPointProvider.cs">
+      <Link>Foundation\IDataPointProvider.cs</Link>
+    </Compile>
+    <Compile Include="..\OxyPlot\Foundation\LineStyle.cs">
+      <Link>Foundation\LineStyle.cs</Link>
+    </Compile>
+    <Compile Include="..\OxyPlot\Foundation\LineStyleHelper.cs">
+      <Link>Foundation\LineStyleHelper.cs</Link>
+    </Compile>
+    <Compile Include="..\OxyPlot\Foundation\ListFiller.cs">
+      <Link>Foundation\ListFiller.cs</Link>
+    </Compile>
+    <Compile Include="..\OxyPlot\Foundation\MarkerType.cs">
+      <Link>Foundation\MarkerType.cs</Link>
+    </Compile>
+    <Compile Include="..\OxyPlot\Foundation\OxyColor.cs">
+      <Link>Foundation\OxyColor.cs</Link>
+    </Compile>
+    <Compile Include="..\OxyPlot\Foundation\OxyColors.cs">
+      <Link>Foundation\OxyColors.cs</Link>
+    </Compile>
+    <Compile Include="..\OxyPlot\Foundation\OxyImage.cs">
+      <Link>Foundation\OxyImage.cs</Link>
+    </Compile>
+    <Compile Include="..\OxyPlot\Foundation\OxyPalette.cs">
+      <Link>Foundation\OxyPalette.cs</Link>
+    </Compile>
+    <Compile Include="..\OxyPlot\Foundation\OxyPalettes.cs">
+      <Link>Foundation\OxyPalettes.cs</Link>
+    </Compile>
+    <Compile Include="..\OxyPlot\Foundation\OxyPen.cs">
+      <Link>Foundation\OxyPen.cs</Link>
+    </Compile>
+    <Compile Include="..\OxyPlot\Foundation\OxyPenLineJoin.cs">
+      <Link>Foundation\OxyPenLineJoin.cs</Link>
+    </Compile>
+    <Compile Include="..\OxyPlot\Foundation\OxyRect.cs">
+      <Link>Foundation\OxyRect.cs</Link>
+    </Compile>
+    <Compile Include="..\OxyPlot\Foundation\OxySize.cs">
+      <Link>Foundation\OxySize.cs</Link>
+    </Compile>
+    <Compile Include="..\OxyPlot\Foundation\OxyThickness.cs">
+      <Link>Foundation\OxyThickness.cs</Link>
+    </Compile>
+    <Compile Include="..\OxyPlot\Foundation\PlotLength.cs">
+      <Link>Foundation\PlotLength.cs</Link>
+    </Compile>
+    <Compile Include="..\OxyPlot\Foundation\PlotLengthUnit.cs">
+      <Link>Foundation\PlotLengthUnit.cs</Link>
+    </Compile>
+    <Compile Include="..\OxyPlot\Foundation\PngEncoder.cs">
+      <Link>Foundation\PngEncoder.cs</Link>
+    </Compile>
+    <Compile Include="..\OxyPlot\Foundation\ReflectionHelper.cs">
+      <Link>Foundation\ReflectionHelper.cs</Link>
+    </Compile>
+    <Compile Include="..\OxyPlot\Foundation\ScreenPoint.cs">
+      <Link>Foundation\ScreenPoint.cs</Link>
+    </Compile>
+    <Compile Include="..\OxyPlot\Foundation\ScreenPointHelper.cs">
+      <Link>Foundation\ScreenPointHelper.cs</Link>
+    </Compile>
+    <Compile Include="..\OxyPlot\Foundation\ScreenVector.cs">
+      <Link>Foundation\ScreenVector.cs</Link>
+    </Compile>
+    <Compile Include="..\OxyPlot\Foundation\StreamExtensions.cs">
+      <Link>Foundation\StreamExtensions.cs</Link>
+    </Compile>
+    <Compile Include="..\OxyPlot\Foundation\StringHelper.cs">
+      <Link>Foundation\StringHelper.cs</Link>
+    </Compile>
+    <Compile Include="..\OxyPlot\Foundation\SutherlandHodgmanClipping.cs">
+      <Link>Foundation\SutherlandHodgmanClipping.cs</Link>
+    </Compile>
+    <Compile Include="..\OxyPlot\Foundation\VerticalAlignment.cs">
+      <Link>Foundation\VerticalAlignment.cs</Link>
+    </Compile>
+    <Compile Include="..\OxyPlot\Foundation\XmlWriterBase.cs">
+      <Link>Foundation\XmlWriterBase.cs</Link>
+    </Compile>
+    <Compile Include="..\OxyPlot\Foundation\CodeGenerator\CodeGenerationAttribute.cs">
+      <Link>Foundation\CodeGenerator\CodeGenerationAttribute.cs</Link>
+    </Compile>
+    <Compile Include="..\OxyPlot\Foundation\CodeGenerator\CodeGenerator.cs">
+      <Link>Foundation\CodeGenerator\CodeGenerator.cs</Link>
+    </Compile>
+    <Compile Include="..\OxyPlot\Foundation\CodeGenerator\CodeGeneratorStringExtensions.cs">
+      <Link>Foundation\CodeGenerator\CodeGeneratorStringExtensions.cs</Link>
+    </Compile>
+    <Compile Include="..\OxyPlot\Foundation\CodeGenerator\ICodeGenerating.cs">
+      <Link>Foundation\CodeGenerator\ICodeGenerating.cs</Link>
+    </Compile>
+    <Compile Include="..\OxyPlot\Manipulators\CursorType.cs">
+      <Link>Manipulators\CursorType.cs</Link>
+    </Compile>
+    <Compile Include="..\OxyPlot\Manipulators\IPlotControl.cs">
+      <Link>Manipulators\IPlotControl.cs</Link>
+    </Compile>
+    <Compile Include="..\OxyPlot\Manipulators\ManipulationEventArgs.cs">
+      <Link>Manipulators\ManipulationEventArgs.cs</Link>
+    </Compile>
+    <Compile Include="..\OxyPlot\Manipulators\ManipulatorBase.cs">
+      <Link>Manipulators\ManipulatorBase.cs</Link>
+    </Compile>
+    <Compile Include="..\OxyPlot\Manipulators\PanManipulator.cs">
+      <Link>Manipulators\PanManipulator.cs</Link>
+    </Compile>
+    <Compile Include="..\OxyPlot\Manipulators\ResetManipulator.cs">
+      <Link>Manipulators\ResetManipulator.cs</Link>
+    </Compile>
+    <Compile Include="..\OxyPlot\Manipulators\TrackerHitResult.cs">
+      <Link>Manipulators\TrackerHitResult.cs</Link>
+    </Compile>
+    <Compile Include="..\OxyPlot\Manipulators\TrackerManipulator.cs">
+      <Link>Manipulators\TrackerManipulator.cs</Link>
+    </Compile>
+    <Compile Include="..\OxyPlot\Manipulators\ZoomManipulator.cs">
+      <Link>Manipulators\ZoomManipulator.cs</Link>
+    </Compile>
+    <Compile Include="..\OxyPlot\Manipulators\ZoomRectangleManipulator.cs">
+      <Link>Manipulators\ZoomRectangleManipulator.cs</Link>
+    </Compile>
+    <Compile Include="..\OxyPlot\Manipulators\ZoomStepManipulator.cs">
+      <Link>Manipulators\ZoomStepManipulator.cs</Link>
+    </Compile>
+    <Compile Include="..\OxyPlot\PlotModel\HitTestResult.cs">
+      <Link>PlotModel\HitTestResult.cs</Link>
+    </Compile>
+    <Compile Include="..\OxyPlot\PlotModel\OxyMouseButton.cs">
+      <Link>PlotModel\OxyMouseButton.cs</Link>
+    </Compile>
+    <Compile Include="..\OxyPlot\PlotModel\OxyMouseEventArgs.cs">
+      <Link>PlotModel\OxyMouseEventArgs.cs</Link>
+    </Compile>
+    <Compile Include="..\OxyPlot\PlotModel\PlotElement.cs">
+      <Link>PlotModel\PlotElement.cs</Link>
+    </Compile>
+    <Compile Include="..\OxyPlot\PlotModel\PlotModel.Legends.cs">
+      <Link>PlotModel\PlotModel.Legends.cs</Link>
+    </Compile>
+    <Compile Include="..\OxyPlot\PlotModel\PlotModel.MouseEvents.cs">
+      <Link>PlotModel\PlotModel.MouseEvents.cs</Link>
+    </Compile>
+    <Compile Include="..\OxyPlot\PlotModel\PlotModel.Rendering.cs">
+      <Link>PlotModel\PlotModel.Rendering.cs</Link>
+    </Compile>
+    <Compile Include="..\OxyPlot\PlotModel\PlotModel.cs">
+      <Link>PlotModel\PlotModel.cs</Link>
+    </Compile>
+    <Compile Include="..\OxyPlot\PlotModel\SelectablePlotElement.cs">
+      <Link>PlotModel\SelectablePlotElement.cs</Link>
+    </Compile>
+    <Compile Include="..\OxyPlot\PlotModel\UIPlotElement.cs">
+      <Link>PlotModel\UIPlotElement.cs</Link>
+    </Compile>
+    <Compile Include="..\OxyPlot\Properties\AssemblyInfo.cs">
+      <Link>Properties\AssemblyInfo.cs</Link>
+    </Compile>
+    <Compile Include="..\OxyPlot\Render\AngleAxisRenderer.cs">
+      <Link>Render\AngleAxisRenderer.cs</Link>
+    </Compile>
+    <Compile Include="..\OxyPlot\Render\AxisRendererBase.cs">
+      <Link>Render\AxisRendererBase.cs</Link>
+    </Compile>
+    <Compile Include="..\OxyPlot\Render\HorizontalAndVerticalAxisRenderer.cs">
+      <Link>Render\HorizontalAndVerticalAxisRenderer.cs</Link>
+    </Compile>
+    <Compile Include="..\OxyPlot\Render\IRenderContext.cs">
+      <Link>Render\IRenderContext.cs</Link>
+    </Compile>
+    <Compile Include="..\OxyPlot\Render\MagnitudeAxisRenderer.cs">
+      <Link>Render\MagnitudeAxisRenderer.cs</Link>
+    </Compile>
+    <Compile Include="..\OxyPlot\Render\MathRenderingExtensions.cs">
+      <Link>Render\MathRenderingExtensions.cs</Link>
+    </Compile>
+    <Compile Include="..\OxyPlot\Render\RenderContextBase.cs">
+      <Link>Render\RenderContextBase.cs</Link>
+    </Compile>
+    <Compile Include="..\OxyPlot\Render\RenderingExtensions.cs">
+      <Link>Render\RenderingExtensions.cs</Link>
+    </Compile>
+    <Compile Include="..\OxyPlot\Reporting\NamespaceDoc.cs">
+      <Link>Reporting\NamespaceDoc.cs</Link>
+    </Compile>
+    <Compile Include="..\OxyPlot\Reporting\Report\DrawingFigure.cs">
+      <Link>Reporting\Report\DrawingFigure.cs</Link>
+    </Compile>
+    <Compile Include="..\OxyPlot\Reporting\Report\Equation.cs">
+      <Link>Reporting\Report\Equation.cs</Link>
+    </Compile>
+    <Compile Include="..\OxyPlot\Reporting\Report\Figure.cs">
+      <Link>Reporting\Report\Figure.cs</Link>
+    </Compile>
+    <Compile Include="..\OxyPlot\Reporting\Report\Header.cs">
+      <Link>Reporting\Report\Header.cs</Link>
+    </Compile>
+    <Compile Include="..\OxyPlot\Reporting\Report\HeaderHelper.cs">
+      <Link>Reporting\Report\HeaderHelper.cs</Link>
+    </Compile>
+    <Compile Include="..\OxyPlot\Reporting\Report\Image.cs">
+      <Link>Reporting\Report\Image.cs</Link>
+    </Compile>
+    <Compile Include="..\OxyPlot\Reporting\Report\ItemsTable.cs">
+      <Link>Reporting\Report\ItemsTable.cs</Link>
+    </Compile>
+    <Compile Include="..\OxyPlot\Reporting\Report\ItemsTableField.cs">
+      <Link>Reporting\Report\ItemsTableField.cs</Link>
+    </Compile>
+    <Compile Include="..\OxyPlot\Reporting\Report\Paragraph.cs">
+      <Link>Reporting\Report\Paragraph.cs</Link>
+    </Compile>
+    <Compile Include="..\OxyPlot\Reporting\Report\ParagraphStyle.cs">
+      <Link>Reporting\Report\ParagraphStyle.cs</Link>
+    </Compile>
+    <Compile Include="..\OxyPlot\Reporting\Report\PlotFigure.cs">
+      <Link>Reporting\Report\PlotFigure.cs</Link>
+    </Compile>
+    <Compile Include="..\OxyPlot\Reporting\Report\PropertyTable.cs">
+      <Link>Reporting\Report\PropertyTable.cs</Link>
+    </Compile>
+    <Compile Include="..\OxyPlot\Reporting\Report\Report.cs">
+      <Link>Reporting\Report\Report.cs</Link>
+    </Compile>
+    <Compile Include="..\OxyPlot\Reporting\Report\ReportItem.cs">
+      <Link>Reporting\Report\ReportItem.cs</Link>
+    </Compile>
+    <Compile Include="..\OxyPlot\Reporting\Report\ReportSection.cs">
+      <Link>Reporting\Report\ReportSection.cs</Link>
+    </Compile>
+    <Compile Include="..\OxyPlot\Reporting\Report\ReportStyle.cs">
+      <Link>Reporting\Report\ReportStyle.cs</Link>
+    </Compile>
+    <Compile Include="..\OxyPlot\Reporting\Report\Table.cs">
+      <Link>Reporting\Report\Table.cs</Link>
+    </Compile>
+    <Compile Include="..\OxyPlot\Reporting\Report\TableOfContents.cs">
+      <Link>Reporting\Report\TableOfContents.cs</Link>
+    </Compile>
+    <Compile Include="..\OxyPlot\Reporting\ReportWriters\HtmlReportWriter.cs">
+      <Link>Reporting\ReportWriters\HtmlReportWriter.cs</Link>
+    </Compile>
+    <Compile Include="..\OxyPlot\Reporting\ReportWriters\IReportWriter.cs">
+      <Link>Reporting\ReportWriters\IReportWriter.cs</Link>
+    </Compile>
+    <Compile Include="..\OxyPlot\Reporting\ReportWriters\StringExtensions.cs">
+      <Link>Reporting\ReportWriters\StringExtensions.cs</Link>
+    </Compile>
+    <Compile Include="..\OxyPlot\Reporting\ReportWriters\TextReportWriter.cs">
+      <Link>Reporting\ReportWriters\TextReportWriter.cs</Link>
+    </Compile>
+    <Compile Include="..\OxyPlot\Reporting\ReportWriters\WikiReportWriter.cs">
+      <Link>Reporting\ReportWriters\WikiReportWriter.cs</Link>
+    </Compile>
+    <Compile Include="..\OxyPlot\Series\AreaSeries.cs">
+      <Link>Series\AreaSeries.cs</Link>
+    </Compile>
+    <Compile Include="..\OxyPlot\Series\BoxPlotItem.cs">
+      <Link>Series\BoxPlotItem.cs</Link>
+    </Compile>
+    <Compile Include="..\OxyPlot\Series\BoxPlotSeries.cs">
+      <Link>Series\BoxPlotSeries.cs</Link>
+    </Compile>
+    <Compile Include="..\OxyPlot\Series\CandleStickSeries.cs">
+      <Link>Series\CandleStickSeries.cs</Link>
+    </Compile>
+    <Compile Include="..\OxyPlot\Series\ContourSeries.cs">
+      <Link>Series\ContourSeries.cs</Link>
+    </Compile>
+    <Compile Include="..\OxyPlot\Series\DataPointSeries.cs">
+      <Link>Series\DataPointSeries.cs</Link>
+    </Compile>
+    <Compile Include="..\OxyPlot\Series\FunctionSeries.cs">
+      <Link>Series\FunctionSeries.cs</Link>
+    </Compile>
+    <Compile Include="..\OxyPlot\Series\HeatMapSeries.cs">
+      <Link>Series\HeatMapSeries.cs</Link>
+    </Compile>
+    <Compile Include="..\OxyPlot\Series\HighLowItem.cs">
+      <Link>Series\HighLowItem.cs</Link>
+    </Compile>
+    <Compile Include="..\OxyPlot\Series\HighLowSeries.cs">
+      <Link>Series\HighLowSeries.cs</Link>
+    </Compile>
+    <Compile Include="..\OxyPlot\Series\ITrackableSeries.cs">
+      <Link>Series\ITrackableSeries.cs</Link>
+    </Compile>
+    <Compile Include="..\OxyPlot\Series\ItemsSeries.cs">
+      <Link>Series\ItemsSeries.cs</Link>
+    </Compile>
+    <Compile Include="..\OxyPlot\Series\LineLegendPosition.cs">
+      <Link>Series\LineLegendPosition.cs</Link>
+    </Compile>
+    <Compile Include="..\OxyPlot\Series\LineSeries.cs">
+      <Link>Series\LineSeries.cs</Link>
+    </Compile>
+    <Compile Include="..\OxyPlot\Series\PieSeries.cs">
+      <Link>Series\PieSeries.cs</Link>
+    </Compile>
+    <Compile Include="..\OxyPlot\Series\PieSlice.cs">
+      <Link>Series\PieSlice.cs</Link>
+    </Compile>
+    <Compile Include="..\OxyPlot\Series\ScatterPoint.cs">
+      <Link>Series\ScatterPoint.cs</Link>
+    </Compile>
+    <Compile Include="..\OxyPlot\Series\ScatterSeries.cs">
+      <Link>Series\ScatterSeries.cs</Link>
+    </Compile>
+    <Compile Include="..\OxyPlot\Series\Series.cs">
+      <Link>Series\Series.cs</Link>
+    </Compile>
+    <Compile Include="..\OxyPlot\Series\StairStepSeries.cs">
+      <Link>Series\StairStepSeries.cs</Link>
+    </Compile>
+    <Compile Include="..\OxyPlot\Series\StemSeries.cs">
+      <Link>Series\StemSeries.cs</Link>
+    </Compile>
+    <Compile Include="..\OxyPlot\Series\TwoColorLineSeries.cs">
+      <Link>Series\TwoColorLineSeries.cs</Link>
+    </Compile>
+    <Compile Include="..\OxyPlot\Series\XYAxisSeries.cs">
+      <Link>Series\XYAxisSeries.cs</Link>
+    </Compile>
+    <Compile Include="..\OxyPlot\Series\BarSeries\BarItem.cs">
+      <Link>Series\BarSeries\BarItem.cs</Link>
+    </Compile>
+    <Compile Include="..\OxyPlot\Series\BarSeries\BarItemBase.cs">
+      <Link>Series\BarSeries\BarItemBase.cs</Link>
+    </Compile>
+    <Compile Include="..\OxyPlot\Series\BarSeries\BarSeries.cs">
+      <Link>Series\BarSeries\BarSeries.cs</Link>
+    </Compile>
+    <Compile Include="..\OxyPlot\Series\BarSeries\BarSeriesBase.cs">
+      <Link>Series\BarSeries\BarSeriesBase.cs</Link>
+    </Compile>
+    <Compile Include="..\OxyPlot\Series\BarSeries\BarSeriesBase{T}.cs">
+      <Link>Series\BarSeries\BarSeriesBase{T}.cs</Link>
+    </Compile>
+    <Compile Include="..\OxyPlot\Series\BarSeries\CategorizedItem.cs">
+      <Link>Series\BarSeries\CategorizedItem.cs</Link>
+    </Compile>
+    <Compile Include="..\OxyPlot\Series\BarSeries\CategorizedSeries.cs">
+      <Link>Series\BarSeries\CategorizedSeries.cs</Link>
+    </Compile>
+    <Compile Include="..\OxyPlot\Series\BarSeries\ColumnItem.cs">
+      <Link>Series\BarSeries\ColumnItem.cs</Link>
+    </Compile>
+    <Compile Include="..\OxyPlot\Series\BarSeries\ColumnSeries.cs">
+      <Link>Series\BarSeries\ColumnSeries.cs</Link>
+    </Compile>
+    <Compile Include="..\OxyPlot\Series\BarSeries\ErrorColumnItem.cs">
+      <Link>Series\BarSeries\ErrorColumnItem.cs</Link>
+    </Compile>
+    <Compile Include="..\OxyPlot\Series\BarSeries\ErrorColumnSeries.cs">
+      <Link>Series\BarSeries\ErrorColumnSeries.cs</Link>
+    </Compile>
+    <Compile Include="..\OxyPlot\Series\BarSeries\IStackableSeries.cs">
+      <Link>Series\BarSeries\IStackableSeries.cs</Link>
+    </Compile>
+    <Compile Include="..\OxyPlot\Series\BarSeries\IntervalBarItem.cs">
+      <Link>Series\BarSeries\IntervalBarItem.cs</Link>
+    </Compile>
+    <Compile Include="..\OxyPlot\Series\BarSeries\IntervalBarSeries.cs">
+      <Link>Series\BarSeries\IntervalBarSeries.cs</Link>
+    </Compile>
+    <Compile Include="..\OxyPlot\Series\BarSeries\LabelPlacement.cs">
+      <Link>Series\BarSeries\LabelPlacement.cs</Link>
+    </Compile>
+    <Compile Include="..\OxyPlot\Series\BarSeries\RectangleBarItem.cs">
+      <Link>Series\BarSeries\RectangleBarItem.cs</Link>
+    </Compile>
+    <Compile Include="..\OxyPlot\Series\BarSeries\RectangleBarSeries.cs">
+      <Link>Series\BarSeries\RectangleBarSeries.cs</Link>
+    </Compile>
+    <Compile Include="..\OxyPlot\Series\BarSeries\TornadoBarItem.cs">
+      <Link>Series\BarSeries\TornadoBarItem.cs</Link>
+    </Compile>
+    <Compile Include="..\OxyPlot\Series\BarSeries\TornadoBarSeries.cs">
+      <Link>Series\BarSeries\TornadoBarSeries.cs</Link>
+    </Compile>
+    <Compile Include="..\OxyPlot\Svg\NativeMethods.cs">
+      <Link>Svg\NativeMethods.cs</Link>
+    </Compile>
+    <Compile Include="..\OxyPlot\Svg\SvgExporter.cs">
+      <Link>Svg\SvgExporter.cs</Link>
+    </Compile>
+    <Compile Include="..\OxyPlot\Svg\SvgRenderContext.cs">
+      <Link>Svg\SvgRenderContext.cs</Link>
+    </Compile>
+    <Compile Include="..\OxyPlot\Svg\SvgWriter.cs">
+      <Link>Svg\SvgWriter.cs</Link>
+    </Compile>
+  </ItemGroup>
+  <ItemGroup>
+    <None Include="..\OxyPlot\ClassDiagrams\PlotModel.cd">
+      <Link>ClassDiagrams\PlotModel.cd</Link>
+    </None>
+    <None Include="..\OxyPlot\ClassDiagrams\Reporting.cd">
+      <Link>ClassDiagrams\Reporting.cd</Link>
+    </None>
+    <None Include="..\OxyPlot\ClassDiagrams\Series.cd">
+      <Link>ClassDiagrams\Series.cd</Link>
+    </None>
+  </ItemGroup>
+  <ItemGroup>
+    <Folder Include="MouseActions\" />
+  </ItemGroup>
+</Project>
diff --git a/oxyplot/OxyPlotMono/OxyPlotMono.userprefs b/oxyplot/OxyPlotMono/OxyPlotMono.userprefs
new file mode 100644
index 0000000..802099d
--- /dev/null
+++ b/oxyplot/OxyPlotMono/OxyPlotMono.userprefs
@@ -0,0 +1,12 @@
+<Properties>
+  <MonoDevelop.Ide.Workspace ActiveConfiguration="Debug" />
+  <MonoDevelop.Ide.Workbench ActiveDocument="../OxyPlot/Foundation/XmlWriterBase.cs">
+    <Files>
+      <File FileName="../OxyPlot/Foundation/XmlWriterBase.cs" Line="35" Column="18" />
+    </Files>
+  </MonoDevelop.Ide.Workbench>
+  <MonoDevelop.Ide.DebuggingService.Breakpoints>
+    <BreakpointStore />
+  </MonoDevelop.Ide.DebuggingService.Breakpoints>
+  <MonoDevelop.Ide.DebuggingService.PinnedWatches />
+</Properties>
\ No newline at end of file
diff --git a/oxyplot/OxyPlotMono/bin/Debug/OxyPlotMono.dll b/oxyplot/OxyPlotMono/bin/Debug/OxyPlotMono.dll
new file mode 100755
index 0000000..4ab05f1
Binary files /dev/null and b/oxyplot/OxyPlotMono/bin/Debug/OxyPlotMono.dll differ
diff --git a/oxyplot/OxyPlotMono/bin/Debug/OxyPlotMono.dll.mdb 
b/oxyplot/OxyPlotMono/bin/Debug/OxyPlotMono.dll.mdb
new file mode 100644
index 0000000..92cf7e2
Binary files /dev/null and b/oxyplot/OxyPlotMono/bin/Debug/OxyPlotMono.dll.mdb differ



[Date Prev][Date Next]   [Thread Prev][Thread Next]   [Thread Index] [Date Index] [Author Index]