diff --git a/Source/Examples/DrawingLibrary/DrawingLibrary.csproj b/Source/Examples/DrawingLibrary/DrawingLibrary.csproj new file mode 100644 index 000000000..7765c1427 --- /dev/null +++ b/Source/Examples/DrawingLibrary/DrawingLibrary.csproj @@ -0,0 +1,39 @@ + + + + net47 + OxyPlot.ExampleLibrary + True + Example models for OxyPlot. + https://raw.githubusercontent.com/oxyplot/oxyplot/master/LICENSE + OxyPlot contributors + http://oxyplot.org/ + https://raw.githubusercontent.com/oxyplot/oxyplot/develop/Icons/OxyPlot_128.png + plotting plot charting chart + git + https://github.com/oxyplot/oxyplot.git + + + + + + + + + + + + + + + + + + + + + + + + + \ No newline at end of file diff --git a/Source/Examples/DrawingLibrary/Example.cs b/Source/Examples/DrawingLibrary/Example.cs new file mode 100644 index 000000000..062d89909 --- /dev/null +++ b/Source/Examples/DrawingLibrary/Example.cs @@ -0,0 +1,18 @@ +namespace DrawingDemo +{ + using OxyPlot; + using OxyPlot.Drawing; + + public class Example + { + public Example(DrawingModel model, IController controller = null) + { + this.Model = model; + this.Controller = controller; + } + + public DrawingModel Model { get; set; } + + public IController Controller { get; set; } + } +} \ No newline at end of file diff --git a/Source/Examples/DrawingLibrary/ExampleAttribute.cs b/Source/Examples/DrawingLibrary/ExampleAttribute.cs new file mode 100644 index 000000000..402fd5070 --- /dev/null +++ b/Source/Examples/DrawingLibrary/ExampleAttribute.cs @@ -0,0 +1,14 @@ +namespace DrawingDemo +{ + using System; + + public class ExampleAttribute : Attribute + { + public ExampleAttribute(string title) + { + this.Title = title; + } + + public string Title { get; set; } + } +} \ No newline at end of file diff --git a/Source/Examples/DrawingLibrary/ExampleInfo.cs b/Source/Examples/DrawingLibrary/ExampleInfo.cs new file mode 100644 index 000000000..f296b0a2c --- /dev/null +++ b/Source/Examples/DrawingLibrary/ExampleInfo.cs @@ -0,0 +1,39 @@ +namespace DrawingDemo +{ + using System; + + using OxyPlot.Drawing; + + public class ExampleInfo + { + private readonly Func exampleGetter; + + private Example example; + + public ExampleInfo(string title, Func exampleGetter) + { + this.exampleGetter = exampleGetter; + this.Title = title; + } + + public string Title { get; set; } + + public DrawingModel Model + { + get + { + if (this.example == null) + { + this.example = this.exampleGetter(); + } + + return this.example.Model; + } + } + + public override string ToString() + { + return this.Title; + } + } +} \ No newline at end of file diff --git a/Source/Examples/DrawingLibrary/Examples.cs b/Source/Examples/DrawingLibrary/Examples.cs new file mode 100644 index 000000000..d2f7f6ec7 --- /dev/null +++ b/Source/Examples/DrawingLibrary/Examples.cs @@ -0,0 +1,28 @@ +namespace DrawingDemo +{ + using System.Collections.Generic; + using System.Linq; + using System.Reflection; + + public static class Examples + { + public static IEnumerable Get() + { + foreach (var type in typeof(Examples).GetTypeInfo().Assembly.DefinedTypes) + { + foreach (var method in type.AsType().GetRuntimeMethods()) + { + var exampleAttributes = method.GetCustomAttributes(typeof(ExampleAttribute), true).ToArray(); + if (exampleAttributes.Length == 1) + { + var m = method; + yield return + new ExampleInfo( + ((ExampleAttribute)exampleAttributes[0]).Title, + () => (Example)m.Invoke(null, null)); + } + } + } + } + } +} diff --git a/Source/Examples/DrawingLibrary/Examples/AirfoilExamples/AirfoilExamples.cs b/Source/Examples/DrawingLibrary/Examples/AirfoilExamples/AirfoilExamples.cs new file mode 100644 index 000000000..64c5b3424 --- /dev/null +++ b/Source/Examples/DrawingLibrary/Examples/AirfoilExamples/AirfoilExamples.cs @@ -0,0 +1,56 @@ +namespace DrawingLibrary.Examples +{ + using System.Collections.Generic; + using System.Linq; + + using DrawingDemo; + + using OxyPlot; + using OxyPlot.Drawing; + + public static class AirfoilExamples + { + [Example("NACA 0012")] + public static Example Naca0012() + { + return Naca4("0012"); + } + + [Example("NACA 2412")] + public static Example Naca2412() + { + return Naca4("2412"); + } + + [Example("NACA 6412")] + public static Example Naca6412() + { + return Naca4("6412"); + } + + public static Example Naca4(string id) + { + var airfoil = new NacaAirfoil(id); + DataPoint[] camberLine; + DataPoint[] upper; + DataPoint[] lower; + DataPoint[] thickness; + airfoil.GetProfile(81, 100, out camberLine, out thickness, out upper, out lower); + + var profile = new List(upper.Reverse()); + profile.AddRange(lower); + + var drawing = new DrawingModel() { Background = OxyColor.FromRgb(0, 128, 196) }; + drawing.Add(new Grid() { MajorColor = OxyColor.FromAColor(20, OxyColors.White), MinorColor = OxyColor.FromAColor(10, OxyColors.White) }); + drawing.Add(new Polygon(profile) { Stroke = OxyColors.Blue, Fill = OxyColor.FromAColor(30, OxyColors.White), Thickness = -2 }); + drawing.Add(new Polyline(camberLine) { Color = OxyColors.Red, Thickness = -2 }); + drawing.Add(new Polyline(thickness) { Color = OxyColors.Purple, Thickness = -2 }); + drawing.Add(new Text { Point = new DataPoint(0, 20), Content = "Airfoil example", FontSize = 4, FontWeight = FontWeights.Bold }); + drawing.Add(new Text { Point = new DataPoint(0, -7), Content = airfoil.ToString(), FontSize = 3, FontWeight = FontWeights.Bold }); + drawing.Add(new Text { Point = new DataPoint(80, -4), Content = "Camber line", FontSize = 2, Color = OxyColors.Red }); + drawing.Add(new Text { Point = new DataPoint(80, -7), Content = "Thickness", FontSize = 2, Color = OxyColors.Purple }); + drawing.Add(new Rectangle { MinimumX = -2, MaximumX = 102, MinimumY = -12, MaximumY = 22, Stroke = OxyColors.Black }); + return new Example(drawing); + } + } +} diff --git a/Source/Examples/DrawingLibrary/Examples/AirfoilExamples/NacaAirfoil.cs b/Source/Examples/DrawingLibrary/Examples/AirfoilExamples/NacaAirfoil.cs new file mode 100644 index 000000000..92f834f5c --- /dev/null +++ b/Source/Examples/DrawingLibrary/Examples/AirfoilExamples/NacaAirfoil.cs @@ -0,0 +1,78 @@ +namespace DrawingLibrary.Examples +{ + using System; + + using OxyPlot; + + public class NacaAirfoil + { + public NacaAirfoil() + { + this.MaximumCamber = 0.02; + this.PositionOfMaximumCamber = 0.4; + this.Thickness = 0.12; + } + + public NacaAirfoil(string id) + { + this.MaximumCamber = int.Parse(id.Substring(0, 1)) * 0.01; + this.PositionOfMaximumCamber = int.Parse(id.Substring(1, 1)) * 0.1; + this.Thickness = int.Parse(id.Substring(2, 2)) * 0.01; + } + + public double Thickness { get; set; } + + public double MaximumCamber { get; set; } + + public double PositionOfMaximumCamber { get; set; } + + public override string ToString() + { + return string.Format("NACA {0}{1}{2}", (int)(this.MaximumCamber * 100), (int)(this.PositionOfMaximumCamber * 10), (int)(this.Thickness * 100)); + } + + public void GetProfile(int n, double c, out DataPoint[] camberLine, out DataPoint[] thickness, out DataPoint[] upper, out DataPoint[] lower) + { + camberLine = new DataPoint[n]; + for (int i = 0; i < n; i++) + { + double beta = Math.PI * i / (n - 1); + double x = c * (1 - Math.Cos(beta)) / 2; + camberLine[i] = new DataPoint(x, Yc(c, x, this.MaximumCamber, this.PositionOfMaximumCamber)); + } + + upper = new DataPoint[n]; + lower = new DataPoint[n]; + thickness = new DataPoint[n]; + + for (int i = 0; i < n; i++) + { + var i0 = i > 0 ? i - 1 : i; + var i1 = i < n - 1 ? i + 1 : i; + var theta = Math.Atan2(camberLine[i1].Y - camberLine[i0].Y, camberLine[i1].X - camberLine[i0].X); + + double x = camberLine[i].X; + var yt = Yt(c, x, this.Thickness); + thickness[i] = new DataPoint(x, yt); + upper[i] = new DataPoint(x - yt * Math.Sin(theta), camberLine[i].Y + yt * Math.Cos(theta)); + lower[i] = new DataPoint(x + yt * Math.Sin(theta), camberLine[i].Y - yt * Math.Cos(theta)); + } + } + + private static double Yt(double c, double x, double t) + { + var xc = x / c; + return t / 0.2 * c * ((0.2969 * Math.Sqrt(xc)) - (0.126 * xc) - (0.3516 * xc * xc) + (0.2843 * xc * xc * xc) - (0.1015 * xc * xc * xc * xc)); + } + + private static double Yc(double c, double x, double m, double p) + { + if (x < p * c) + { + return m * x / (p * p) * ((2 * p) - (x / c)); + } + + return m * (c - x) / ((1 - p) * (1 - p)) * (1 + (x / c) - (2 * p)); + } + } +} diff --git a/Source/Examples/DrawingLibrary/Examples/BezierExamples.cs b/Source/Examples/DrawingLibrary/Examples/BezierExamples.cs new file mode 100644 index 000000000..f149b6e42 --- /dev/null +++ b/Source/Examples/DrawingLibrary/Examples/BezierExamples.cs @@ -0,0 +1,220 @@ +namespace DrawingDemo +{ + using System; + using System.Collections.Generic; + using System.Linq; + + using OxyPlot; + using OxyPlot.Drawing; + + public static class BezierExamples + { + [Example("Bzier curve (by De Casteljau's algorithm)")] + public static Example BzierDeCasteljau() + { + // https://en.wikipedia.org/wiki/De_Casteljau's_algorithm + // http://pomax.github.io/bezierinfo/ + Func, double, DataPoint> bezier = (points, t) => + { + while (points.Count() > 1) + { + var newPoints = new DataPoint[points.Count - 1]; + for (int i = 0; i < newPoints.Length; i++) + { + newPoints[i] = new DataPoint(((1 - t) * points[i].X) + (t * points[i + 1].X), ((1 - t) * points[i].Y) + (t * points[i + 1].Y)); + } + + points = newPoints; + } + + return points[0]; + }; + + var controlPoints = new[] { new DataPoint(65, 25), new DataPoint(5, 150), new DataPoint(80, 290), new DataPoint(220, 235), new DataPoint(250, 150), new DataPoint(135, 125) }; + return CreateBezierExample(controlPoints, bezier); + } + + [Example("Bzier curve (3 control points)")] + public static Example Bzier3() + { + // http://paulbourke.net/geometry/bezier/index.html + Func, double, DataPoint> bezier3 = (p, mu) => + { + var mu2 = mu * mu; + var mum1 = 1 - mu; + var mum12 = mum1 * mum1; + + return new DataPoint(p[0].X * mum12 + 2 * p[1].X * mum1 * mu + p[2].X * mu2, p[0].Y * mum12 + 2 * p[1].Y * mum1 * mu + p[2].Y * mu2); + }; + + var controlPoints = new[] { new DataPoint(65, 25), new DataPoint(5, 150), new DataPoint(80, 290) }; + return CreateBezierExample(controlPoints, bezier3); + } + + [Example("Bzier curve (4 control points)")] + public static Example Bzier4() + { + // http://paulbourke.net/geometry/bezier/index.html + Func, double, DataPoint> bezier4 = (p, mu) => + { + var mum1 = 1 - mu; + var mum13 = mum1 * mum1 * mum1; + var mu3 = mu * mu * mu; + var p1 = p[0]; + var p2 = p[1]; + var p3 = p[2]; + var p4 = p[3]; + var px = mum13 * p1.X + 3 * mu * mum1 * mum1 * p2.X + 3 * mu * mu * mum1 * p3.X + mu3 * p4.X; + var py = mum13 * p1.Y + 3 * mu * mum1 * mum1 * p2.Y + 3 * mu * mu * mum1 * p3.Y + mu3 * p4.Y; + + return new DataPoint(px, py); + }; + + var controlPoints = new[] { new DataPoint(65, 25), new DataPoint(5, 150), new DataPoint(80, 290), new DataPoint(220, 235) }; + return CreateBezierExample(controlPoints, bezier4); + } + + [Example("Bzier curve (cubic)")] + public static Example CubicBzier() + { + // http://paulbourke.net/geometry/bezier/index.html + Func, double, DataPoint> cubicBezier = (p, mu) => + { + // Piecewise cubic bezier curve as defined by Adobe in Postscript + // The two end points are p0 and p3 + // Their associated control points are p1 and p2 + var p0 = p[0]; + var p1 = p[1]; + var p2 = p[2]; + var p3 = p[3]; + + var cx = 3 * (p1.X - p0.X); + var cy = 3 * (p1.Y - p0.Y); + var bx = 3 * (p2.X - p1.X) - cx; + var by = 3 * (p2.Y - p1.Y) - cy; + var ax = p3.X - p0.X - cx - bx; + var ay = p3.Y - p0.Y - cy - by; + + var px = ax * mu * mu * mu + bx * mu * mu + cx * mu + p0.X; + var py = ay * mu * mu * mu + by * mu * mu + cy * mu + p0.Y; + + return new DataPoint(px, py); + }; + + var controlPoints = new[] { new DataPoint(65, 25), new DataPoint(5, 150), new DataPoint(80, 290), new DataPoint(220, 235) }; + return CreateBezierExample(controlPoints, cubicBezier); + } + + [Example("Bzier curve (general)")] + public static Example GeneralBzier() + { + // http://paulbourke.net/geometry/bezier/index.html + Func, double, DataPoint> solveBezier = (p, mu) => + { + if (1 - mu < 1e-8) + { + return p.Last(); + } + + int k, kn, nn, nkn; + double blend, muk, munk; + double bx = 0, by = 0; + int n = p.Count - 1; + + muk = 1; + munk = Math.Pow(1 - mu, n); + + for (k = 0; k <= n; k++) + { + nn = n; + kn = k; + nkn = n - k; + blend = muk * munk; + muk *= mu; + munk /= (1 - mu); + while (nn >= 1) + { + blend *= nn; + nn--; + if (kn > 1) + { + blend /= kn; + kn--; + } + + if (nkn > 1) + { + blend /= nkn; + nkn--; + } + } + + bx += p[k].X * blend; + by += p[k].Y * blend; + } + + return new DataPoint(bx, by); + }; + + var controlPoints = new[] { new DataPoint(65, 25), new DataPoint(5, 150), new DataPoint(80, 290) }; //, new DataPoint(220, 235), new DataPoint(250, 150), new DataPoint(135, 125) }; + + return CreateBezierExample(controlPoints, solveBezier); + } + + private static Example CreateBezierExample(DataPoint[] initialPoints, Func, double, DataPoint> solveBezier) + { + var drawing = new DrawingModel(); + var bezierLine = new Polyline { Thickness = 2, Color = OxyColors.Green }; + var controlPointsLine = new Polyline { Thickness = 2, Color = OxyColors.Red }; + drawing.Add(bezierLine); + drawing.Add(controlPointsLine); + var controlPoints = new List(); + var evaluatedPoints = new List(); + + Action update = () => + { + foreach (var e in evaluatedPoints) + { + drawing.Remove(e); + } + + controlPointsLine.Points.Clear(); + controlPointsLine.Points.AddRange(controlPoints.Select(c => c.Center)); + + var bezierPoints = CreateCurve(controlPointsLine.Points, 100, solveBezier); + bezierLine.Points.Clear(); + bezierLine.Points.AddRange(bezierPoints); + + foreach (var p in bezierPoints) + { + evaluatedPoints.Add(drawing.AddPoint(p, OxyColors.White, 1, 0.8)); + } + + drawing.Invalidate(); + }; + + foreach (var p in initialPoints) + { + var cp = drawing.AddPoint(p, OxyColors.Blue, radius: 3); + cp.OnDragged(update); + controlPoints.Add(cp); + } + + update(); + + return new Example(drawing); + } + + private static DataPoint[] CreateCurve(IList controlPoints, int n, Func, double, DataPoint> solver) + { + var points = new DataPoint[n]; + for (int i = 0; i < n; i++) + { + double t = (double)i / (n - 1); + points[i] = solver(controlPoints, t); + } + + return points; + } + } +} \ No newline at end of file diff --git a/Source/Examples/DrawingLibrary/Examples/CircleExamples.cs b/Source/Examples/DrawingLibrary/Examples/CircleExamples.cs new file mode 100644 index 000000000..d62c3f92d --- /dev/null +++ b/Source/Examples/DrawingLibrary/Examples/CircleExamples.cs @@ -0,0 +1,67 @@ +namespace DrawingDemo +{ + using System; + + using OxyPlot; + using OxyPlot.Drawing; + + public static class CircleExamples + { + [Example("Circle from three points")] + public static Example CircleFromThreePoints() + { + var drawing = new DrawingModel(); + + var p1 = new DataPoint(0, 0); + var p2 = new DataPoint(100, 20); + var p3 = new DataPoint(50, 50); + + var circle = new Ellipse { Fill = OxyColors.LightGray, Stroke = OxyColors.LightBlue, Thickness = -2 }; + drawing.Add(circle); + + var h1 = drawing.AddPoint(p1, OxyColors.LightBlue); + var h2 = drawing.AddPoint(p2, OxyColors.LightBlue); + var h3 = drawing.AddPoint(p3, OxyColors.LightBlue); + + Action updateCircle = () => + { + DataPoint c; + double r; + FindCircle(h1.Center, h2.Center, h3.Center, out c, out r); + circle.Center = c; + circle.RadiusX = circle.RadiusY = r; + drawing.Invalidate(); + }; + + updateCircle(); + h1.OnDragged(updateCircle); + h2.OnDragged(updateCircle); + h2.OnDragged(updateCircle); + return new Example(drawing); + } + + public static void FindCircle(DataPoint a, DataPoint b, DataPoint c, out DataPoint cc, out double r) + { + // Get the perpendicular bisector of (x1, y1) and (x2, y2). + var x1 = (b.X + a.X) / 2; + var y1 = (b.Y + a.Y) / 2; + var dy1 = b.X - a.X; + var dx1 = -(b.Y - a.Y); + + // Get the perpendicular bisector of (x2, y2) and (x3, y3). + var x2 = (c.X + b.X) / 2; + var y2 = (c.Y + b.Y) / 2; + var dy2 = c.X - b.X; + var dx2 = -(c.Y - b.Y); + + // See where the lines intersect. + var cx = ((y1 * dx1 * dx2) + (x2 * dx1 * dy2) - (x1 * dy1 * dx2) - (y2 * dx1 * dx2)) / ((dx1 * dy2) - (dy1 * dx2)); + var cy = ((cx - x1) * dy1 / dx1) + y1; + + var dx = cx - a.X; + var dy = cy - a.Y; + cc = new DataPoint(cx, cy); + r = Math.Sqrt((dx * dx) + (dy * dy)); + } + } +} \ No newline at end of file diff --git a/Source/Examples/DrawingLibrary/Examples/ExtensionMethods.cs b/Source/Examples/DrawingLibrary/Examples/ExtensionMethods.cs new file mode 100644 index 000000000..717fe4cb2 --- /dev/null +++ b/Source/Examples/DrawingLibrary/Examples/ExtensionMethods.cs @@ -0,0 +1,75 @@ +namespace DrawingDemo +{ + using System; + + using OxyPlot; + using OxyPlot.Drawing; + + public static class ExtensionMethods + { + public static Ellipse AddPoint(this DrawingModel drawing, DataPoint p, OxyColor color, double alpha = 0.25, double radius = 1) + { + var ellipse = new Ellipse + { + Center = p, + RadiusX = radius, + RadiusY = radius, + Stroke = color, + Thickness = -2, + Fill = OxyColor.FromAColor((byte)(alpha * 255), color) + }; + drawing.Add(ellipse); + return ellipse; + } + + public static void AddCross(this DrawingModel drawing, double x, double y, OxyColor color, double size = 1, double thickness = 0.1) + { + drawing.Add(new Lines( + new[] + { + new DataPoint(x - size, y), new DataPoint(x + size, y), new DataPoint(x, y - size), + new DataPoint(x, y + size) + }) { Color = color, Thickness = thickness }); + } + + public static void OnDragged(this Ellipse ellipse, Action changed) + { + var downPoint = ScreenPoint.Undefined; + var dragging = false; + double originalSize = 0; + ellipse.MouseDown += (s, e) => + { + originalSize = ellipse.RadiusX; + ellipse.RadiusX = ellipse.RadiusY = originalSize * 1.2; + changed(); + downPoint = e.Position; + e.Handled = true; + }; + ellipse.MouseUp += (s, e) => + { + ellipse.RadiusX = ellipse.RadiusY = originalSize; + changed(); + dragging = false; + e.Handled = true; + }; + ellipse.MouseMove += (s, e) => + { + if (!dragging && (e.Position - downPoint).Length > 10) + { + dragging = true; + } + + if (dragging) + { + var view = (IDrawingView)e.View; + var vm = view.ActualViewModel; + ellipse.Center = vm.InverseTransform(e.Position); + changed(); + } + + e.Handled = true; + }; + } + + } +} \ No newline at end of file diff --git a/Source/Examples/DrawingLibrary/Examples/IntersectionExamples.cs b/Source/Examples/DrawingLibrary/Examples/IntersectionExamples.cs new file mode 100644 index 000000000..74c6c9ade --- /dev/null +++ b/Source/Examples/DrawingLibrary/Examples/IntersectionExamples.cs @@ -0,0 +1,77 @@ +namespace DrawingDemo +{ + using System; + using System.Collections.Generic; + + using OxyPlot; + using OxyPlot.Drawing; + + public static class IntersectionExamples + { + [Example("Intersection of two circles")] + public static Example IntersectionOfTwoCircles() + { + // http://paulbourke.net/geometry/circlesphere/ + var drawing = new DrawingModel(); + drawing.Add(new Ellipse { Center = new DataPoint(0, 0), RadiusX = 6, RadiusY = 6 }); + drawing.Add(new Ellipse { Center = new DataPoint(5, 1), RadiusX = 7, RadiusY = 7 }); + var p0 = new DataPoint(0, 0); + var p1 = new DataPoint(5, 1); + foreach (var i in GetCircleCircleIntersections(p0, p1, 6, 7)) + { + drawing.AddPoint(i, OxyColors.Red); + } + + return new Example(drawing); + } + + [Example("Intersection of line and circle")] + public static Example IntersectionOfLineAndCircles() + { + // http://paulbourke.net/geometry/circlesphere/ + var drawing = new DrawingModel(); + drawing.Add(new Ellipse { Center = new DataPoint(0, 0), RadiusX = 6, RadiusY = 6 }); + drawing.Add(new Lines(-8, 0, 12, 3)); + foreach (var i in GetRayCircleIntersections(new DataPoint(-8, 0), new DataPoint(12, 3), new DataPoint(0, 0), 6)) + { + drawing.AddPoint(i, OxyColors.Red); + } + + return new Example(drawing); + } + + private static IEnumerable GetCircleCircleIntersections(DataPoint p0, DataPoint p1, double r0, double r1) + { + var d = p0.DistanceTo(p1); + var a = (r0 * r0 - r1 * r1 + d * d) / (2 * d); + var h = Math.Sqrt(r0 * r0 - a * a); + var p2 = new DataPoint(p0.X + a * (p1.X - p0.X) / d, p0.Y + a * (p1.Y - p0.Y) / d); + yield return new DataPoint(p2.X + h * (p1.Y - p0.Y) / d, p2.Y - h * (p1.X - p0.X) / d); + yield return new DataPoint(p2.X - h * (p1.Y - p0.Y) / d, p2.Y + h * (p1.X - p0.X) / d); + } + + private static IEnumerable GetRayCircleIntersections(DataPoint p1, DataPoint p2, DataPoint sc, double r) + { + double bb4ac; + + var dx = p2.X - p1.X; + var dy = p2.Y - p1.Y; + var a = dx * dx + dy * dy; + var b = 2 * (dx * (p1.X - sc.X) + dy * (p1.Y - sc.Y)); + var c = sc.X * sc.X + sc.Y * sc.Y; + c += p1.X * p1.X + p1.Y * p1.Y; + c -= 2 * (sc.X * p1.X + sc.Y * p1.Y); + c -= r * r; + bb4ac = b * b - 4 * a * c; + if (Math.Abs(a) < 1e-8 || bb4ac < 0) + { + yield break; + } + + var mu1 = (-b + Math.Sqrt(bb4ac)) / (2 * a); + var mu2 = (-b - Math.Sqrt(bb4ac)) / (2 * a); + yield return new DataPoint(p1.X + mu1 * dx, p1.Y + mu1 * dy); + yield return new DataPoint(p1.X + mu2 * dx, p1.Y + mu2 * dy); + } + } +} \ No newline at end of file diff --git a/Source/Examples/DrawingLibrary/Examples/MiscExamples.cs b/Source/Examples/DrawingLibrary/Examples/MiscExamples.cs new file mode 100644 index 000000000..f9e6710b5 --- /dev/null +++ b/Source/Examples/DrawingLibrary/Examples/MiscExamples.cs @@ -0,0 +1,384 @@ +namespace DrawingDemo +{ + using System; + + using OxyPlot; + using OxyPlot.Drawing; + + public static class MiscExamples + { + [Example("Planets")] + public static Example Planets() + { + var drawing = new DrawingModel(); + var au = 1.496e11; + Action add = + (name, distance, radius, color) => + drawing.Add( + new Ellipse + { + RadiusX = radius / au, + RadiusY = radius / au, + Center = new DataPoint(distance / au, 0), + Fill = color, + Text = name + }); + add("Sun", 0, 696342e3, OxyColors.Yellow); + add("Mercury", 0.4 * au, 2439.7e3, OxyColors.Maroon); + add("Venus", 0.7 * au, 6051.8e3, OxyColors.Violet); + add("Earth", 1 * au, 6371e3, OxyColors.AliceBlue); + add("Mars", 1.5 * au, 3389.5e3, OxyColors.Magenta); + add("Jupiter", 5.2 * au, 69911e3, OxyColors.Peru); + add("Saturn", 9.5 * au, 58232e3, OxyColors.Salmon); + add("Uranus", 19.2 * au, 25362e3, OxyColors.OrangeRed); + add("Neptune", 30 * au, 24622e3, OxyColors.Blue); + add("Pluto", 39 * au, 1184e3, OxyColors.Black); + + return new Example(drawing); + } + + [Example("Grid")] + public static Example Grid() + { + var drawing = new DrawingModel(); + drawing.Add(new Grid()); + for (int i = 10; i <= 50; i += 5) + { + drawing.Add(new Ellipse { Center = new DataPoint(i, 0), RadiusX = i, RadiusY = i }); + } + + return new Example(drawing); + } + + [Example("Optical illusion")] + public static Example OpticalIllusion() + { + var drawing = new DrawingModel(); + drawing.Background = OxyColors.Black; + int n = 10; + + for (int i = 0; i + 1 < n; i++) + { + for (int j = 0; j < 5; j++) + { + double x = 1.5 + Math.Sin(i * Math.PI * 2 / (n - 1)) * 1 + j * 3; + drawing.Add( + new Rectangle + { + MinimumX = x, + MinimumY = i, + MaximumX = x + 1, + MaximumY = i + 1, + Fill = OxyColors.White + }); + } + } + + for (int i = 0; i < n; i++) + { + drawing.Add(new Lines(0, i, 16, i) { Color = OxyColors.Gray, Thickness = -2 }); + } + + return new Example(drawing); + } + + [Example("Arrows")] + public static Example Arrows() + { + var drawing = new DrawingModel(); + drawing.Add(new Arrow { StartPoint = new DataPoint(0, 0), EndPoint = new DataPoint(40, 10) }); + drawing.Add(new Arrow { StartPoint = new DataPoint(0, 10), EndPoint = new DataPoint(40, 20), Veeness = 0 }); + drawing.Add(new Arrow { StartPoint = new DataPoint(0, 20), EndPoint = new DataPoint(40, 30), Veeness = -1 }); + return new Example(drawing); + } + + [Example("Snurr")] + public static Example Snurr() + { + var p = new DataPoint[5]; + p[0] = new DataPoint(0, 0); + p[1] = new DataPoint(1, 0); + p[2] = new DataPoint(1, 1); + p[3] = new DataPoint(0, 1); + p[4] = p[0]; + var drawing = new DrawingModel { Background = OxyColors.Black }; + Func lerp = (p1, p2, f) => new DataPoint(p1.X * (1 - f) + p2.X * f, p1.Y * (1 - f) + p2.Y * f); + for (int i = 0; i < 255; i++) + { + var c = OxyColor.FromHsv(Math.Abs(Math.Sin(i * 0.03)), 1, 1); + drawing.Add(new Polyline(p) { Color = c, Thickness = -1.8 }); + p[1] = lerp(p[1], p[2], 0.02); + p[2] = lerp(p[2], p[3], 0.02); + p[3] = lerp(p[3], p[0], 0.02); + p[0] = lerp(p[0], p[1], 0.02); + p[4] = p[0]; + } + + return new Example(drawing); + } + + [Example("Blueprint")] + public static Example Blueprint() + { + var drawing = new DrawingModel { Background = OxyColor.FromRgb(0, 128, 196) }; + drawing.Add( + new RoundedRectangle + { + MinimumX = 0, + MinimumY = 0, + MaximumX = 300, + MaximumY = 200, + CornerRadius = 3, + Stroke = OxyColors.White, + Fill = OxyColor.FromAColor(20, OxyColors.White) + }); + + for (int i = 1; i < 30; i++) + { + drawing.Add(new Lines(i * 10, 30, i * 10, 200) { Color = OxyColor.FromAColor(50, OxyColors.White), Thickness = 0.1 }); + } + + for (int i = 4; i < 20; i++) + { + drawing.Add(new Lines(0, i * 10, 300, i * 10) { Color = OxyColor.FromAColor(50, OxyColors.White), Thickness = 0.1 }); + } + + drawing.Add(new Lines(0, 30, 300, 30) { Color = OxyColors.White, Aliased = true }); + drawing.Add(new Lines(200, 0, 200, 30) { Color = OxyColors.White, Aliased = true }); + drawing.Add(new Lines(200, 15, 300, 15) { Color = OxyColors.White, Aliased = true }); + drawing.Add(new Text { Point = new DataPoint(5, 195), Content = "TOP VIEW", Color = OxyColors.White }); + drawing.Add( + new Text + { + Point = new DataPoint(5, 20), + Content = "OxyPlot drawing model", + Color = OxyColors.White, + FontSize = 10, + FontWeight = FontWeights.Bold + }); + drawing.Add( + new Text { Point = new DataPoint(205, 27), Content = "NAME", Color = OxyColors.White, FontSize = 6 }); + drawing.Add( + new Text + { + Point = new DataPoint(205, 12), + Content = DateTime.Now.ToString("yyyy-MM-dd"), + Color = OxyColors.White, + FontSize = 6 + }); + return new Example(drawing); + } + + [Example("Genealogy tree")] + public static Example GenealogyTree() + { + var drawing = new DrawingModel(); + var ystein = new Person( + "ystein", + new Person( + "Olav", + new Person( + "Sigurd", + new Person("Martin", new Person("Olav"), new Person("Marta")), + new Person("Brita", new Person("Trond"), new Person("Helga"))), + new Person( + "Hjrdis", + new Person("Ola", new Person("Jon"), new Person("Anna")), + new Person("Guro", new Person("Nils"), new Person("Blansa")))), + new Person( + "Sylvi", + new Person( + "Jonas", + new Person("Peder", new Person("Kristoffer"), new Person("Karen")), + new Person("Guri", new Person("Aslak"), new Person("Johanne"))), + new Person( + "Eline Brynhild", + new Person("Johan", new Person("Bernt"), new Person("Eline")), + new Person("Susanne", new Person("Severin"), new Person("Ragnhild"))))); + + ystein.Render(drawing, 1, -10, 190); + + return new Example(drawing); + } + + /// + /// Shows a venn diagram. + /// + /// An example definition. + /// + [Example("Venn diagram")] + public static Example Diagram() + { + var drawing = new DrawingModel(); + + drawing.Add( + new Text + { + Point = new DataPoint(0, 460), + Content = "HOW WOULD YOU LIKE", + Color = OxyColors.Black, + FontSize = 60, + FontWeight = FontWeights.Bold, + HorizontalAlignment = HorizontalAlignment.Center, + VerticalAlignment = OxyPlot.VerticalAlignment.Middle + }); + drawing.Add( + new Text + { + Point = new DataPoint(0, 400), + Content = "YOUR GRAPHIC DESIGN?", + Color = OxyColors.Black, + FontSize = 60, + FontWeight = FontWeights.Bold, + HorizontalAlignment = HorizontalAlignment.Center, + VerticalAlignment = OxyPlot.VerticalAlignment.Middle + }); + drawing.Add( + new Text + { + Point = new DataPoint(0, 350), + Content = "(YOU MAY PICK TWO)", + Color = OxyColors.Black, + FontSize = 20, + FontWeight = FontWeights.Bold, + HorizontalAlignment = HorizontalAlignment.Center, + VerticalAlignment = OxyPlot.VerticalAlignment.Middle + }); + + drawing.Add( + new Ellipse + { + Center = new DataPoint(-120, 100), + RadiusX = 185, + RadiusY = 185, + Fill = OxyColor.FromAColor(180, OxyColors.Red) + }); + drawing.Add( + new Ellipse + { + Center = new DataPoint(120, 100), + RadiusX = 185, + RadiusY = 185, + Fill = OxyColor.FromAColor(180, OxyColors.Gold) + }); + drawing.Add( + new Ellipse + { + Center = new DataPoint(0, 100 - 230), + RadiusX = 185, + RadiusY = 185, + Fill = OxyColor.FromAColor(180, OxyColors.SkyBlue) + }); + drawing.Add( + new Ellipse + { + Center = new DataPoint(-205, -105), + RadiusX = 90, + RadiusY = 90, + Fill = OxyColor.FromAColor(180, OxyColors.Black) + }); + drawing.Add( + new Text + { + Point = new DataPoint(-180, 132), + Content = "FAST", + Color = OxyColors.White, + FontSize = 60, + FontWeight = FontWeights.Bold, + HorizontalAlignment = HorizontalAlignment.Center, + VerticalAlignment = OxyPlot.VerticalAlignment.Middle + }); + drawing.Add( + new Text + { + Point = new DataPoint(180, 132), + Content = "CHEAP", + Color = OxyColors.White, + FontSize = 60, + FontWeight = FontWeights.Bold, + HorizontalAlignment = HorizontalAlignment.Center, + VerticalAlignment = OxyPlot.VerticalAlignment.Middle + }); + drawing.Add( + new Text + { + Point = new DataPoint(0, -160), + Content = "GREAT", + Color = OxyColors.White, + FontSize = 60, + FontWeight = FontWeights.Bold, + HorizontalAlignment = HorizontalAlignment.Center, + VerticalAlignment = OxyPlot.VerticalAlignment.Middle + }); + drawing.Add( + new Text + { + Point = new DataPoint(-240, -100), + Content = "FREE", + Color = OxyColors.White, + FontSize = 40, + FontWeight = FontWeights.Bold, + HorizontalAlignment = HorizontalAlignment.Center, + VerticalAlignment = OxyPlot.VerticalAlignment.Middle + }); + + return new Example(drawing); + } + } + + public class Person + { + public Person(string name, Person father = null, Person mother = null) + { + this.Name = name; + this.Father = father; + this.Mother = mother; + } + + public string Name { get; private set; } + public Person Father { get; private set; } + public Person Mother { get; private set; } + } + + public static class PersonExtensions + { + public static void Render(this Person person, DrawingModel drawing, int generation, double startAngle, double endAngle) + { + var arc = new Polyline(); + var r0 = (generation - 1) * 100; + var r1 = generation * 100; + arc.Points.AddRange(Interpolation.Arc(new DataPoint(0, 0), r1, r1, startAngle, endAngle)); + drawing.Add(arc); + var lines = new Lines(); + var midAngle = (startAngle + endAngle) / 2; + var th0 = startAngle / 180 * Math.PI; + var th1 = endAngle / 180 * Math.PI; + var th2 = midAngle / 180 * Math.PI; + lines.Add(Math.Cos(th0) * r0, Math.Sin(th0) * r0, Math.Cos(th0) * r1, Math.Sin(th0) * r1); + lines.Add(Math.Cos(th1) * r0, Math.Sin(th1) * r0, Math.Cos(th1) * r1, Math.Sin(th1) * r1); + drawing.Add(lines); + + var r2 = (r0 + r1) / 2; + drawing.Add(new Text + { + Point = new DataPoint(Math.Cos(th2) * r2, Math.Sin(th2) * r2), + Content = person.Name, + FontSize = 20, + FontFamily = "Times New Roman", + HorizontalAlignment = HorizontalAlignment.Center, + VerticalAlignment = VerticalAlignment.Middle, + Rotate = 90 - midAngle + }); + + if (person.Father != null) + { + person.Father.Render(drawing, generation + 1, midAngle, endAngle); + } + + if (person.Mother != null) + { + person.Mother.Render(drawing, generation + 1, startAngle, midAngle); + } + } + } +} \ No newline at end of file diff --git a/Source/Examples/DrawingLibrary/Examples/MouseEventExamples.cs b/Source/Examples/DrawingLibrary/Examples/MouseEventExamples.cs new file mode 100644 index 000000000..9a921df8d --- /dev/null +++ b/Source/Examples/DrawingLibrary/Examples/MouseEventExamples.cs @@ -0,0 +1,38 @@ +namespace DrawingDemo +{ + using OxyPlot; + using OxyPlot.Drawing; + + public static class MouseEventExamples + { + [Example("MouseEvents: Circle")] + public static Example CircleFromThreePoints() + { + var drawing = new DrawingModel(); + var p1 = drawing.AddPoint(new DataPoint(0, 0), OxyColors.Red); + p1.FontSize = 120; + p1.FontWeight = FontWeights.Bold; + var originalFill = OxyColors.Undefined; + p1.MouseDown += (s, e) => + { + if (e.ChangedButton == OxyMouseButton.Left) + { + p1.Text = "Pressed"; + originalFill = p1.Fill; + p1.Fill = OxyColors.Red; + drawing.Invalidate(); + e.Handled = true; + } + }; + p1.MouseUp += (s, e) => + { + p1.Text = null; + p1.Fill = originalFill; + drawing.Invalidate(); + e.Handled = true; + }; + + return new Example(drawing); + } + } +} \ No newline at end of file diff --git a/Source/Examples/DrawingLibrary/Examples/OpenStreetMapExamples/OpenStreetMapExamples.cs b/Source/Examples/DrawingLibrary/Examples/OpenStreetMapExamples/OpenStreetMapExamples.cs new file mode 100644 index 000000000..cd345b7c8 --- /dev/null +++ b/Source/Examples/DrawingLibrary/Examples/OpenStreetMapExamples/OpenStreetMapExamples.cs @@ -0,0 +1,83 @@ +namespace DrawingLibrary.Examples +{ + using System; + using System.Collections.Generic; + using System.Linq; + using System.Reflection; + + using DrawingDemo; + + using OsmLibrary; + + using OxyPlot; + using OxyPlot.Drawing; + + public static class OpenStreetMapExamples + { + [Example("OSM Høvik")] + public static Example OsmHøvik() + { + var drawing = new DrawingModel(); + + var tileLayer = new TileLayer + { + Source = "http://tile.openstreetmap.org/{Z}/{X}/{Y}.png", + CopyrightNotice = "OpenStreetMap", + Opacity = 0.2 + }; + drawing.Add(tileLayer); + Func, IEnumerable> transform = nodes => nodes.Select(n => tileLayer.Transform(new LatLon(n.Latitude, n.Longitude))); + var assembly = typeof(OpenStreetMapExamples).GetTypeInfo().Assembly; + using (var stream = assembly.GetManifestResourceStream("DrawingLibrary.Examples.OpenStreetMapExamples.map.osm")) + { + var osm = OpenStreetMap.Load(stream); + osm.Query(way => way["highway"] == "motorway", (way, nodes) => drawing.Add(new Polyline(transform(nodes)) { Thickness = -5 })); + osm.Query(way => way["highway"] == "primary", (way, nodes) => drawing.Add(new Polyline(transform(nodes)) { Thickness = -3 })); + osm.Query(way => way["highway"] == "secondary", (way, nodes) => drawing.Add(new Polyline(transform(nodes)) { Thickness = -2 })); + osm.Query(way => way["highway"] == "residential", (way, nodes) => drawing.Add(new Polyline(transform(nodes)) { Thickness = -2, Color = OxyColors.Gray })); + osm.Query(way => way["building"] != null, (way, nodes) => drawing.Add(new Polygon(transform(nodes)) { Fill = OxyColors.Gray })); + osm.Query(way => way["amenity"] == "parking", (way, nodes) => drawing.Add(new Polygon(transform(nodes)) { Fill = OxyColors.LightBlue })); + } + + return new Example(drawing); + } + + [Example("OSM MTB")] + public static Example OsmMtb() + { + // Ways with mtb:scale tags are extracted using http://overpass-turbo.eu/ with the following query + /* + + + + + + + + + + */ + + var drawing = new DrawingModel(); + + var tileLayer = new TileLayer + { + Source = "http://tile.openstreetmap.org/{Z}/{X}/{Y}.png", + CopyrightNotice = "OpenStreetMap", + }; + drawing.Add(tileLayer); + Func, IEnumerable> transform = nodes => nodes.Select(n => tileLayer.Transform(new LatLon(n.Latitude, n.Longitude))); + var assembly = typeof(OpenStreetMapExamples).GetTypeInfo().Assembly; + using (var stream = assembly.GetManifestResourceStream("DrawingLibrary.Examples.OpenStreetMapExamples.mtbways.osm")) + { + var osm = OpenStreetMap.Load(stream); + osm.Query(way => way["mtb:scale"] == "0", (way, nodes) => drawing.Add(new Polyline(transform(nodes)) { Thickness = -5, Color = OxyColor.FromAColor(80, OxyColors.Green) })); + osm.Query(way => way["mtb:scale"] == "1", (way, nodes) => drawing.Add(new Polyline(transform(nodes)) { Thickness = -5, Color = OxyColor.FromAColor(80, OxyColors.Blue) })); + osm.Query(way => way["mtb:scale"] == "2", (way, nodes) => drawing.Add(new Polyline(transform(nodes)) { Thickness = -5, Color = OxyColor.FromAColor(80, OxyColors.Red) })); + osm.Query(way => way["mtb:scale"] == "3", (way, nodes) => drawing.Add(new Polyline(transform(nodes)) { Thickness = -5, Color = OxyColor.FromAColor(80, OxyColors.Magenta) })); + } + + return new Example(drawing); + } + } +} diff --git a/Source/Examples/DrawingLibrary/Examples/OpenStreetMapExamples/OsmModel/Bounds.cs b/Source/Examples/DrawingLibrary/Examples/OpenStreetMapExamples/OsmModel/Bounds.cs new file mode 100644 index 000000000..faf26320e --- /dev/null +++ b/Source/Examples/DrawingLibrary/Examples/OpenStreetMapExamples/OsmModel/Bounds.cs @@ -0,0 +1,38 @@ +namespace OsmLibrary +{ + using System.Xml.Serialization; + + /// + /// Represents a bounding box. + /// + public struct Bounds + { + /// + /// Gets or sets the minimum latitude. + /// + /// The minimum latitude. + [XmlAttribute("minlat")] + public double MinLat { get; set; } + + /// + /// Gets or sets the minimum longitude. + /// + /// The minimum longitude. + [XmlAttribute("minlon")] + public double MinLon { get; set; } + + /// + /// Gets or sets the maximum latitude. + /// + /// The maximum latitude. + [XmlAttribute("maxlat")] + public double MaxLat { get; set; } + + /// + /// Gets or sets the maximum longitude. + /// + /// The maximum longitude. + [XmlAttribute("maxlon")] + public double MaxLon { get; set; } + } +} \ No newline at end of file diff --git a/Source/Examples/DrawingLibrary/Examples/OpenStreetMapExamples/OsmModel/Element.cs b/Source/Examples/DrawingLibrary/Examples/OpenStreetMapExamples/OsmModel/Element.cs new file mode 100644 index 000000000..a9e1d3cc8 --- /dev/null +++ b/Source/Examples/DrawingLibrary/Examples/OpenStreetMapExamples/OsmModel/Element.cs @@ -0,0 +1,60 @@ +namespace OsmLibrary +{ + using System; + using System.Xml.Serialization; + + /// + /// Represents a base class for elements. + /// + public abstract class Element + { + /// + /// Gets or sets the identifier. + /// + /// The identifier. + [XmlAttribute("id")] + public long Id { get; set; } + + /// + /// Gets or sets a value indicating whether this is visible. + /// + /// true if visible; otherwise, false. + [XmlAttribute("visible")] + public bool Visible { get; set; } + + /// + /// Gets or sets the version. + /// + /// The version. + [XmlAttribute("version")] + public int Version { get; set; } + + /// + /// Gets or sets the changeset. + /// + /// The changeset. + [XmlAttribute("changeset")] + public long Changeset { get; set; } + + /// + /// Gets or sets the timestamp. + /// + /// The timestamp. + [XmlAttribute("timestamp")] + public DateTime Timestamp { get; set; } + + /// + /// Gets or sets the user. + /// + /// The user. + [XmlAttribute("user")] + public string User { get; set; } + + /// + /// Gets or sets the user id. + /// + /// The user id. + [XmlAttribute("uid")] + public long Uid { get; set; } + } +} diff --git a/Source/Examples/DrawingLibrary/Examples/OpenStreetMapExamples/OsmModel/Member.cs b/Source/Examples/DrawingLibrary/Examples/OpenStreetMapExamples/OsmModel/Member.cs new file mode 100644 index 000000000..32698e84f --- /dev/null +++ b/Source/Examples/DrawingLibrary/Examples/OpenStreetMapExamples/OsmModel/Member.cs @@ -0,0 +1,31 @@ +namespace OsmLibrary +{ + using System.Xml.Serialization; + + /// + /// Represents a member of a . + /// + public struct Member + { + /// + /// Gets or sets the type. + /// + /// The type. + [XmlAttribute("type")] + public string Type { get; set; } + + /// + /// Gets or sets the reference. + /// + /// The reference. + [XmlAttribute("ref")] + public long Ref { get; set; } + + /// + /// Gets or sets the role. + /// + /// The role. + [XmlAttribute("role")] + public string Role { get; set; } + } +} \ No newline at end of file diff --git a/Source/Examples/DrawingLibrary/Examples/OpenStreetMapExamples/OsmModel/Node.cs b/Source/Examples/DrawingLibrary/Examples/OpenStreetMapExamples/OsmModel/Node.cs new file mode 100644 index 000000000..9f95ef37c --- /dev/null +++ b/Source/Examples/DrawingLibrary/Examples/OpenStreetMapExamples/OsmModel/Node.cs @@ -0,0 +1,24 @@ +namespace OsmLibrary +{ + using System.Xml.Serialization; + + /// + /// Represents a node. + /// + public class Node : TaggedElement + { + /// + /// Gets or sets the latitude. + /// + /// The latitude. + [XmlAttribute("lat")] + public double Latitude { get; set; } + + /// + /// Gets or sets the longitude. + /// + /// The longitude. + [XmlAttribute("lon")] + public double Longitude { get; set; } + } +} \ No newline at end of file diff --git a/Source/Examples/DrawingLibrary/Examples/OpenStreetMapExamples/OsmModel/NodeRef.cs b/Source/Examples/DrawingLibrary/Examples/OpenStreetMapExamples/OsmModel/NodeRef.cs new file mode 100644 index 000000000..22dd6d5c6 --- /dev/null +++ b/Source/Examples/DrawingLibrary/Examples/OpenStreetMapExamples/OsmModel/NodeRef.cs @@ -0,0 +1,17 @@ +namespace OsmLibrary +{ + using System.Xml.Serialization; + + /// + /// Represents a node reference in a . + /// + public struct NodeRef + { + /// + /// Gets or sets the node reference. + /// + /// The reference. + [XmlAttribute("ref")] + public long Ref { get; set; } + } +} \ No newline at end of file diff --git a/Source/Examples/DrawingLibrary/Examples/OpenStreetMapExamples/OsmModel/OpenStreetMap.cs b/Source/Examples/DrawingLibrary/Examples/OpenStreetMapExamples/OsmModel/OpenStreetMap.cs new file mode 100644 index 000000000..f2786c22e --- /dev/null +++ b/Source/Examples/DrawingLibrary/Examples/OpenStreetMapExamples/OsmModel/OpenStreetMap.cs @@ -0,0 +1,137 @@ +namespace OsmLibrary +{ + using System; + using System.Collections.Generic; + using System.IO; + using System.Linq; + using System.Xml.Serialization; + + /// + /// Represents a OpenStreetMap file. + /// + [XmlRoot("osm")] + [XmlInclude(typeof(Bounds))] + [XmlInclude(typeof(Node))] + [XmlInclude(typeof(Way))] + [XmlInclude(typeof(Relation))] + public class OpenStreetMap + { + /// + /// The serializer. + /// + private static XmlSerializer serializer = new XmlSerializer(typeof(OpenStreetMap)); + + /// + /// Initializes a new instance of the class. + /// + public OpenStreetMap() + { + this.Nodes = new List(); + this.Ways = new List(); + this.Relations = new List(); + } + + /// + /// Gets or sets the version. + /// + /// The version. + [XmlAttribute("version")] + public string Version { get; set; } + + /// + /// Gets or sets the generator. + /// + /// The generator. + [XmlAttribute("generator")] + public string Generator { get; set; } + + /// + /// Gets or sets the copyright. + /// + /// The copyright. + [XmlAttribute("copyright")] + public string Copyright { get; set; } + + /// + /// Gets or sets the attribution. + /// + /// The attribution. + [XmlAttribute("attribution")] + public string Attribution { get; set; } + + /// + /// Gets or sets the license. + /// + /// The license. + [XmlAttribute("license")] + public string License { get; set; } + + /// + /// Gets or sets the bounding box. + /// + /// The bounding box. + [XmlElement("bounds")] + public Bounds Bounds { get; set; } + + /// + /// Gets the nodes. + /// + /// The nodes. + [XmlElement("node")] + public List Nodes { get; private set; } + + /// + /// Gets the ways. + /// + /// The ways. + [XmlElement("way")] + public List Ways { get; private set; } + + /// + /// Gets the relations. + /// + /// The relations. + [XmlElement("relation")] + public List Relations { get; private set; } + + /// + /// Loads a from the specified stream. + /// + /// The stream to load from. + /// A . + public static OpenStreetMap Load(Stream s) + { + return (OpenStreetMap)serializer.Deserialize(s); + } + + /// + /// Saves to the specified stream. + /// + /// The stream to write to. + public void Save(Stream s) + { + serializer.Serialize(s, this); + } + + public IEnumerable GetNodes(List nodes) + { + foreach (var nd in nodes) + { + var node = this.Nodes.FirstOrDefault(n => n.Id == nd.Ref); + if (node != null) + { + yield return node; + } + } + } + + public void Query(Func predicate, Action> action) + { + foreach (var way in this.Ways.Where(predicate)) + { + var nodes = this.GetNodes(way.Nodes); + action(way, nodes); + } + } + } +} diff --git a/Source/Examples/DrawingLibrary/Examples/OpenStreetMapExamples/OsmModel/Relation.cs b/Source/Examples/DrawingLibrary/Examples/OpenStreetMapExamples/OsmModel/Relation.cs new file mode 100644 index 000000000..bcee89840 --- /dev/null +++ b/Source/Examples/DrawingLibrary/Examples/OpenStreetMapExamples/OsmModel/Relation.cs @@ -0,0 +1,37 @@ +namespace OsmLibrary +{ + using System.Collections.Generic; + using System.Xml.Serialization; + + /// + /// Represents a relation. + /// + public class Relation : Element + { + /// + /// The members. + /// + private readonly List members; + + /// + /// Initializes a new instance of the class. + /// + public Relation() + { + this.members = new List(); + } + + /// + /// Gets the members. + /// + /// The members. + [XmlElement("member")] + public List Members + { + get + { + return this.members; + } + } + } +} \ No newline at end of file diff --git a/Source/Examples/DrawingLibrary/Examples/OpenStreetMapExamples/OsmModel/Tag.cs b/Source/Examples/DrawingLibrary/Examples/OpenStreetMapExamples/OsmModel/Tag.cs new file mode 100644 index 000000000..82f75a3fa --- /dev/null +++ b/Source/Examples/DrawingLibrary/Examples/OpenStreetMapExamples/OsmModel/Tag.cs @@ -0,0 +1,24 @@ +namespace OsmLibrary +{ + using System.Xml.Serialization; + + /// + /// Represents a tag in a . + /// + public class Tag + { + /// + /// Gets or sets the key. + /// + /// The key. + [XmlAttribute("k")] + public string Key { get; set; } + + /// + /// Gets or sets the value. + /// + /// The value. + [XmlAttribute("v")] + public string Value { get; set; } + } +} \ No newline at end of file diff --git a/Source/Examples/DrawingLibrary/Examples/OpenStreetMapExamples/OsmModel/TaggedElement.cs b/Source/Examples/DrawingLibrary/Examples/OpenStreetMapExamples/OsmModel/TaggedElement.cs new file mode 100644 index 000000000..eb431b4de --- /dev/null +++ b/Source/Examples/DrawingLibrary/Examples/OpenStreetMapExamples/OsmModel/TaggedElement.cs @@ -0,0 +1,38 @@ +namespace OsmLibrary +{ + using System.Collections.Generic; + using System.Xml.Serialization; + + /// + /// Provides a base class for elements that contains tags. + /// + public abstract class TaggedElement : Element + { + /// + /// The tags + /// + private List tags; + + /// + /// Initializes a new instance of the class. + /// + protected TaggedElement() + { + this.tags = new List(); + } + + + /// + /// Gets the tags of the element. + /// + /// The tags. + [XmlElement("tag")] + public List Tags + { + get + { + return this.tags; + } + } + } +} \ No newline at end of file diff --git a/Source/Examples/DrawingLibrary/Examples/OpenStreetMapExamples/OsmModel/Way.cs b/Source/Examples/DrawingLibrary/Examples/OpenStreetMapExamples/OsmModel/Way.cs new file mode 100644 index 000000000..36f061cce --- /dev/null +++ b/Source/Examples/DrawingLibrary/Examples/OpenStreetMapExamples/OsmModel/Way.cs @@ -0,0 +1,51 @@ +namespace OsmLibrary +{ + using System.Collections.Generic; + using System.Linq; + using System.Xml.Serialization; + + /// + /// Represents a way. + /// + public class Way : TaggedElement + { + /// + /// The nodes + /// + private readonly List nodes; + + /// + /// Initializes a new instance of the class. + /// + public Way() + { + this.nodes = new List(); + } + + /// + /// Gets the nodes of the way. + /// + /// The nodes. + [XmlElement("nd")] + public List Nodes + { + get + { + return this.nodes; + } + } + + public string this[string key] + { + get + { + var t = this.Tags.FirstOrDefault(tag => tag.Key == key); + if (t != null) + { + return t.Value; + } + return null; + } + } + } +} \ No newline at end of file diff --git a/Source/Examples/DrawingLibrary/Examples/OpenStreetMapExamples/map.osm b/Source/Examples/DrawingLibrary/Examples/OpenStreetMapExamples/map.osm new file mode 100644 index 000000000..21526d748 --- /dev/null +++ b/Source/Examples/DrawingLibrary/Examples/OpenStreetMapExamples/map.osm @@ -0,0 +1,11957 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/Source/Examples/DrawingLibrary/Examples/OpenStreetMapExamples/mtbways.osm b/Source/Examples/DrawingLibrary/Examples/OpenStreetMapExamples/mtbways.osm new file mode 100644 index 000000000..16f85622c --- /dev/null +++ b/Source/Examples/DrawingLibrary/Examples/OpenStreetMapExamples/mtbways.osm @@ -0,0 +1,12146 @@ + + +The data included in this document is from www.openstreetmap.org. The data is made available under ODbL. + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/Source/Examples/DrawingLibrary/Examples/SvgExamples/Blank_map_of_Europe.svg b/Source/Examples/DrawingLibrary/Examples/SvgExamples/Blank_map_of_Europe.svg new file mode 100644 index 000000000..c63d30ab9 --- /dev/null +++ b/Source/Examples/DrawingLibrary/Examples/SvgExamples/Blank_map_of_Europe.svg @@ -0,0 +1,400 @@ + + + + + Countries of Europe + A blank Map of Europe. Every country has an id which is its ISO-3166-1-ALPHA2 code in lower case. + Members of the EU have a class="eu", countries in europe (which I found turkey to be but russia not) have a class="europe". + Certain countries are further subdivided the United Kingdom has gb-gbn for Great Britain and gb-nir for Northern Ireland. Russia is divided into ru-kgd for the Kaliningrad Oblast and ru-main for the Main body of Russia. There is the additional grouping #xb for the "British Islands" (the UK with its Crown Dependencies - Jersey, Guernsey and the Isle of Man) + + Contributors. + Original Image: (http://commons.wikimedia.org/wiki/Image:Europe_countries.svg) Júlio Reis (http://commons.wikimedia.org/wiki/User:Tintazul). + Recolouring and tagging with country codes: Marian "maix" Sigler (http://commons.wikimedia.org/wiki/User:Maix) + Improved geographical features: http://commons.wikimedia.org/wiki/User:W!B: + Updated to reflect dissolution of Serbia & Montenegro: http://commons.wikimedia.org/wiki/User:Zirland + Updated to include British Crown Dependencies as seperate entities and regroup them as "British Islands", with some simplifications to the XML and CSS: James Hardy (http://commons.wikimedia.org/wiki/User:MrWeeble) + Validated (http://commons.wikimedia.org/wiki/User:CarolSpears) + Changed the country code of Serbia to RS per http://en.wikipedia.org/wiki/Serbian_country_codes and the file http://www.iso.org/iso/iso3166_en_code_lists.txt (http://commons.wikimedia.org/wiki/User:TimothyBourke) + Uploaded on behalf of User:Checkit, direct complaints to him plox: 'Moved countries out of the "outlines" group, removed "outlines" style class, remove separate style information for Russia' (http://commons.wikimedia.org/wiki/User:Collard) + Updated various coastlines and boarders and added various islands not previously shown (details follow). Added Kosovo and Northern Cyprus as disputed territories. Moved major lakes to their own object and added more. List of updated boarders/coastlines: British Isles (+ added Isle of Wight, Skye, various smaller islands), the Netherlands, Germany, Czech Republic, Denmark, Sweden, Finland, Poland, Kaliningrad Oblast of the Russian Federation (and minor tweaks to Lithuania), Ukraine, Moldova (minor), Romania, Bulgaria, Turkey, Greece, F.Y.R. Macedonia, Serbia, Bosnia and Herzegovina, Montenegro, Albania, Croatia, Italy (mainland and Sicily), Malta (http://commons.wikimedia.org/wiki/User:Alphathon). + Added Bornholm (http://commons.wikimedia.org/wiki/User:Heb) + + Released under CreativeCommons Attribution ShareAlike (http://creativecommons.org/licenses/by-sa/2.5/). + + + + + image/svg+xml + + Countries of Europe + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/Source/Examples/DrawingLibrary/Examples/SvgExamples/Europe_countries.svg b/Source/Examples/DrawingLibrary/Examples/SvgExamples/Europe_countries.svg new file mode 100644 index 000000000..358b497ca --- /dev/null +++ b/Source/Examples/DrawingLibrary/Examples/SvgExamples/Europe_countries.svg @@ -0,0 +1,30 @@ + + + + + + + image/svg+xml + + + + + + + + + + + + + + + + + + + + + + + \ No newline at end of file diff --git a/Source/Examples/DrawingLibrary/Examples/SvgExamples/Ghostscript_Tiger.svg b/Source/Examples/DrawingLibrary/Examples/SvgExamples/Ghostscript_Tiger.svg new file mode 100644 index 000000000..679edec2e --- /dev/null +++ b/Source/Examples/DrawingLibrary/Examples/SvgExamples/Ghostscript_Tiger.svg @@ -0,0 +1,725 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/Source/Examples/DrawingLibrary/Examples/SvgExamples/Ghostscript_Tiger.svgz b/Source/Examples/DrawingLibrary/Examples/SvgExamples/Ghostscript_Tiger.svgz new file mode 100644 index 000000000..0ac42669f Binary files /dev/null and b/Source/Examples/DrawingLibrary/Examples/SvgExamples/Ghostscript_Tiger.svgz differ diff --git a/Source/Examples/DrawingLibrary/Examples/SvgExamples/SvgExamples.cs b/Source/Examples/DrawingLibrary/Examples/SvgExamples/SvgExamples.cs new file mode 100644 index 000000000..957bddcc6 --- /dev/null +++ b/Source/Examples/DrawingLibrary/Examples/SvgExamples/SvgExamples.cs @@ -0,0 +1,316 @@ +namespace DrawingLibrary.Examples +{ + using System; + using System.Collections.Generic; + using System.Globalization; + using System.IO; + using System.Linq; + using System.Reflection; + using System.Text; + + using DrawingDemo; + + using OxyPlot; + using OxyPlot.Drawing; + + using SvgLibrary; + + public static class SvgExamples + { + [Example("SVG Tiger")] + public static Example Tiger() + { + var drawing = new DrawingModel(); + + var assembly = typeof(SvgExamples).GetTypeInfo().Assembly; + using (var stream = assembly.GetManifestResourceStream("DrawingLibrary.Examples.SvgExamples.Ghostscript_Tiger.svg")) + { + var svg = Svg.Load(stream); + RenderSvg(svg, drawing); + } + + return new Example(drawing); + } + + [Example("SVG Europe")] + public static Example Europe() + { + var drawing = new DrawingModel(); + + var assembly = typeof(SvgExamples).GetTypeInfo().Assembly; + using (var stream = assembly.GetManifestResourceStream("DrawingLibrary.Examples.SvgExamples.Blank_map_of_Europe.svg")) + { + var svg = Svg.Load(stream); + RenderSvg(svg, drawing); + } + + return new Example(drawing); + } + + [Example("SVG Path")] + public static Example Path() + { + var drawing = new DrawingModel(); + var content = ""; + using (var stream = new MemoryStream(Encoding.UTF8.GetBytes(content))) + { + var svg = Svg.Load(stream); + RenderSvg(svg, drawing); + } + + return new Example(drawing); + } + + private static void RenderSvg(SvgGroup group, DrawingModel drawing, SvgStyle groupStyle = null, SvgTransform groupTransform = null) + { + if (groupStyle == null) + { + groupStyle = new SvgStyle(); + } + + if (groupTransform == null) + { + groupTransform = new SvgTransform(); + } + + Func ytransform = x => new DataPoint(x.X, -x.Y); + + foreach (var element in group.Elements) + { + var computedStyle = groupStyle.Append(element.Style); + var totalTransform = groupTransform.Append(element.Transform); + var innerGroup = element as SvgGroup; + if (innerGroup != null) + { + RenderSvg(innerGroup, drawing, computedStyle, totalTransform); + } + + Func transform = x => + { + double xx, yy; + totalTransform.Transform(x.X, x.Y, out xx, out yy); + return new DataPoint(xx, -yy); + }; + + var path = element as SvgPath; + if (path != null) + { + var figures = GetPaths(path); + foreach (var f in figures) + { + var closed = double.IsNaN(f.Last().X); + if (closed) + { + f.RemoveAt(f.Count - 1); + var p = new Polygon(f.Select(transform)) + { + Stroke = OxyColor.Parse(computedStyle.Stroke), + Thickness = computedStyle.StrokeWidth, + Fill = OxyColor.Parse(computedStyle.Fill) + }; + drawing.Add(p); + } + else + { + var p = new Polyline(f.Select(transform)) + { + Color = OxyColor.Parse(computedStyle.Stroke), + Thickness = computedStyle.StrokeWidth, + }; + drawing.Add(p); + } + } + } + } + } + + private static List> GetPaths(SvgPath path, int n = 8) + { + var figures = new List>(); + List figure = null; + + var currentCommand = '\0'; + var currentPoint = new DataPoint(); + var previousControlPoint = new DataPoint(); + + Action moveTo = (x, y, relative) => + { + // Debug.WriteLine("moveTo({0},{1})", x, y); + currentPoint = relative ? new DataPoint(currentPoint.X + x, currentPoint.Y + y) : new DataPoint(x, y); + previousControlPoint = currentPoint; + figure = new List { currentPoint }; + figures.Add(figure); + }; + Action lineTo = (x, y, relative) => + { + // Debug.WriteLine("lineTo({0},{1})", x, y); + currentPoint = relative ? new DataPoint(currentPoint.X + x, currentPoint.Y + y) : new DataPoint(x, y); + figure.Add(currentPoint); + }; + Action curveTo = (x1, y1, x2, y2, x, y, relative) => + { + // Debug.WriteLine("curveTo({0},{1},{2},{3},{4},{5})", x1, y1, x2, y2, x, y); + var p0 = currentPoint; + var p1 = relative ? new DataPoint(currentPoint.X + x1, currentPoint.Y + y1) : new DataPoint(x1, y1); + var p2 = relative ? new DataPoint(currentPoint.X + x2, currentPoint.Y + y2) : new DataPoint(x2, y2); + var p3 = relative ? new DataPoint(currentPoint.X + x, currentPoint.Y + y) : new DataPoint(x, y); + for (int i = 1; i <= n; i++) + { + var t = (double)i / n; + var cube = t * t * t; + var square = t * t; + var ax = 3 * (p1.X - p0.X); + var ay = 3 * (p1.Y - p0.Y); + var bx = (3 * (p2.X - p1.X)) - ax; + var by = (3 * (p2.Y - p1.Y)) - ay; + var cx = p3.X - p0.X - ax - bx; + var cy = p3.Y - p0.Y - ay - by; + var xt = (cx * cube) + (bx * square) + (ax * t) + p0.X; + var yt = (cy * cube) + (by * square) + (ay * t) + p0.Y; + figure.Add(new DataPoint(xt, yt)); + } + + currentPoint = p3; + previousControlPoint = p2; + }; + Action smoothCurveTo = (x2, y2, x, y, relative) => + { + // Debug.WriteLine("smoothCurveTo({0},{1},{2},{3})", x2, y2, x, y); + + // absolute coordinates + var dx = currentPoint.X - previousControlPoint.X; + var dy = currentPoint.Y - previousControlPoint.Y; + var x1 = relative ? dx : currentPoint.X + dx; + var y1 = relative ? dy : currentPoint.Y + dy; + curveTo(x1, y1, x2, y2, x, y, relative); + }; + + Action close = () => + { + figure.Add(new DataPoint(double.NaN, double.NaN)); + figure = null; + }; + + // Debug.WriteLine(path.PathData); + var queue = new Queue(PathLexer(path.PathData)); + Func next = () => (double)queue.Dequeue(); + while (queue.Count > 0) + { + if (queue.Peek() is char) + { + currentCommand = (char)queue.Dequeue(); + // Debug.WriteLine(currentCommand); + continue; + } + + bool relative = char.IsLower(currentCommand); + double x, y, x1, y1, x2, y2; + switch (char.ToLower(currentCommand)) + { + case 'm': + x = next(); + y = next(); + moveTo(x, y, relative); + currentCommand = relative ? 'l' : 'L'; + break; + + case 'l': + x = next(); + y = next(); + lineTo(x, y, relative); + break; + + case 'h': + x = next(); + lineTo(x, 0, relative); + break; + + case 'v': + y = next(); + lineTo(0, y, relative); + break; + + case 'z': + close(); + break; + + case 's': + x2 = next(); + y2 = next(); + x = next(); + y = next(); + smoothCurveTo(x2, y2, x, y, relative); + break; + + case 'c': + x1 = next(); + y1 = next(); + x2 = next(); + y2 = next(); + x = next(); + y = next(); + curveTo(x1, y1, x2, y2, x, y, relative); + break; + case 'a': + var rx = next(); + var ry = next(); + var xrot = next(); + var largeArcFlag = next(); + var sweepFlag = next(); + x = next(); + y = next(); + lineTo(x, y, relative); + // arcTo(x1, y1, x2, y2, x, y, relative); + break; + default: + throw new NotImplementedException("The command " + currentCommand + " is not yet supported."); + } + } + + if (char.ToLower(currentCommand) == 'z') + { + close(); + } + + return figures; + } + + private static IEnumerable PathLexer(string path) + { + string number = null; + + foreach (char c in path) + { + if (number != null) + { + if (char.IsNumber(c) || c == '.' || c == 'E' || c == 'e' || (c == '-' && number[number.Length - 1] == 'e')) + { + number += c; + continue; + } + + yield return double.Parse(number, CultureInfo.InvariantCulture); + number = null; + } + + if (char.IsNumber(c) || c == '.' || c == '-') + { + number = c.ToString(); + continue; + } + + if (c == ' ' || c == ',') + { + continue; + } + + yield return c; + } + + if (number != null) + { + yield return double.Parse(number, CultureInfo.InvariantCulture); + } + } + } +} diff --git a/Source/Examples/DrawingLibrary/Examples/SvgExamples/SvgModel/Svg.cs b/Source/Examples/DrawingLibrary/Examples/SvgExamples/SvgModel/Svg.cs new file mode 100644 index 000000000..faff8f6f8 --- /dev/null +++ b/Source/Examples/DrawingLibrary/Examples/SvgExamples/SvgModel/Svg.cs @@ -0,0 +1,43 @@ +namespace SvgLibrary +{ + using System.IO; + using System.Xml.Serialization; + + /// + /// Represents a OpenStreetMap file. + /// + [XmlRoot("svg", Namespace = "http://www.w3.org/2000/svg")] + public class Svg : SvgGroup + { + /// + /// The serializer. + /// + private static XmlSerializer serializer = new XmlSerializer(typeof(Svg)); + + /// + /// Gets or sets the view box. + /// + /// The view box. + [XmlAttribute("viewBox")] + public string ViewBox { get; set; } + + /// + /// Loads a from the specified stream. + /// + /// The stream to load from. + /// An instance. + public static Svg Load(Stream s) + { + return (Svg)serializer.Deserialize(s); + } + + /// + /// Saves to the specified stream. + /// + /// The stream to write to. + public void Save(Stream s) + { + serializer.Serialize(s, this); + } + } +} diff --git a/Source/Examples/DrawingLibrary/Examples/SvgExamples/SvgModel/SvgElement.cs b/Source/Examples/DrawingLibrary/Examples/SvgExamples/SvgModel/SvgElement.cs new file mode 100644 index 000000000..f1484c645 --- /dev/null +++ b/Source/Examples/DrawingLibrary/Examples/SvgExamples/SvgModel/SvgElement.cs @@ -0,0 +1,221 @@ +namespace SvgLibrary +{ + using System.Collections.Generic; + using System.Globalization; + using System.Linq; + using System.Text; + using System.Text.RegularExpressions; + using System.Xml.Serialization; + + /// + /// Represents a base class for elements. + /// + public abstract class SvgElement + { + public SvgElement() + { + this.Style = new SvgStyle(); + this.Transform = new SvgTransform(); + } + + /// + /// Gets or sets the identifier. + /// + /// The identifier. + [XmlAttribute("id")] + public string Id { get; set; } + + [XmlAttribute("class")] + public string Class { get; set; } + + [XmlAttribute("style")] + public string StyleAttribute + { + get + { + return this.Style.ToString(); + } + + set + { + this.Style.Set(value); + } + } + + [XmlIgnore] + public SvgStyle Style { get; set; } + + [XmlIgnore] + public SvgTransform Transform { get; set; } + + [XmlAttribute("transform")] + public string TransformAttribute + { + get + { + return Transform.ToString(); + } + set + { + this.Transform.Set(value); + } + } + + [XmlAttribute("stroke-width")] + public double StrokeWidth + { + get + { + return this.Style.StrokeWidth; + } + + set + { + this.Style.StrokeWidth = value; + } + } + + [XmlAttribute("stroke")] + public string Stroke + { + get + { + return this.Style.Stroke; + } + + set + { + this.Style.Stroke = value; + } + } + + [XmlAttribute("fill")] + public string Fill + { + get + { + return this.Style.Fill; + } + + set + { + this.Style.Fill = value; + } + } + } + + public class SvgTransform + { + public SvgTransform() + { + this.A = 1; + this.D = 1; + } + public double A { get; set; } + public double B { get; set; } + public double C { get; set; } + public double D { get; set; } + public double E { get; set; } + public double F { get; set; } + + public void Set(string transform) + { + // https://developer.mozilla.org/en-US/docs/Web/SVG/Attribute/transform + + foreach (Match m in Regex.Matches(transform, @"(matrix)\((.*)\)")) + { + var values = m.Groups[2].Value.Split(", ".ToCharArray()).Select(v => double.Parse(v, CultureInfo.InvariantCulture)).ToArray(); + if (m.Groups[1].Value == "matrix") + { + this.A = values[0]; + this.B = values[1]; + this.C = values[2]; + this.D = values[3]; + this.E = values[4]; + this.F = values[5]; + } + } + } + + public SvgTransform Append(SvgTransform x) + { + var output = new SvgTransform + { + A = this.A * x.A + this.C * x.B, + B = this.B * x.A + this.D * x.B, + C = this.A * x.C + this.C * x.D, + D = this.B * x.C + this.D * x.D, + E = this.A * x.E + this.C * x.F + this.E, + F = this.B * x.E + this.D * x.F + this.F + }; + return output; + } + + public void Transform(double x, double y, out double xx, out double yy) + { + xx = this.A * x + this.C * y + this.E; + yy = this.B * x + this.D * y + this.F; + } + } + + public class SvgStyle + { + public SvgStyle() + { + this.StrokeWidth = double.NaN; + } + + public double StrokeWidth { get; set; } + + public string Stroke { get; set; } + + public string Fill { get; set; } + + public void Set(string style) + { + foreach (var item in style.Split(';')) + { + var keyValue = item.Split(':'); + switch (keyValue[0]) + { + case "fill": + this.Fill = keyValue[1]; + break; + case "stroke": + this.Stroke = keyValue[1]; + break; + case "stroke-width": + this.StrokeWidth = double.Parse(keyValue[1], CultureInfo.InvariantCulture); + break; + } + } + } + + public override string ToString() + { + var b = new StringBuilder(); + if (this.Fill != null) b.Append("fill:" + this.Fill + ";"); + if (this.Stroke != null) b.Append("stroke:" + this.Stroke + ";"); + if (!double.IsNaN(this.StrokeWidth)) b.Append("stroke-width:" + this.StrokeWidth.ToString(CultureInfo.InvariantCulture) + ";"); + return base.ToString(); + } + + public SvgStyle Append(SvgStyle s) + { + var computedStyle = new SvgStyle() + { + Fill = this.Fill, + Stroke = this.Stroke, + StrokeWidth = this.StrokeWidth + }; + + if (s.Fill != null) computedStyle.Fill = s.Fill; + if (s.Stroke != null) computedStyle.Stroke = s.Stroke; + if (!double.IsNaN(s.StrokeWidth)) computedStyle.StrokeWidth = s.StrokeWidth; + + // default values + if (double.IsNaN(computedStyle.StrokeWidth)) computedStyle.StrokeWidth = 1; + return computedStyle; + } + } +} \ No newline at end of file diff --git a/Source/Examples/DrawingLibrary/Examples/SvgExamples/SvgModel/SvgGroup.cs b/Source/Examples/DrawingLibrary/Examples/SvgExamples/SvgModel/SvgGroup.cs new file mode 100644 index 000000000..044343522 --- /dev/null +++ b/Source/Examples/DrawingLibrary/Examples/SvgExamples/SvgModel/SvgGroup.cs @@ -0,0 +1,23 @@ +namespace SvgLibrary +{ + using System.Collections.Generic; + using System.Xml.Serialization; + + [XmlInclude(typeof(SvgPath))] + [XmlInclude(typeof(SvgGroup))] + public class SvgGroup : SvgElement + { + public SvgGroup() + { + this.Elements = new List(); + } + + /// + /// Gets the elements. + /// + /// The elements. + [XmlElement(typeof(SvgGroup), ElementName = "g")] + [XmlElement(typeof(SvgPath), ElementName = "path")] + public List Elements { get; private set; } + } +} \ No newline at end of file diff --git a/Source/Examples/DrawingLibrary/Examples/SvgExamples/SvgModel/SvgPath.cs b/Source/Examples/DrawingLibrary/Examples/SvgExamples/SvgModel/SvgPath.cs new file mode 100644 index 000000000..c7682e738 --- /dev/null +++ b/Source/Examples/DrawingLibrary/Examples/SvgExamples/SvgModel/SvgPath.cs @@ -0,0 +1,10 @@ +namespace SvgLibrary +{ + using System.Xml.Serialization; + + public class SvgPath : SvgElement + { + [XmlAttribute("d")] + public string PathData { get; set; } + } +} \ No newline at end of file diff --git a/Source/Examples/DrawingLibrary/Examples/TileLayerExamples.cs b/Source/Examples/DrawingLibrary/Examples/TileLayerExamples.cs new file mode 100644 index 000000000..6087fa24c --- /dev/null +++ b/Source/Examples/DrawingLibrary/Examples/TileLayerExamples.cs @@ -0,0 +1,101 @@ +namespace DrawingDemo +{ + using System.Collections.Generic; + using System.Globalization; + using System.IO; + using System.Linq; + using System.Reflection; + using System.Text.RegularExpressions; + + using OxyPlot; + using OxyPlot.Drawing; + + public static class TileLayerExamples { + + [Example("Tile layer and gpx track log")] + public static Example OpenStreetMap() + { + var drawing = new DrawingModel(); + + var tileLayer = new TileLayer + { + Source = "http://opencache.statkart.no/gatekeeper/gk/gk.open_gmaps?layers=toporaster3&zoom={Z}&x={X}&y={Y}", + CopyrightNotice = "Kartgrunnlag: Statens kartverk, Geovekst og kommuner.", + Opacity = 0.7 + }; + drawing.Add(tileLayer); + + var assembly = typeof(TileLayerExamples).GetTypeInfo().Assembly; + using (var stream = assembly.GetManifestResourceStream("DrawingLibrary.Resources.Tracklog.gpx")) + { + var track = LoadGpxTrack(stream).ToArray(); + + var trackLine = new Polyline(track.Select(tileLayer.Transform)) + { + Color = OxyColor.FromAColor(180, OxyColors.Red), + Thickness = -3, + MinimumSegmentLength = 1 + }; + + drawing.Add(trackLine); + + var milestones = GetMileStones(track, 5000); + foreach (var kvp in milestones) + { + var p = tileLayer.Transform(kvp.Value); + var milestoneEllipse = new Ellipse + { + Center = p, + RadiusX = -10, + RadiusY = -10, + Stroke = OxyColors.Black, + Fill = OxyColor.FromAColor(180, OxyColors.White), + Thickness = -1.5, + Text = string.Format(CultureInfo.InvariantCulture, "{0:0}", kvp.Key / 1000), + FontSize = 9 + }; + + drawing.Add(milestoneEllipse); + } + } + + return new Example(drawing); + } + + private static Dictionary GetMileStones(IList points, double distance) + { + var result = new Dictionary(); + double milestone = distance; + double d0 = 0; + for (int i = 1; i < points.Count; i++) + { + var d = points[i - 1].DistanceTo(points[i]); + var d1 = d0 + d; + if (milestone > d0 && milestone <= d1) + { + double f = (milestone - d0) / (d1 - d0); + var lat = points[i - 1].Latitude + (f * (points[i].Latitude - points[i - 1].Latitude)); + var lon = points[i - 1].Longitude + (f * (points[i].Longitude - points[i - 1].Longitude)); + result.Add(milestone, new LatLon(lat, lon)); + milestone += distance; + } + + d0 = d1; + } + + return result; + } + + private static IEnumerable LoadGpxTrack(Stream s) + { + var r = new StreamReader(s); + var content = r.ReadToEnd(); + foreach (Match m in Regex.Matches(content, " rc.MeasureText(p, this.model.FontFamily, fontSize)).ToArray(); + var methodSizes = this.model.Methods.Select(p => rc.MeasureText(p, this.model.FontFamily, fontSize)).ToArray(); + var maxWidth = Math.Max(titleSize.Width, Math.Max(propertySizes.Max(p => p.Width), methodSizes.Max(p => p.Width))); + var totalHeight = titleSize.Height + propertySizes.Sum(p => p.Height) + methodSizes.Sum(p => p.Height); + + maxWidth = v.InverseTransform(maxWidth + fontSize / 2); + totalHeight = v.InverseTransform(totalHeight); + var bb = new BoundingBox(); + bb.Union(this.model.Position); + bb.Union(this.model.Position.X + maxWidth, this.model.Position.Y - totalHeight); + return bb; + } + + public override void Update(IRenderContext rc) + { + position = v.Transform(this.model.Position); + fontSize = v.Transform(this.model.FontSize); + } + + public override void Render(IRenderContext rc) + { + var x = position.X + 5; + var y = position.Y; + rc.DrawText(new ScreenPoint(x, y), this.model.Title, OxyColors.Black, this.model.FontFamily, fontSize, FontWeights.Bold); + var titleSize = rc.MeasureText(this.model.Title, this.model.FontFamily, fontSize, FontWeights.Bold); + y += titleSize.Height; + var y0 = y; + double maxWidth = titleSize.Width; + foreach (var p in this.model.Properties) + { + rc.DrawText(new ScreenPoint(x, y), p, OxyColors.Black, this.model.FontFamily, fontSize); + var size = rc.MeasureText(p, this.model.FontFamily, fontSize); + y += size.Height; + maxWidth = Math.Max(maxWidth, size.Width); + } + + var y1 = y; + foreach (var p in this.model.Methods) + { + rc.DrawText(new ScreenPoint(x, y), p, OxyColors.Black, this.model.FontFamily, fontSize); + var size = rc.MeasureText(p, this.model.FontFamily, fontSize); + y += size.Height; + maxWidth = Math.Max(maxWidth, size.Width); + } + + var rect = new OxyRect(position.X, position.Y, maxWidth + fontSize / 2, y - position.Y); + rc.DrawRectangle(rect, OxyColors.Undefined, OxyColors.Black, 1); + rc.DrawLineSegments(new[] + { + new ScreenPoint(position.X, y0), new ScreenPoint(rect.Right, y0), + new ScreenPoint(position.X, y1), new ScreenPoint(rect.Right, y1), + + }, OxyColors.Black, 1); + } + } + } +} diff --git a/Source/Examples/DrawingLibrary/Examples/UmlExamples.cs b/Source/Examples/DrawingLibrary/Examples/UmlExamples.cs new file mode 100644 index 000000000..aa454101a --- /dev/null +++ b/Source/Examples/DrawingLibrary/Examples/UmlExamples.cs @@ -0,0 +1,15 @@ +namespace DrawingDemo +{ + using OxyPlot.Drawing; + + public static class UmlExamples + { + [Example("UML diagram")] + public static Example Uml() + { + var drawing = new DrawingModel(); + drawing.Add(new UmlClassBox { Title = "BankAccount", Properties = new[] { "owner : String", "balance : Dollars = 0" }, Methods = new[] { "deposit ( amount : Dollars )", "withdrawal ( amount : Dollars )" } }); + return new Example(drawing); + } + } +} \ No newline at end of file diff --git a/Source/Examples/DrawingLibrary/Resources/Tracklog.gpx b/Source/Examples/DrawingLibrary/Resources/Tracklog.gpx new file mode 100644 index 000000000..d19ddea32 --- /dev/null +++ b/Source/Examples/DrawingLibrary/Resources/Tracklog.gpx @@ -0,0 +1,54265 @@ + + + + + Garmin Connect + + + + + Skitur i Nordmarka + + + 604.0 + + + + 98 + + + + + 604.0 + + + + 96 + + + + + 604.0 + + + + 95 + + + + + 603.7999877929688 + + + + 94 + + + + + 603.2000122070312 + + + + 97 + + + + + 603.4000244140625 + + + + 100 + + + + + 603.4000244140625 + + + + 103 + + + + + 603.5999755859375 + + + + 107 + + + + + 604.0 + + + + 109 + + + + + 604.5999755859375 + + + + 112 + + + + + 604.5999755859375 + + + + 113 + + + + + 604.7999877929688 + + + + 116 + + + + + 605.2000122070312 + + + + 117 + + + + + 605.5999755859375 + + + + 118 + + + + + 606.4000244140625 + + + + 119 + + + + + 606.5999755859375 + + + + 120 + + + + + 607.0 + + + + 120 + + + + + 607.2000122070312 + + + + 118 + + + + + 607.7999877929688 + + + + 120 + + + + + 608.0 + + + + 123 + + + + + 608.4000244140625 + + + + 125 + + + + + 608.7999877929688 + + + + 127 + + + + + 609.2000122070312 + + + + 129 + + + + + 609.5999755859375 + + + + 130 + + + + + 610.4000244140625 + + + + 133 + + + + + 611.5999755859375 + + + + 135 + + + + + 613.0 + + + + 136 + + + + + 614.4000244140625 + + + + 138 + + + + + 615.5999755859375 + + + + 140 + + + + + 616.2000122070312 + + + + 141 + + + + + 616.5999755859375 + + + + 141 + + + + + 617.2000122070312 + + + + 142 + + + + + 618.0 + + + + 143 + + + + + 617.7999877929688 + + + + 143 + + + + + 617.4000244140625 + + + + 143 + + + + + 614.7999877929688 + + + + 143 + + + + + 612.0 + + + + 142 + + + + + 611.4000244140625 + + + + 141 + + + + + 610.2000122070312 + + + + 141 + + + + + 608.5999755859375 + + + + 141 + + + + + 606.2000122070312 + + + + 139 + + + + + 605.4000244140625 + + + + 140 + + + + + 605.4000244140625 + + + + 140 + + + + + 605.4000244140625 + + + + 140 + + + + + 606.2000122070312 + + + + 141 + + + + + 607.2000122070312 + + + + 141 + + + + + 608.2000122070312 + + + + 142 + + + + + 608.7999877929688 + + + + 143 + + + + + 610.0 + + + + 144 + + + + + 611.4000244140625 + + + + 146 + + + + + 613.4000244140625 + + + + 147 + + + + + 614.5999755859375 + + + + 148 + + + + + 615.7999877929688 + + + + 150 + + + + + 616.4000244140625 + + + + 151 + + + + + 617.4000244140625 + + + + 153 + + + + + 617.4000244140625 + + + + 153 + + + + + 618.0 + + + + 153 + + + + + 618.2000122070312 + + + + 154 + + + + + 619.0 + + + + 153 + + + + + 619.7999877929688 + + + + 153 + + + + + 619.7999877929688 + + + + 152 + + + + + 619.4000244140625 + + + + 152 + + + + + 618.7999877929688 + + + + 151 + + + + + 618.2000122070312 + + + + 150 + + + + + 617.5999755859375 + + + + 150 + + + + + 615.5999755859375 + + + + 150 + + + + + 613.7999877929688 + + + + 149 + + + + + 612.2000122070312 + + + + 148 + + + + + 612.4000244140625 + + + + 147 + + + + + 611.7999877929688 + + + + 147 + + + + + 611.7999877929688 + + + + 147 + + + + + 611.5999755859375 + + + + 146 + + + + + 611.4000244140625 + + + + 146 + + + + + 611.4000244140625 + + + + 146 + + + + + 611.2000122070312 + + + + 146 + + + + + 611.0 + + + + 146 + + + + + 611.0 + + + + 146 + + + + + 611.2000122070312 + + + + 145 + + + + + 611.5999755859375 + + + + 145 + + + + + 611.7999877929688 + + + + 146 + + + + + 612.4000244140625 + + + + 146 + + + + + 612.5999755859375 + + + + 146 + + + + + 614.0 + + + + 147 + + + + + 615.7999877929688 + + + + 147 + + + + + 617.0 + + + + 148 + + + + + 618.2000122070312 + + + + 149 + + + + + 618.7999877929688 + + + + 151 + + + + + 619.2000122070312 + + + + 152 + + + + + 619.4000244140625 + + + + 152 + + + + + 619.5999755859375 + + + + 152 + + + + + 620.5999755859375 + + + + 152 + + + + + 621.5999755859375 + + + + 152 + + + + + 622.7999877929688 + + + + 152 + + + + + 623.2000122070312 + + + + 152 + + + + + 624.0 + + + + 151 + + + + + 624.5999755859375 + + + + 152 + + + + + 625.4000244140625 + + + + 152 + + + + + 625.5999755859375 + + + + 152 + + + + + 626.2000122070312 + + + + 153 + + + + + 627.0 + + + + 153 + + + + + 628.0 + + + + 153 + + + + + 629.2000122070312 + + + + 154 + + + + + 630.2000122070312 + + + + 155 + + + + + 631.2000122070312 + + + + 156 + + + + + 632.0 + + + + 157 + + + + + 632.4000244140625 + + + + 158 + + + + + 633.2000122070312 + + + + 158 + + + + + 633.4000244140625 + + + + 159 + + + + + 633.5999755859375 + + + + 158 + + + + + 633.5999755859375 + + + + 157 + + + + + 633.5999755859375 + + + + 157 + + + + + 633.2000122070312 + + + + 156 + + + + + 633.0 + + + + 155 + + + + + 633.0 + + + + 155 + + + + + 634.2000122070312 + + + + 154 + + + + + 634.7999877929688 + + + + 153 + + + + + 635.4000244140625 + + + + 153 + + + + + 635.5999755859375 + + + + 153 + + + + + 637.2000122070312 + + + + 151 + + + + + 637.4000244140625 + + + + 151 + + + + + 637.7999877929688 + + + + 151 + + + + + 638.2000122070312 + + + + 151 + + + + + 638.4000244140625 + + + + 151 + + + + + 638.0 + + + + 150 + + + + + 636.2000122070312 + + + + 149 + + + + + 635.2000122070312 + + + + 149 + + + + + 634.5999755859375 + + + + 149 + + + + + 632.5999755859375 + + + + 148 + + + + + 631.2000122070312 + + + + 147 + + + + + 631.2000122070312 + + + + 147 + + + + + 631.0 + + + + 145 + + + + + 631.0 + + + + 144 + + + + + 631.2000122070312 + + + + 143 + + + + + 631.4000244140625 + + + + 143 + + + + + 629.0 + + + + 141 + + + + + 628.5999755859375 + + + + 141 + + + + + 627.0 + + + + 141 + + + + + 626.2000122070312 + + + + 142 + + + + + 626.2000122070312 + + + + 142 + + + + + 626.2000122070312 + + + + 143 + + + + + 627.0 + + + + 144 + + + + + 628.0 + + + + 145 + + + + + 629.4000244140625 + + + + 145 + + + + + 630.5999755859375 + + + + 147 + + + + + 630.7999877929688 + + + + 147 + + + + + 631.0 + + + + 149 + + + + + 631.0 + + + + 149 + + + + + 631.0 + + + + 150 + + + + + 631.5999755859375 + + + + 150 + + + + + 632.2000122070312 + + + + 151 + + + + + 633.0 + + + + 151 + + + + + 633.4000244140625 + + + + 152 + + + + + 633.7999877929688 + + + + 153 + + + + + 634.0 + + + + 154 + + + + + 634.0 + + + + 155 + + + + + 634.2000122070312 + + + + 156 + + + + + 634.4000244140625 + + + + 156 + + + + + 635.4000244140625 + + + + 155 + + + + + 635.7999877929688 + + + + 156 + + + + + 636.0 + + + + 155 + + + + + 636.5999755859375 + + + + 154 + + + + + 637.0 + + + + 152 + + + + + 637.5999755859375 + + + + 152 + + + + + 637.7999877929688 + + + + 152 + + + + + 637.7999877929688 + + + + 151 + + + + + 637.7999877929688 + + + + 151 + + + + + 637.4000244140625 + + + + 151 + + + + + 637.0 + + + + 150 + + + + + 636.4000244140625 + + + + 149 + + + + + 636.2000122070312 + + + + 148 + + + + + 635.7999877929688 + + + + 147 + + + + + 635.0 + + + + 146 + + + + + 634.7999877929688 + + + + 146 + + + + + 634.5999755859375 + + + + 145 + + + + + 634.5999755859375 + + + + 145 + + + + + 634.5999755859375 + + + + 145 + + + + + 634.5999755859375 + + + + 143 + + + + + 634.5999755859375 + + + + 142 + + + + + 634.5999755859375 + + + + 141 + + + + + 634.4000244140625 + + + + 140 + + + + + 632.4000244140625 + + + + 139 + + + + + 631.5999755859375 + + + + 138 + + + + + 629.7999877929688 + + + + 137 + + + + + 628.4000244140625 + + + + 135 + + + + + 627.5999755859375 + + + + 134 + + + + + 626.7999877929688 + + + + 134 + + + + + 624.2000122070312 + + + + 133 + + + + + 623.4000244140625 + + + + 132 + + + + + 622.5999755859375 + + + + 131 + + + + + 622.0 + + + + 129 + + + + + 621.5999755859375 + + + + 129 + + + + + 620.7999877929688 + + + + 127 + + + + + 620.4000244140625 + + + + 127 + + + + + 619.7999877929688 + + + + 128 + + + + + 619.7999877929688 + + + + 129 + + + + + 619.7999877929688 + + + + 129 + + + + + 619.7999877929688 + + + + 130 + + + + + 619.7999877929688 + + + + 131 + + + + + 619.7999877929688 + + + + 132 + + + + + 619.7999877929688 + + + + 132 + + + + + 620.0 + + + + 134 + + + + + 620.0 + + + + 134 + + + + + 620.0 + + + + 132 + + + + + 619.7999877929688 + + + + 132 + + + + + 619.7999877929688 + + + + 131 + + + + + 619.5999755859375 + + + + 130 + + + + + 619.5999755859375 + + + + 130 + + + + + 619.4000244140625 + + + + 130 + + + + + 619.2000122070312 + + + + 130 + + + + + 619.0 + + + + 130 + + + + + 618.7999877929688 + + + + 130 + + + + + 618.2000122070312 + + + + 128 + + + + + 617.5999755859375 + + + + 127 + + + + + 617.2000122070312 + + + + 127 + + + + + 616.7999877929688 + + + + 127 + + + + + 616.4000244140625 + + + + 127 + + + + + 616.2000122070312 + + + + 126 + + + + + 615.5999755859375 + + + + 126 + + + + + 614.7999877929688 + + + + 125 + + + + + 614.5999755859375 + + + + 125 + + + + + 613.5999755859375 + + + + 126 + + + + + 613.4000244140625 + + + + 126 + + + + + 612.5999755859375 + + + + 128 + + + + + 612.7999877929688 + + + + 129 + + + + + 613.0 + + + + 129 + + + + + 613.2000122070312 + + + + 130 + + + + + 613.5999755859375 + + + + 130 + + + + + 613.7999877929688 + + + + 131 + + + + + 614.0 + + + + 132 + + + + + 614.0 + + + + 132 + + + + + 614.0 + + + + 133 + + + + + 613.7999877929688 + + + + 134 + + + + + 613.7999877929688 + + + + 134 + + + + + 613.7999877929688 + + + + 134 + + + + + 614.2000122070312 + + + + 135 + + + + + 614.7999877929688 + + + + 136 + + + + + 615.5999755859375 + + + + 137 + + + + + 619.2000122070312 + + + + 138 + + + + + 621.5999755859375 + + + + 137 + + + + + 622.0 + + + + 138 + + + + + 622.5999755859375 + + + + 137 + + + + + 623.7999877929688 + + + + 138 + + + + + 624.7999877929688 + + + + 138 + + + + + 625.2000122070312 + + + + 138 + + + + + 625.7999877929688 + + + + 139 + + + + + 626.2000122070312 + + + + 139 + + + + + 628.2000122070312 + + + + 141 + + + + + 629.0 + + + + 144 + + + + + 630.2000122070312 + + + + 147 + + + + + 631.0 + + + + 150 + + + + + 631.5999755859375 + + + + 151 + + + + + 632.0 + + + + 154 + + + + + 632.2000122070312 + + + + 155 + + + + + 632.7999877929688 + + + + 157 + + + + + 633.0 + + + + 157 + + + + + 633.0 + + + + 157 + + + + + 633.2000122070312 + + + + 158 + + + + + 633.5999755859375 + + + + 159 + + + + + 633.5999755859375 + + + + 159 + + + + + 633.0 + + + + 159 + + + + + 633.2000122070312 + + + + 158 + + + + + 633.2000122070312 + + + + 158 + + + + + 633.5999755859375 + + + + 156 + + + + + 633.7999877929688 + + + + 155 + + + + + 634.0 + + + + 155 + + + + + 634.0 + + + + 154 + + + + + 635.2000122070312 + + + + 154 + + + + + 635.4000244140625 + + + + 154 + + + + + 636.0 + + + + 153 + + + + + 636.7999877929688 + + + + 154 + + + + + 637.2000122070312 + + + + 155 + + + + + 637.5999755859375 + + + + 156 + + + + + 637.5999755859375 + + + + 156 + + + + + 638.4000244140625 + + + + 157 + + + + + 639.5999755859375 + + + + 159 + + + + + 641.2000122070312 + + + + 160 + + + + + 641.2000122070312 + + + + 160 + + + + + 641.4000244140625 + + + + 159 + + + + + 642.2000122070312 + + + + 159 + + + + + 643.0 + + + + 160 + + + + + 644.0 + + + + 159 + + + + + 645.0 + + + + 160 + + + + + 645.2000122070312 + + + + 160 + + + + + 645.7999877929688 + + + + 160 + + + + + 647.2000122070312 + + + + 160 + + + + + 647.4000244140625 + + + + 160 + + + + + 648.5999755859375 + + + + 160 + + + + + 649.0 + + + + 159 + + + + + 649.2000122070312 + + + + 159 + + + + + 649.5999755859375 + + + + 159 + + + + + 649.5999755859375 + + + + 159 + + + + + 649.7999877929688 + + + + 159 + + + + + 650.0 + + + + 159 + + + + + 650.5999755859375 + + + + 158 + + + + + 650.5999755859375 + + + + 157 + + + + + 650.4000244140625 + + + + 156 + + + + + 649.7999877929688 + + + + 156 + + + + + 649.0 + + + + 156 + + + + + 648.2000122070312 + + + + 156 + + + + + 646.4000244140625 + + + + 154 + + + + + 644.4000244140625 + + + + 153 + + + + + 643.7999877929688 + + + + 153 + + + + + 642.5999755859375 + + + + 153 + + + + + 642.0 + + + + 153 + + + + + 641.4000244140625 + + + + 152 + + + + + 640.4000244140625 + + + + 152 + + + + + 640.2000122070312 + + + + 151 + + + + + 640.2000122070312 + + + + 149 + + + + + 642.0 + + + + 148 + + + + + 642.4000244140625 + + + + 147 + + + + + 642.7999877929688 + + + + 147 + + + + + 643.0 + + + + 147 + + + + + 644.2000122070312 + + + + 148 + + + + + 645.0 + + + + 149 + + + + + 646.5999755859375 + + + + 150 + + + + + 647.4000244140625 + + + + 150 + + + + + 648.4000244140625 + + + + 151 + + + + + 649.0 + + + + 150 + + + + + 649.7999877929688 + + + + 151 + + + + + 650.0 + + + + 151 + + + + + 650.2000122070312 + + + + 151 + + + + + 650.5999755859375 + + + + 152 + + + + + 651.0 + + + + 152 + + + + + 651.2000122070312 + + + + 152 + + + + + 651.4000244140625 + + + + 151 + + + + + 651.7999877929688 + + + + 152 + + + + + 652.2000122070312 + + + + 152 + + + + + 652.2000122070312 + + + + 153 + + + + + 652.4000244140625 + + + + 154 + + + + + 652.4000244140625 + + + + 154 + + + + + 652.4000244140625 + + + + 154 + + + + + 652.4000244140625 + + + + 154 + + + + + 652.5999755859375 + + + + 154 + + + + + 652.7999877929688 + + + + 153 + + + + + 652.7999877929688 + + + + 154 + + + + + 653.4000244140625 + + + + 153 + + + + + 654.2000122070312 + + + + 152 + + + + + 654.7999877929688 + + + + 152 + + + + + 656.0 + + + + 152 + + + + + 656.4000244140625 + + + + 152 + + + + + 657.4000244140625 + + + + 152 + + + + + 658.5999755859375 + + + + 152 + + + + + 659.7999877929688 + + + + 153 + + + + + 660.4000244140625 + + + + 153 + + + + + 661.0 + + + + 155 + + + + + 661.7999877929688 + + + + 156 + + + + + 662.2000122070312 + + + + 157 + + + + + 662.4000244140625 + + + + 157 + + + + + 663.0 + + + + 158 + + + + + 663.5999755859375 + + + + 157 + + + + + 663.5999755859375 + + + + 157 + + + + + 663.0 + + + + 156 + + + + + 662.5999755859375 + + + + 155 + + + + + 662.4000244140625 + + + + 154 + + + + + 662.4000244140625 + + + + 153 + + + + + 662.0 + + + + 152 + + + + + 661.2000122070312 + + + + 149 + + + + + 660.4000244140625 + + + + 148 + + + + + 660.2000122070312 + + + + 148 + + + + + 658.5999755859375 + + + + 146 + + + + + 657.0 + + + + 144 + + + + + 656.4000244140625 + + + + 144 + + + + + 655.2000122070312 + + + + 142 + + + + + 654.2000122070312 + + + + 140 + + + + + 652.4000244140625 + + + + 137 + + + + + 651.5999755859375 + + + + 137 + + + + + 651.0 + + + + 136 + + + + + 650.2000122070312 + + + + 136 + + + + + 648.7999877929688 + + + + 136 + + + + + 647.2000122070312 + + + + 135 + + + + + 646.2000122070312 + + + + 135 + + + + + 645.7999877929688 + + + + 135 + + + + + 645.7999877929688 + + + + 135 + + + + + 645.4000244140625 + + + + 134 + + + + + 645.0 + + + + 135 + + + + + 644.4000244140625 + + + + 134 + + + + + 644.2000122070312 + + + + 135 + + + + + 644.0 + + + + 136 + + + + + 643.7999877929688 + + + + 137 + + + + + 643.5999755859375 + + + + 138 + + + + + 643.7999877929688 + + + + 139 + + + + + 644.0 + + + + 139 + + + + + 644.4000244140625 + + + + 140 + + + + + 644.5999755859375 + + + + 141 + + + + + 644.5999755859375 + + + + 141 + + + + + 644.7999877929688 + + + + 141 + + + + + 644.7999877929688 + + + + 142 + + + + + 644.5999755859375 + + + + 142 + + + + + 644.5999755859375 + + + + 143 + + + + + 645.7999877929688 + + + + 144 + + + + + 646.2000122070312 + + + + 144 + + + + + 646.4000244140625 + + + + 144 + + + + + 646.7999877929688 + + + + 144 + + + + + 647.2000122070312 + + + + 144 + + + + + 647.2000122070312 + + + + 144 + + + + + 647.2000122070312 + + + + 143 + + + + + 647.2000122070312 + + + + 143 + + + + + 647.2000122070312 + + + + 143 + + + + + 646.2000122070312 + + + + 143 + + + + + 646.0 + + + + 143 + + + + + 644.5999755859375 + + + + 142 + + + + + 644.2000122070312 + + + + 142 + + + + + 642.5999755859375 + + + + 143 + + + + + 640.5999755859375 + + + + 142 + + + + + 639.4000244140625 + + + + 142 + + + + + 638.5999755859375 + + + + 143 + + + + + 638.0 + + + + 143 + + + + + 637.5999755859375 + + + + 142 + + + + + 637.5999755859375 + + + + 142 + + + + + 637.7999877929688 + + + + 142 + + + + + 638.0 + + + + 142 + + + + + 638.0 + + + + 142 + + + + + 638.0 + + + + 143 + + + + + 638.0 + + + + 143 + + + + + 638.2000122070312 + + + + 142 + + + + + 638.2000122070312 + + + + 142 + + + + + 638.0 + + + + 141 + + + + + 637.2000122070312 + + + + 140 + + + + + 637.2000122070312 + + + + 140 + + + + + 636.4000244140625 + + + + 139 + + + + + 636.0 + + + + 139 + + + + + 634.7999877929688 + + + + 139 + + + + + 633.2000122070312 + + + + 137 + + + + + 632.0 + + + + 135 + + + + + 631.7999877929688 + + + + 135 + + + + + 630.5999755859375 + + + + 133 + + + + + 630.0 + + + + 133 + + + + + 629.7999877929688 + + + + 133 + + + + + 629.2000122070312 + + + + 134 + + + + + 629.0 + + + + 134 + + + + + 628.5999755859375 + + + + 134 + + + + + 627.4000244140625 + + + + 133 + + + + + 627.2000122070312 + + + + 133 + + + + + 627.0 + + + + 133 + + + + + 626.7999877929688 + + + + 132 + + + + + 626.5999755859375 + + + + 133 + + + + + 626.5999755859375 + + + + 133 + + + + + 626.4000244140625 + + + + 133 + + + + + 626.7999877929688 + + + + 133 + + + + + 627.4000244140625 + + + + 133 + + + + + 627.7999877929688 + + + + 134 + + + + + 628.2000122070312 + + + + 134 + + + + + 628.2000122070312 + + + + 133 + + + + + 628.2000122070312 + + + + 133 + + + + + 628.0 + + + + 133 + + + + + 628.0 + + + + 133 + + + + + 627.7999877929688 + + + + 132 + + + + + 627.5999755859375 + + + + 132 + + + + + 627.4000244140625 + + + + 132 + + + + + 626.5999755859375 + + + + 131 + + + + + 625.5999755859375 + + + + 132 + + + + + 624.4000244140625 + + + + 133 + + + + + 622.7999877929688 + + + + 131 + + + + + 621.2000122070312 + + + + 130 + + + + + 620.7999877929688 + + + + 130 + + + + + 619.5999755859375 + + + + 130 + + + + + 619.2000122070312 + + + + 130 + + + + + 616.5999755859375 + + + + 130 + + + + + 614.7999877929688 + + + + 130 + + + + + 614.4000244140625 + + + + 129 + + + + + 614.0 + + + + 128 + + + + + 613.4000244140625 + + + + 125 + + + + + 613.4000244140625 + + + + 124 + + + + + 613.2000122070312 + + + + 122 + + + + + 613.0 + + + + 122 + + + + + 613.0 + + + + 120 + + + + + 613.0 + + + + 119 + + + + + 613.0 + + + + 120 + + + + + 613.0 + + + + 120 + + + + + 613.0 + + + + 122 + + + + + 613.2000122070312 + + + + 122 + + + + + 613.5999755859375 + + + + 121 + + + + + 613.5999755859375 + + + + 121 + + + + + 613.5999755859375 + + + + 121 + + + + + 613.5999755859375 + + + + 121 + + + + + 613.2000122070312 + + + + 122 + + + + + 612.7999877929688 + + + + 122 + + + + + 612.2000122070312 + + + + 122 + + + + + 611.5999755859375 + + + + 123 + + + + + 611.7999877929688 + + + + 123 + + + + + 611.7999877929688 + + + + 125 + + + + + 611.7999877929688 + + + + 125 + + + + + 611.4000244140625 + + + + 126 + + + + + 611.2000122070312 + + + + 126 + + + + + 610.5999755859375 + + + + 126 + + + + + 610.4000244140625 + + + + 126 + + + + + 609.7999877929688 + + + + 128 + + + + + 609.0 + + + + 128 + + + + + 608.0 + + + + 127 + + + + + 606.0 + + + + 127 + + + + + 605.4000244140625 + + + + 126 + + + + + 605.2000122070312 + + + + 127 + + + + + 604.0 + + + + 127 + + + + + 603.7999877929688 + + + + 127 + + + + + 603.4000244140625 + + + + 127 + + + + + 603.0 + + + + 126 + + + + + 602.7999877929688 + + + + 127 + + + + + 602.0 + + + + 127 + + + + + 602.2000122070312 + + + + 127 + + + + + 602.4000244140625 + + + + 127 + + + + + 602.5999755859375 + + + + 127 + + + + + 603.2000122070312 + + + + 127 + + + + + 603.5999755859375 + + + + 128 + + + + + 603.4000244140625 + + + + 129 + + + + + 602.7999877929688 + + + + 131 + + + + + 602.0 + + + + 132 + + + + + 602.0 + + + + 132 + + + + + 601.5999755859375 + + + + 134 + + + + + 601.5999755859375 + + + + 134 + + + + + 601.5999755859375 + + + + 135 + + + + + 601.7999877929688 + + + + 135 + + + + + 601.7999877929688 + + + + 136 + + + + + 602.0 + + + + 137 + + + + + 602.0 + + + + 137 + + + + + 601.7999877929688 + + + + 138 + + + + + 601.5999755859375 + + + + 139 + + + + + 601.5999755859375 + + + + 139 + + + + + 601.0 + + + + 139 + + + + + 601.0 + + + + 139 + + + + + 600.7999877929688 + + + + 140 + + + + + 601.0 + + + + 140 + + + + + 601.0 + + + + 140 + + + + + 601.2000122070312 + + + + 139 + + + + + 601.4000244140625 + + + + 139 + + + + + 601.0 + + + + 139 + + + + + 599.4000244140625 + + + + 138 + + + + + 599.0 + + + + 138 + + + + + 597.7999877929688 + + + + 137 + + + + + 597.0 + + + + 137 + + + + + 595.4000244140625 + + + + 135 + + + + + 595.2000122070312 + + + + 135 + + + + + 594.5999755859375 + + + + 135 + + + + + 593.5999755859375 + + + + 134 + + + + + 592.4000244140625 + + + + 132 + + + + + 592.2000122070312 + + + + 131 + + + + + 592.7999877929688 + + + + 128 + + + + + 593.2000122070312 + + + + 127 + + + + + 592.7999877929688 + + + + 125 + + + + + 592.2000122070312 + + + + 125 + + + + + 591.2000122070312 + + + + 125 + + + + + 591.0 + + + + 124 + + + + + 591.0 + + + + 125 + + + + + 590.5999755859375 + + + + 128 + + + + + 590.5999755859375 + + + + 129 + + + + + 590.4000244140625 + + + + 131 + + + + + 590.4000244140625 + + + + 132 + + + + + 590.5999755859375 + + + + 134 + + + + + 590.5999755859375 + + + + 134 + + + + + 590.7999877929688 + + + + 133 + + + + + 590.5999755859375 + + + + 133 + + + + + 590.4000244140625 + + + + 133 + + + + + 590.4000244140625 + + + + 133 + + + + + 590.4000244140625 + + + + 133 + + + + + 590.5999755859375 + + + + 134 + + + + + 590.7999877929688 + + + + 135 + + + + + 591.0 + + + + 135 + + + + + 591.4000244140625 + + + + 135 + + + + + 591.4000244140625 + + + + 135 + + + + + 591.4000244140625 + + + + 135 + + + + + 591.4000244140625 + + + + 134 + + + + + 591.4000244140625 + + + + 133 + + + + + 591.2000122070312 + + + + 132 + + + + + 590.7999877929688 + + + + 130 + + + + + 590.7999877929688 + + + + 130 + + + + + 590.7999877929688 + + + + 131 + + + + + 590.7999877929688 + + + + 131 + + + + + 590.7999877929688 + + + + 128 + + + + + 590.7999877929688 + + + + 125 + + + + + 590.7999877929688 + + + + 122 + + + + + 590.7999877929688 + + + + 119 + + + + + 590.7999877929688 + + + + 116 + + + + + 590.7999877929688 + + + + 113 + + + + + 590.7999877929688 + + + + 110 + + + + + 590.7999877929688 + + + + 113 + + + + + 590.7999877929688 + + + + 110 + + + + + 590.7999877929688 + + + + 107 + + + + + 590.7999877929688 + + + + 108 + + + + + 590.7999877929688 + + + + 111 + + + + + 590.7999877929688 + + + + 114 + + + + + 590.7999877929688 + + + + 113 + + + + + 590.5999755859375 + + + + 112 + + + + + 590.4000244140625 + + + + 109 + + + + + 590.4000244140625 + + + + 108 + + + + + 590.0 + + + + 108 + + + + + 589.5999755859375 + + + + 109 + + + + + 589.4000244140625 + + + + 110 + + + + + 589.0 + + + + 111 + + + + + 588.7999877929688 + + + + 119 + + + + + 588.5999755859375 + + + + 119 + + + + + 588.4000244140625 + + + + 118 + + + + + 587.7999877929688 + + + + 117 + + + + + 586.7999877929688 + + + + 115 + + + + + 586.7999877929688 + + + + 115 + + + + + 586.5999755859375 + + + + 115 + + + + + 586.5999755859375 + + + + 115 + + + + + 586.7999877929688 + + + + 115 + + + + + 586.7999877929688 + + + + 115 + + + + + 587.0 + + + + 117 + + + + + 587.4000244140625 + + + + 119 + + + + + 587.7999877929688 + + + + 120 + + + + + 588.2000122070312 + + + + 122 + + + + + 588.4000244140625 + + + + 125 + + + + + 588.5999755859375 + + + + 125 + + + + + 588.7999877929688 + + + + 126 + + + + + 588.7999877929688 + + + + 126 + + + + + 588.5999755859375 + + + + 126 + + + + + 588.4000244140625 + + + + 126 + + + + + 588.4000244140625 + + + + 127 + + + + + 588.4000244140625 + + + + 127 + + + + + 588.4000244140625 + + + + 127 + + + + + 588.5999755859375 + + + + 128 + + + + + 588.7999877929688 + + + + 129 + + + + + 588.7999877929688 + + + + 130 + + + + + 589.0 + + + + 130 + + + + + 589.2000122070312 + + + + 132 + + + + + 589.2000122070312 + + + + 133 + + + + + 589.0 + + + + 134 + + + + + 588.7999877929688 + + + + 134 + + + + + 588.4000244140625 + + + + 135 + + + + + 588.2000122070312 + + + + 135 + + + + + 588.2000122070312 + + + + 135 + + + + + 588.4000244140625 + + + + 135 + + + + + 588.4000244140625 + + + + 135 + + + + + 588.5999755859375 + + + + 137 + + + + + 588.5999755859375 + + + + 137 + + + + + 588.7999877929688 + + + + 138 + + + + + 588.7999877929688 + + + + 138 + + + + + 589.0 + + + + 139 + + + + + 589.2000122070312 + + + + 140 + + + + + 589.2000122070312 + + + + 140 + + + + + 589.2000122070312 + + + + 140 + + + + + 589.2000122070312 + + + + 140 + + + + + 589.4000244140625 + + + + 140 + + + + + 589.4000244140625 + + + + 141 + + + + + 589.7999877929688 + + + + 140 + + + + + 589.7999877929688 + + + + 141 + + + + + 590.4000244140625 + + + + 141 + + + + + 590.7999877929688 + + + + 141 + + + + + 591.0 + + + + 141 + + + + + 591.5999755859375 + + + + 140 + + + + + 592.0 + + + + 140 + + + + + 593.5999755859375 + + + + 139 + + + + + 595.4000244140625 + + + + 141 + + + + + 596.7999877929688 + + + + 141 + + + + + 597.5999755859375 + + + + 141 + + + + + 598.5999755859375 + + + + 142 + + + + + 599.5999755859375 + + + + 142 + + + + + 601.2000122070312 + + + + 143 + + + + + 602.4000244140625 + + + + 143 + + + + + 603.4000244140625 + + + + 144 + + + + + 604.4000244140625 + + + + 145 + + + + + 605.0 + + + + 146 + + + + + 605.0 + + + + 146 + + + + + 605.5999755859375 + + + + 146 + + + + + 605.5999755859375 + + + + 147 + + + + + 606.0 + + + + 147 + + + + + 606.4000244140625 + + + + 147 + + + + + 606.5999755859375 + + + + 147 + + + + + 607.0 + + + + 148 + + + + + 608.0 + + + + 149 + + + + + 609.5999755859375 + + + + 149 + + + + + 610.4000244140625 + + + + 149 + + + + + 611.0 + + + + 148 + + + + + 612.2000122070312 + + + + 147 + + + + + 613.2000122070312 + + + + 147 + + + + + 614.2000122070312 + + + + 146 + + + + + 614.7999877929688 + + + + 146 + + + + + 614.7999877929688 + + + + 143 + + + + + 614.5999755859375 + + + + 143 + + + + + 613.4000244140625 + + + + 141 + + + + + 612.7999877929688 + + + + 140 + + + + + 610.4000244140625 + + + + 138 + + + + + 607.7999877929688 + + + + 137 + + + + + 604.2000122070312 + + + + 135 + + + + + 602.4000244140625 + + + + 133 + + + + + 600.2000122070312 + + + + 130 + + + + + 597.5999755859375 + + + + 128 + + + + + 595.4000244140625 + + + + 127 + + + + + 593.5999755859375 + + + + 124 + + + + + 593.2000122070312 + + + + 124 + + + + + 592.7999877929688 + + + + 124 + + + + + 592.4000244140625 + + + + 124 + + + + + 592.2000122070312 + + + + 124 + + + + + 592.0 + + + + 123 + + + + + 591.5999755859375 + + + + 124 + + + + + 590.4000244140625 + + + + 123 + + + + + 589.7999877929688 + + + + 122 + + + + + 588.2000122070312 + + + + 120 + + + + + 584.4000244140625 + + + + 122 + + + + + 580.7999877929688 + + + + 119 + + + + + 579.5999755859375 + + + + 118 + + + + + 579.2000122070312 + + + + 118 + + + + + 578.0 + + + + 119 + + + + + 577.7999877929688 + + + + 121 + + + + + 577.7999877929688 + + + + 122 + + + + + 577.5999755859375 + + + + 123 + + + + + 577.4000244140625 + + + + 122 + + + + + 577.2000122070312 + + + + 120 + + + + + 576.7999877929688 + + + + 119 + + + + + 576.4000244140625 + + + + 120 + + + + + 576.4000244140625 + + + + 121 + + + + + 576.4000244140625 + + + + 118 + + + + + 576.2000122070312 + + + + 119 + + + + + 575.7999877929688 + + + + 118 + + + + + 575.0 + + + + 119 + + + + + 573.7999877929688 + + + + 118 + + + + + 573.4000244140625 + + + + 117 + + + + + 573.2000122070312 + + + + 116 + + + + + 573.0 + + + + 115 + + + + + 572.7999877929688 + + + + 113 + + + + + 572.2000122070312 + + + + 114 + + + + + 571.5999755859375 + + + + 113 + + + + + 569.5999755859375 + + + + 114 + + + + + 567.4000244140625 + + + + 114 + + + + + 566.7999877929688 + + + + 115 + + + + + 565.7999877929688 + + + + 117 + + + + + 565.2000122070312 + + + + 118 + + + + + 564.7999877929688 + + + + 119 + + + + + 564.5999755859375 + + + + 120 + + + + + 564.0 + + + + 121 + + + + + 564.0 + + + + 121 + + + + + 563.2000122070312 + + + + 122 + + + + + 563.0 + + + + 122 + + + + + 562.2000122070312 + + + + 124 + + + + + 561.7999877929688 + + + + 123 + + + + + 561.7999877929688 + + + + 123 + + + + + 561.7999877929688 + + + + 122 + + + + + 561.7999877929688 + + + + 125 + + + + + 561.7999877929688 + + + + 120 + + + + + 561.7999877929688 + + + + 120 + + + + + 561.7999877929688 + + + + 117 + + + + + 561.7999877929688 + + + + 114 + + + + + 561.7999877929688 + + + + 117 + + + + + 561.7999877929688 + + + + 120 + + + + + 561.7999877929688 + + + + 117 + + + + + 561.7999877929688 + + + + 111 + + + + + 561.7999877929688 + + + + 111 + + + + + 561.7999877929688 + + + + 111 + + + + + 561.7999877929688 + + + + 112 + + + + + 561.7999877929688 + + + + 111 + + + + + 562.5999755859375 + + + + 112 + + + + + 563.2000122070312 + + + + 112 + + + + + 563.5999755859375 + + + + 115 + + + + + 563.7999877929688 + + + + 117 + + + + + 564.0 + + + + 118 + + + + + 564.4000244140625 + + + + 120 + + + + + 564.4000244140625 + + + + 122 + + + + + 564.4000244140625 + + + + 123 + + + + + 564.2000122070312 + + + + 124 + + + + + 564.2000122070312 + + + + 124 + + + + + 563.5999755859375 + + + + 126 + + + + + 563.0 + + + + 127 + + + + + 562.7999877929688 + + + + 127 + + + + + 562.5999755859375 + + + + 127 + + + + + 562.0 + + + + 127 + + + + + 562.2000122070312 + + + + 127 + + + + + 562.5999755859375 + + + + 128 + + + + + 563.4000244140625 + + + + 129 + + + + + 563.7999877929688 + + + + 129 + + + + + 564.2000122070312 + + + + 130 + + + + + 564.4000244140625 + + + + 131 + + + + + 564.4000244140625 + + + + 131 + + + + + 564.7999877929688 + + + + 131 + + + + + 564.7999877929688 + + + + 132 + + + + + 565.0 + + + + 132 + + + + + 565.2000122070312 + + + + 132 + + + + + 565.2000122070312 + + + + 132 + + + + + 565.2000122070312 + + + + 132 + + + + + 565.5999755859375 + + + + 133 + + + + + 565.5999755859375 + + + + 133 + + + + + 566.2000122070312 + + + + 134 + + + + + 566.2000122070312 + + + + 134 + + + + + 566.4000244140625 + + + + 134 + + + + + 566.4000244140625 + + + + 134 + + + + + 566.4000244140625 + + + + 134 + + + + + 566.5999755859375 + + + + 136 + + + + + 567.0 + + + + 137 + + + + + 567.7999877929688 + + + + 137 + + + + + 568.4000244140625 + + + + 138 + + + + + 568.5999755859375 + + + + 137 + + + + + 568.5999755859375 + + + + 138 + + + + + 568.5999755859375 + + + + 137 + + + + + 568.5999755859375 + + + + 137 + + + + + 568.4000244140625 + + + + 138 + + + + + 568.4000244140625 + + + + 137 + + + + + 568.4000244140625 + + + + 138 + + + + + 568.7999877929688 + + + + 137 + + + + + 569.4000244140625 + + + + 137 + + + + + 570.0 + + + + 136 + + + + + 570.2000122070312 + + + + 137 + + + + + 570.2000122070312 + + + + 136 + + + + + 570.2000122070312 + + + + 136 + + + + + 570.2000122070312 + + + + 137 + + + + + 570.2000122070312 + + + + 137 + + + + + 570.2000122070312 + + + + 136 + + + + + 569.7999877929688 + + + + 136 + + + + + 570.0 + + + + 136 + + + + + 570.0 + + + + 136 + + + + + 569.7999877929688 + + + + 135 + + + + + 569.5999755859375 + + + + 134 + + + + + 569.7999877929688 + + + + 134 + + + + + 569.7999877929688 + + + + 133 + + + + + 569.5999755859375 + + + + 133 + + + + + 569.5999755859375 + + + + 133 + + + + + 569.5999755859375 + + + + 133 + + + + + 571.0 + + + + 133 + + + + + 571.5999755859375 + + + + 132 + + + + + 572.4000244140625 + + + + 132 + + + + + 572.7999877929688 + + + + 133 + + + + + 573.4000244140625 + + + + 134 + + + + + 574.0 + + + + 134 + + + + + 574.7999877929688 + + + + 135 + + + + + 575.5999755859375 + + + + 137 + + + + + 576.0 + + + + 138 + + + + + 576.4000244140625 + + + + 140 + + + + + 576.4000244140625 + + + + 141 + + + + + 576.2000122070312 + + + + 141 + + + + + 575.7999877929688 + + + + 140 + + + + + 575.4000244140625 + + + + 141 + + + + + 575.2000122070312 + + + + 141 + + + + + 575.0 + + + + 141 + + + + + 574.5999755859375 + + + + 141 + + + + + 574.5999755859375 + + + + 141 + + + + + 574.2000122070312 + + + + 139 + + + + + 574.0 + + + + 136 + + + + + 573.5999755859375 + + + + 135 + + + + + 573.0 + + + + 132 + + + + + 572.5999755859375 + + + + 131 + + + + + 572.4000244140625 + + + + 130 + + + + + 572.4000244140625 + + + + 130 + + + + + 572.4000244140625 + + + + 128 + + + + + 572.2000122070312 + + + + 127 + + + + + 572.2000122070312 + + + + 127 + + + + + 572.0 + + + + 126 + + + + + 572.0 + + + + 125 + + + + + 572.0 + + + + 122 + + + + + 572.0 + + + + 114 + + + + + 572.0 + + + + 115 + + + + + 572.0 + + + + 115 + + + + + 571.7999877929688 + + + + 112 + + + + + 572.0 + + + + 110 + + + + + 572.0 + + + + 111 + + + + + 571.5999755859375 + + + + 110 + + + + + 571.2000122070312 + + + + 113 + + + + + 571.0 + + + + 114 + + + + + 571.0 + + + + 116 + + + + + 571.0 + + + + 117 + + + + + 571.2000122070312 + + + + 118 + + + + + 571.7999877929688 + + + + 117 + + + + + 572.0 + + + + 118 + + + + + 572.2000122070312 + + + + 119 + + + + + 572.2000122070312 + + + + 121 + + + + + 572.4000244140625 + + + + 121 + + + + + 573.2000122070312 + + + + 119 + + + + + 573.4000244140625 + + + + 119 + + + + + 574.0 + + + + 117 + + + + + 574.4000244140625 + + + + 117 + + + + + 575.4000244140625 + + + + 117 + + + + + 575.7999877929688 + + + + 117 + + + + + 576.2000122070312 + + + + 119 + + + + + 576.4000244140625 + + + + 120 + + + + + 576.4000244140625 + + + + 120 + + + + + 577.0 + + + + 122 + + + + + 577.5999755859375 + + + + 123 + + + + + 579.2000122070312 + + + + 125 + + + + + 581.4000244140625 + + + + 128 + + + + + 582.0 + + + + 129 + + + + + 583.2000122070312 + + + + 132 + + + + + 583.5999755859375 + + + + 133 + + + + + 584.0 + + + + 133 + + + + + 584.2000122070312 + + + + 133 + + + + + 584.2000122070312 + + + + 133 + + + + + 584.5999755859375 + + + + 133 + + + + + 585.2000122070312 + + + + 133 + + + + + 586.5999755859375 + + + + 133 + + + + + 587.0 + + + + 133 + + + + + 588.0 + + + + 134 + + + + + 589.0 + + + + 135 + + + + + 589.4000244140625 + + + + 138 + + + + + 588.7999877929688 + + + + 139 + + + + + 587.2000122070312 + + + + 141 + + + + + 585.0 + + + + 142 + + + + + 581.4000244140625 + + + + 141 + + + + + 578.7999877929688 + + + + 140 + + + + + 578.0 + + + + 140 + + + + + 577.4000244140625 + + + + 140 + + + + + 575.5999755859375 + + + + 139 + + + + + 574.4000244140625 + + + + 137 + + + + + 572.7999877929688 + + + + 135 + + + + + 572.4000244140625 + + + + 134 + + + + + 571.0 + + + + 131 + + + + + 570.2000122070312 + + + + 129 + + + + + 569.5999755859375 + + + + 128 + + + + + 568.7999877929688 + + + + 127 + + + + + 568.2000122070312 + + + + 127 + + + + + 568.4000244140625 + + + + 127 + + + + + 568.7999877929688 + + + + 127 + + + + + 569.4000244140625 + + + + 127 + + + + + 569.5999755859375 + + + + 127 + + + + + 569.7999877929688 + + + + 127 + + + + + 569.7999877929688 + + + + 127 + + + + + 569.7999877929688 + + + + 127 + + + + + 569.7999877929688 + + + + 128 + + + + + 570.4000244140625 + + + + 127 + + + + + 571.0 + + + + 127 + + + + + 571.2000122070312 + + + + 128 + + + + + 571.4000244140625 + + + + 127 + + + + + 572.4000244140625 + + + + 127 + + + + + 572.4000244140625 + + + + 127 + + + + + 572.2000122070312 + + + + 127 + + + + + 572.4000244140625 + + + + 126 + + + + + 573.0 + + + + 127 + + + + + 574.2000122070312 + + + + 127 + + + + + 575.4000244140625 + + + + 128 + + + + + 576.0 + + + + 129 + + + + + 576.5999755859375 + + + + 130 + + + + + 576.7999877929688 + + + + 132 + + + + + 577.0 + + + + 132 + + + + + 577.0 + + + + 133 + + + + + 577.2000122070312 + + + + 134 + + + + + 577.4000244140625 + + + + 135 + + + + + 577.5999755859375 + + + + 135 + + + + + 577.7999877929688 + + + + 137 + + + + + 577.7999877929688 + + + + 137 + + + + + 578.0 + + + + 138 + + + + + 578.2000122070312 + + + + 139 + + + + + 578.7999877929688 + + + + 141 + + + + + 579.5999755859375 + + + + 142 + + + + + 580.2000122070312 + + + + 143 + + + + + 581.0 + + + + 144 + + + + + 581.5999755859375 + + + + 143 + + + + + 581.7999877929688 + + + + 140 + + + + + 581.5999755859375 + + + + 139 + + + + + 580.7999877929688 + + + + 136 + + + + + 580.4000244140625 + + + + 135 + + + + + 579.4000244140625 + + + + 132 + + + + + 579.2000122070312 + + + + 131 + + + + + 578.5999755859375 + + + + 131 + + + + + 577.5999755859375 + + + + 129 + + + + + 576.4000244140625 + + + + 128 + + + + + 575.2000122070312 + + + + 126 + + + + + 574.7999877929688 + + + + 125 + + + + + 574.0 + + + + 123 + + + + + 573.7999877929688 + + + + 123 + + + + + 573.5999755859375 + + + + 122 + + + + + 573.2000122070312 + + + + 122 + + + + + 572.5999755859375 + + + + 121 + + + + + 572.2000122070312 + + + + 120 + + + + + 571.4000244140625 + + + + 120 + + + + + 568.7999877929688 + + + + 118 + + + + + 568.2000122070312 + + + + 118 + + + + + 566.2000122070312 + + + + 116 + + + + + 566.5999755859375 + + + + 115 + + + + + 566.5999755859375 + + + + 114 + + + + + 566.4000244140625 + + + + 112 + + + + + 566.0 + + + + 111 + + + + + 565.2000122070312 + + + + 110 + + + + + 564.7999877929688 + + + + 110 + + + + + 564.2000122070312 + + + + 111 + + + + + 563.5999755859375 + + + + 112 + + + + + 562.4000244140625 + + + + 112 + + + + + 560.4000244140625 + + + + 113 + + + + + 558.7999877929688 + + + + 114 + + + + + 557.4000244140625 + + + + 114 + + + + + 557.0 + + + + 114 + + + + + 555.7999877929688 + + + + 114 + + + + + 555.0 + + + + 114 + + + + + 554.2000122070312 + + + + 114 + + + + + 553.7999877929688 + + + + 114 + + + + + 552.0 + + + + 112 + + + + + 551.7999877929688 + + + + 111 + + + + + 551.0 + + + + 111 + + + + + 551.0 + + + + 112 + + + + + 550.7999877929688 + + + + 110 + + + + + 550.5999755859375 + + + + 110 + + + + + 550.4000244140625 + + + + 115 + + + + + 550.2000122070312 + + + + 115 + + + + + 549.7999877929688 + + + + 114 + + + + + 549.4000244140625 + + + + 114 + + + + + 548.4000244140625 + + + + 114 + + + + + 547.5999755859375 + + + + 115 + + + + + 546.7999877929688 + + + + 121 + + + + + 546.5999755859375 + + + + 121 + + + + + 546.4000244140625 + + + + 121 + + + + + 545.7999877929688 + + + + 120 + + + + + 545.7999877929688 + + + + 119 + + + + + 546.0 + + + + 119 + + + + + 546.2000122070312 + + + + 119 + + + + + 546.2000122070312 + + + + 120 + + + + + 546.0 + + + + 121 + + + + + 545.4000244140625 + + + + 120 + + + + + 544.7999877929688 + + + + 120 + + + + + 544.4000244140625 + + + + 120 + + + + + 543.5999755859375 + + + + 119 + + + + + 543.0 + + + + 119 + + + + + 542.0 + + + + 119 + + + + + 541.5999755859375 + + + + 118 + + + + + 539.5999755859375 + + + + 118 + + + + + 538.4000244140625 + + + + 117 + + + + + 537.5999755859375 + + + + 117 + + + + + 536.7999877929688 + + + + 117 + + + + + 535.7999877929688 + + + + 118 + + + + + 535.7999877929688 + + + + 119 + + + + + 535.7999877929688 + + + + 118 + + + + + 535.7999877929688 + + + + 123 + + + + + 535.7999877929688 + + + + 123 + + + + + 536.0 + + + + 122 + + + + + 536.0 + + + + 120 + + + + + 536.7999877929688 + + + + 121 + + + + + 537.7999877929688 + + + + 119 + + + + + 538.2000122070312 + + + + 122 + + + + + 538.5999755859375 + + + + 123 + + + + + 538.7999877929688 + + + + 120 + + + + + 538.7999877929688 + + + + 120 + + + + + 538.4000244140625 + + + + 119 + + + + + 538.5999755859375 + + + + 119 + + + + + 538.2000122070312 + + + + 123 + + + + + 537.7999877929688 + + + + 123 + + + + + 536.5999755859375 + + + + 124 + + + + + 535.4000244140625 + + + + 123 + + + + + 534.7999877929688 + + + + 131 + + + + + 534.5999755859375 + + + + 135 + + + + + 534.5999755859375 + + + + 135 + + + + + 534.4000244140625 + + + + 135 + + + + + 534.2000122070312 + + + + 138 + + + + + 534.0 + + + + 134 + + + + + 533.7999877929688 + + + + 131 + + + + + 533.7999877929688 + + + + 128 + + + + + 533.5999755859375 + + + + 128 + + + + + 533.5999755859375 + + + + 128 + + + + + 533.2000122070312 + + + + 125 + + + + + 532.7999877929688 + + + + 125 + + + + + 533.2000122070312 + + + + 123 + + + + + 533.2000122070312 + + + + 131 + + + + + 533.2000122070312 + + + + 131 + + + + + 533.2000122070312 + + + + 131 + + + + + 532.5999755859375 + + + + 133 + + + + + 532.2000122070312 + + + + 130 + + + + + 531.4000244140625 + + + + 130 + + + + + 530.7999877929688 + + + + 127 + + + + + 530.2000122070312 + + + + 131 + + + + + 529.7999877929688 + + + + 130 + + + + + 528.7999877929688 + + + + 139 + + + + + 528.5999755859375 + + + + 139 + + + + + 528.0 + + + + 139 + + + + + 527.7999877929688 + + + + 142 + + + + + 527.5999755859375 + + + + 145 + + + + + 527.4000244140625 + + + + 145 + + + + + 527.4000244140625 + + + + 142 + + + + + 527.2000122070312 + + + + 136 + + + + + 527.0 + + + + 132 + + + + + 526.7999877929688 + + + + 137 + + + + + 526.7999877929688 + + + + 141 + + + + + 526.4000244140625 + + + + 141 + + + + + 525.7999877929688 + + + + 141 + + + + + 525.4000244140625 + + + + 148 + + + + + 525.4000244140625 + + + + 148 + + + + + 525.2000122070312 + + + + 144 + + + + + 525.2000122070312 + + + + 141 + + + + + 525.0 + + + + 141 + + + + + 525.0 + + + + 145 + + + + + 524.4000244140625 + + + + 147 + + + + + 524.4000244140625 + + + + 141 + + + + + 524.4000244140625 + + + + 138 + + + + + 524.2000122070312 + + + + 138 + + + + + 524.0 + + + + 142 + + + + + 524.0 + + + + 136 + + + + + 524.0 + + + + 133 + + + + + 523.5999755859375 + + + + 131 + + + + + 523.4000244140625 + + + + 136 + + + + + 523.2000122070312 + + + + 136 + + + + + 523.2000122070312 + + + + 133 + + + + + 523.2000122070312 + + + + 130 + + + + + 523.2000122070312 + + + + 129 + + + + + 523.2000122070312 + + + + 127 + + + + + 523.2000122070312 + + + + 124 + + + + + 523.2000122070312 + + + + 122 + + + + + 523.2000122070312 + + + + 121 + + + + + 523.4000244140625 + + + + 120 + + + + + 523.4000244140625 + + + + 129 + + + + + 523.4000244140625 + + + + 133 + + + + + 523.4000244140625 + + + + 133 + + + + + 523.5999755859375 + + + + 129 + + + + + 523.5999755859375 + + + + 126 + + + + + 523.5999755859375 + + + + 123 + + + + + 523.5999755859375 + + + + 120 + + + + + 523.5999755859375 + + + + 119 + + + + + 523.5999755859375 + + + + 120 + + + + + 523.4000244140625 + + + + 116 + + + + + 523.2000122070312 + + + + 112 + + + + + 523.0 + + + + 109 + + + + + 523.0 + + + + 109 + + + + + 522.7999877929688 + + + + 109 + + + + + 522.4000244140625 + + + + 106 + + + + + 522.0 + + + + 105 + + + + + 521.4000244140625 + + + + 106 + + + + + 520.5999755859375 + + + + 120 + + + + + 520.5999755859375 + + + + 120 + + + + + 520.4000244140625 + + + + 116 + + + + + 520.4000244140625 + + + + 112 + + + + + 520.2000122070312 + + + + 111 + + + + + 520.2000122070312 + + + + 520.2000122070312 + + + + 104 + + + + + 520.0 + + + + 104 + + + + + 520.0 + + + + 107 + + + + + 520.2000122070312 + + + + 110 + + + + + 520.5999755859375 + + + + 110 + + + + + 521.0 + + + + 113 + + + + + 521.0 + + + + 114 + + + + + 521.4000244140625 + + + + 117 + + + + + 521.4000244140625 + + + + 117 + + + + + 521.5999755859375 + + + + 118 + + + + + 521.5999755859375 + + + + 118 + + + + + 521.4000244140625 + + + + 117 + + + + + 521.2000122070312 + + + + 117 + + + + + 520.7999877929688 + + + + 116 + + + + + 520.5999755859375 + + + + 117 + + + + + 520.4000244140625 + + + + 117 + + + + + 520.0 + + + + 116 + + + + + 519.7999877929688 + + + + 116 + + + + + 519.0 + + + + 115 + + + + + 518.7999877929688 + + + + 115 + + + + + 518.4000244140625 + + + + 114 + + + + + 516.5999755859375 + + + + 113 + + + + + 513.0 + + + + 111 + + + + + 512.4000244140625 + + + + 111 + + + + + 510.79998779296875 + + + + 110 + + + + + 510.20001220703125 + + + + 109 + + + + + 509.6000061035156 + + + + 109 + + + + + 507.79998779296875 + + + + 107 + + + + + 506.20001220703125 + + + + 106 + + + + + 505.79998779296875 + + + + 106 + + + + + 503.0 + + + + 107 + + + + + 501.3999938964844 + + + + 107 + + + + + 500.0 + + + + 108 + + + + + 498.79998779296875 + + + + 108 + + + + + 497.79998779296875 + + + + 108 + + + + + 495.20001220703125 + + + + 109 + + + + + 494.79998779296875 + + + + 109 + + + + + 494.6000061035156 + + + + 111 + + + + + 494.6000061035156 + + + + 111 + + + + + 494.3999938964844 + + + + 111 + + + + + 494.20001220703125 + + + + 111 + + + + + 494.0 + + + + 112 + + + + + 494.0 + + + + 113 + + + + + 494.0 + + + + 114 + + + + + 494.0 + + + + 115 + + + + + 494.0 + + + + 116 + + + + + 493.6000061035156 + + + + 118 + + + + + 492.3999938964844 + + + + 118 + + + + + 490.79998779296875 + + + + 116 + + + + + 490.0 + + + + 115 + + + + + 489.20001220703125 + + + + 114 + + + + + 489.3999938964844 + + + + 114 + + + + + 489.3999938964844 + + + + 115 + + + + + 489.3999938964844 + + + + 115 + + + + + 489.6000061035156 + + + + 115 + + + + + 489.79998779296875 + + + + 116 + + + + + 490.20001220703125 + + + + 118 + + + + + 490.3999938964844 + + + + 120 + + + + + 490.6000061035156 + + + + 121 + + + + + 490.6000061035156 + + + + 121 + + + + + 491.0 + + + + 123 + + + + + 491.3999938964844 + + + + 124 + + + + + 491.3999938964844 + + + + 124 + + + + + 491.20001220703125 + + + + 124 + + + + + 491.20001220703125 + + + + 123 + + + + + 490.79998779296875 + + + + 123 + + + + + 491.0 + + + + 125 + + + + + 491.3999938964844 + + + + 127 + + + + + 491.6000061035156 + + + + 127 + + + + + 491.79998779296875 + + + + 128 + + + + + 492.20001220703125 + + + + 128 + + + + + 492.3999938964844 + + + + 128 + + + + + 492.3999938964844 + + + + 129 + + + + + 492.20001220703125 + + + + 129 + + + + + 492.79998779296875 + + + + 130 + + + + + 493.20001220703125 + + + + 130 + + + + + 493.3999938964844 + + + + 130 + + + + + 493.79998779296875 + + + + 130 + + + + + 494.3999938964844 + + + + 131 + + + + + 494.3999938964844 + + + + 131 + + + + + 494.0 + + + + 131 + + + + + 493.6000061035156 + + + + 131 + + + + + 493.0 + + + + 130 + + + + + 491.79998779296875 + + + + 130 + + + + + 491.3999938964844 + + + + 129 + + + + + 491.20001220703125 + + + + 130 + + + + + 491.20001220703125 + + + + 130 + + + + + 491.20001220703125 + + + + 130 + + + + + 491.6000061035156 + + + + 130 + + + + + 492.20001220703125 + + + + 130 + + + + + 492.3999938964844 + + + + 130 + + + + + 492.79998779296875 + + + + 130 + + + + + 493.3999938964844 + + + + 129 + + + + + 494.79998779296875 + + + + 130 + + + + + 495.79998779296875 + + + + 131 + + + + + 496.79998779296875 + + + + 131 + + + + + 497.20001220703125 + + + + 131 + + + + + 497.6000061035156 + + + + 131 + + + + + 498.0 + + + + 130 + + + + + 498.0 + + + + 130 + + + + + 498.0 + + + + 130 + + + + + 497.79998779296875 + + + + 130 + + + + + 497.3999938964844 + + + + 131 + + + + + 497.20001220703125 + + + + 131 + + + + + 497.20001220703125 + + + + 132 + + + + + 497.6000061035156 + + + + 132 + + + + + 497.79998779296875 + + + + 133 + + + + + 499.0 + + + + 133 + + + + + 499.6000061035156 + + + + 134 + + + + + 499.6000061035156 + + + + 134 + + + + + 500.6000061035156 + + + + 134 + + + + + 501.79998779296875 + + + + 133 + + + + + 502.6000061035156 + + + + 133 + + + + + 503.0 + + + + 135 + + + + + 503.3999938964844 + + + + 136 + + + + + 503.3999938964844 + + + + 136 + + + + + 503.6000061035156 + + + + 136 + + + + + 504.0 + + + + 137 + + + + + 504.6000061035156 + + + + 136 + + + + + 504.3999938964844 + + + + 136 + + + + + 504.0 + + + + 137 + + + + + 503.3999938964844 + + + + 137 + + + + + 502.6000061035156 + + + + 137 + + + + + 502.0 + + + + 137 + + + + + 500.0 + + + + 137 + + + + + 498.20001220703125 + + + + 136 + + + + + 498.20001220703125 + + + + 136 + + + + + 498.3999938964844 + + + + 135 + + + + + 498.3999938964844 + + + + 135 + + + + + 498.6000061035156 + + + + 135 + + + + + 498.6000061035156 + + + + 135 + + + + + 498.20001220703125 + + + + 135 + + + + + 497.20001220703125 + + + + 134 + + + + + 496.3999938964844 + + + + 134 + + + + + 495.3999938964844 + + + + 132 + + + + + 494.3999938964844 + + + + 131 + + + + + 494.79998779296875 + + + + 130 + + + + + 495.20001220703125 + + + + 130 + + + + + 495.6000061035156 + + + + 129 + + + + + 496.0 + + + + 129 + + + + + 496.6000061035156 + + + + 128 + + + + + 496.79998779296875 + + + + 128 + + + + + 498.0 + + + + 129 + + + + + 499.6000061035156 + + + + 128 + + + + + 500.20001220703125 + + + + 128 + + + + + 500.3999938964844 + + + + 128 + + + + + 500.79998779296875 + + + + 127 + + + + + 501.6000061035156 + + + + 127 + + + + + 502.0 + + + + 126 + + + + + 501.6000061035156 + + + + 126 + + + + + 500.79998779296875 + + + + 124 + + + + + 499.79998779296875 + + + + 122 + + + + + 498.0 + + + + 121 + + + + + 497.3999938964844 + + + + 121 + + + + + 495.79998779296875 + + + + 120 + + + + + 495.3999938964844 + + + + 119 + + + + + 495.0 + + + + 119 + + + + + 494.79998779296875 + + + + 118 + + + + + 494.20001220703125 + + + + 116 + + + + + 493.79998779296875 + + + + 116 + + + + + 493.6000061035156 + + + + 117 + + + + + 493.79998779296875 + + + + 117 + + + + + 494.3999938964844 + + + + 116 + + + + + 494.79998779296875 + + + + 116 + + + + + 495.0 + + + + 117 + + + + + 495.20001220703125 + + + + 118 + + + + + 496.0 + + + + 120 + + + + + 496.20001220703125 + + + + 120 + + + + + 496.3999938964844 + + + + 119 + + + + + 496.20001220703125 + + + + 120 + + + + + 494.79998779296875 + + + + 120 + + + + + 493.3999938964844 + + + + 122 + + + + + 492.3999938964844 + + + + 123 + + + + + 490.6000061035156 + + + + 125 + + + + + 490.0 + + + + 125 + + + + + 489.3999938964844 + + + + 125 + + + + + 490.3999938964844 + + + + 126 + + + + + 490.3999938964844 + + + + 126 + + + + + 491.20001220703125 + + + + 127 + + + + + 492.0 + + + + 127 + + + + + 492.79998779296875 + + + + 127 + + + + + 493.20001220703125 + + + + 126 + + + + + 493.20001220703125 + + + + 126 + + + + + 493.0 + + + + 126 + + + + + 493.0 + + + + 126 + + + + + 493.0 + + + + 126 + + + + + 493.0 + + + + 126 + + + + + 493.0 + + + + 125 + + + + + 492.6000061035156 + + + + 125 + + + + + 492.3999938964844 + + + + 123 + + + + + 492.20001220703125 + + + + 123 + + + + + 491.79998779296875 + + + + 125 + + + + + 491.6000061035156 + + + + 126 + + + + + 491.3999938964844 + + + + 127 + + + + + 491.3999938964844 + + + + 128 + + + + + 491.6000061035156 + + + + 130 + + + + + 491.6000061035156 + + + + 131 + + + + + 492.0 + + + + 133 + + + + + 492.20001220703125 + + + + 134 + + + + + 492.20001220703125 + + + + 134 + + + + + 492.6000061035156 + + + + 135 + + + + + 493.20001220703125 + + + + 136 + + + + + 493.20001220703125 + + + + 136 + + + + + 493.79998779296875 + + + + 136 + + + + + 494.0 + + + + 136 + + + + + 494.6000061035156 + + + + 136 + + + + + 495.0 + + + + 136 + + + + + 495.3999938964844 + + + + 135 + + + + + 495.20001220703125 + + + + 135 + + + + + 495.0 + + + + 135 + + + + + 494.6000061035156 + + + + 134 + + + + + 494.3999938964844 + + + + 135 + + + + + 494.0 + + + + 135 + + + + + 493.79998779296875 + + + + 136 + + + + + 494.20001220703125 + + + + 137 + + + + + 494.79998779296875 + + + + 136 + + + + + 495.0 + + + + 134 + + + + + 495.20001220703125 + + + + 133 + + + + + 495.20001220703125 + + + + 134 + + + + + 495.20001220703125 + + + + 133 + + + + + 495.20001220703125 + + + + 132 + + + + + 495.20001220703125 + + + + 131 + + + + + 495.20001220703125 + + + + 130 + + + + + 495.20001220703125 + + + + 131 + + + + + 495.20001220703125 + + + + 132 + + + + + 495.0 + + + + 132 + + + + + 495.0 + + + + 132 + + + + + 495.3999938964844 + + + + 133 + + + + + 496.20001220703125 + + + + 134 + + + + + 497.20001220703125 + + + + 136 + + + + + 498.0 + + + + 137 + + + + + 498.79998779296875 + + + + 139 + + + + + 498.79998779296875 + + + + 139 + + + + + 498.6000061035156 + + + + 139 + + + + + 498.79998779296875 + + + + 139 + + + + + 498.79998779296875 + + + + 139 + + + + + 499.3999938964844 + + + + 139 + + + + + 500.20001220703125 + + + + 140 + + + + + 500.6000061035156 + + + + 140 + + + + + 500.6000061035156 + + + + 140 + + + + + 500.6000061035156 + + + + 140 + + + + + 500.6000061035156 + + + + 141 + + + + + 500.3999938964844 + + + + 141 + + + + + 500.20001220703125 + + + + 141 + + + + + 499.79998779296875 + + + + 141 + + + + + 499.3999938964844 + + + + 141 + + + + + 499.0 + + + + 141 + + + + + 498.79998779296875 + + + + 141 + + + + + 498.3999938964844 + + + + 141 + + + + + 498.0 + + + + 142 + + + + + 498.20001220703125 + + + + 142 + + + + + 498.3999938964844 + + + + 141 + + + + + 498.3999938964844 + + + + 140 + + + + + 498.6000061035156 + + + + 140 + + + + + 498.6000061035156 + + + + 139 + + + + + 498.79998779296875 + + + + 139 + + + + + 499.0 + + + + 139 + + + + + 499.0 + + + + 138 + + + + + 499.0 + + + + 138 + + + + + 499.0 + + + + 138 + + + + + 498.79998779296875 + + + + 138 + + + + + 498.79998779296875 + + + + 137 + + + + + 498.79998779296875 + + + + 136 + + + + + 498.79998779296875 + + + + 134 + + + + + 498.79998779296875 + + + + 132 + + + + + 499.0 + + + + 129 + + + + + 499.0 + + + + 128 + + + + + 499.0 + + + + 128 + + + + + 499.0 + + + + 127 + + + + + 498.6000061035156 + + + + 127 + + + + + 498.20001220703125 + + + + 129 + + + + + 498.0 + + + + 130 + + + + + 497.79998779296875 + + + + 132 + + + + + 497.6000061035156 + + + + 132 + + + + + 497.6000061035156 + + + + 132 + + + + + 497.6000061035156 + + + + 131 + + + + + 497.79998779296875 + + + + 131 + + + + + 497.79998779296875 + + + + 131 + + + + + 498.20001220703125 + + + + 131 + + + + + 498.3999938964844 + + + + 131 + + + + + 499.20001220703125 + + + + 133 + + + + + 498.79998779296875 + + + + 134 + + + + + 498.6000061035156 + + + + 134 + + + + + 498.20001220703125 + + + + 135 + + + + + 497.79998779296875 + + + + 136 + + + + + 497.79998779296875 + + + + 136 + + + + + 497.3999938964844 + + + + 136 + + + + + 497.0 + + + + 136 + + + + + 496.79998779296875 + + + + 137 + + + + + 496.20001220703125 + + + + 138 + + + + + 496.3999938964844 + + + + 138 + + + + + 497.0 + + + + 138 + + + + + 497.6000061035156 + + + + 138 + + + + + 497.79998779296875 + + + + 136 + + + + + 498.0 + + + + 135 + + + + + 498.20001220703125 + + + + 135 + + + + + 498.20001220703125 + + + + 134 + + + + + 498.20001220703125 + + + + 134 + + + + + 498.3999938964844 + + + + 133 + + + + + 498.6000061035156 + + + + 133 + + + + + 498.6000061035156 + + + + 133 + + + + + 498.79998779296875 + + + + 133 + + + + + 498.79998779296875 + + + + 133 + + + + + 499.0 + + + + 132 + + + + + 499.20001220703125 + + + + 132 + + + + + 499.20001220703125 + + + + 133 + + + + + 499.79998779296875 + + + + 134 + + + + + 500.3999938964844 + + + + 135 + + + + + 500.79998779296875 + + + + 136 + + + + + 500.79998779296875 + + + + 136 + + + + + 501.0 + + + + 136 + + + + + 501.20001220703125 + + + + 136 + + + + + 501.20001220703125 + + + + 136 + + + + + 501.3999938964844 + + + + 135 + + + + + 501.79998779296875 + + + + 135 + + + + + 501.79998779296875 + + + + 135 + + + + + 502.20001220703125 + + + + 134 + + + + + 502.6000061035156 + + + + 134 + + + + + 503.20001220703125 + + + + 133 + + + + + 504.0 + + + + 133 + + + + + 504.6000061035156 + + + + 134 + + + + + 505.20001220703125 + + + + 134 + + + + + 505.3999938964844 + + + + 133 + + + + + 505.3999938964844 + + + + 133 + + + + + 505.79998779296875 + + + + 132 + + + + + 506.20001220703125 + + + + 133 + + + + + 506.20001220703125 + + + + 132 + + + + + 506.79998779296875 + + + + 131 + + + + + 507.0 + + + + 130 + + + + + 507.20001220703125 + + + + 128 + + + + + 507.3999938964844 + + + + 127 + + + + + 507.79998779296875 + + + + 127 + + + + + 508.0 + + + + 128 + + + + + 508.0 + + + + 129 + + + + + 508.0 + + + + 129 + + + + + 508.20001220703125 + + + + 129 + + + + + 508.20001220703125 + + + + 129 + + + + + 508.20001220703125 + + + + 127 + + + + + 508.0 + + + + 127 + + + + + 507.6000061035156 + + + + 125 + + + + + 507.20001220703125 + + + + 125 + + + + + 507.0 + + + + 126 + + + + + 506.6000061035156 + + + + 125 + + + + + 506.3999938964844 + + + + 125 + + + + + 506.0 + + + + 124 + + + + + 505.79998779296875 + + + + 124 + + + + + 505.79998779296875 + + + + 124 + + + + + 506.0 + + + + 125 + + + + + 505.6000061035156 + + + + 124 + + + + + 505.3999938964844 + + + + 122 + + + + + 504.79998779296875 + + + + 122 + + + + + 504.6000061035156 + + + + 122 + + + + + 504.6000061035156 + + + + 122 + + + + + 504.6000061035156 + + + + 122 + + + + + 504.6000061035156 + + + + 123 + + + + + 504.6000061035156 + + + + 124 + + + + + 504.79998779296875 + + + + 124 + + + + + 504.79998779296875 + + + + 125 + + + + + 505.0 + + + + 125 + + + + + 505.6000061035156 + + + + 125 + + + + + 505.79998779296875 + + + + 125 + + + + + 505.20001220703125 + + + + 126 + + + + + 505.3999938964844 + + + + 126 + + + + + 505.6000061035156 + + + + 128 + + + + + 505.6000061035156 + + + + 129 + + + + + 505.79998779296875 + + + + 129 + + + + + 506.0 + + + + 129 + + + + + 506.20001220703125 + + + + 130 + + + + + 506.3999938964844 + + + + 130 + + + + + 506.79998779296875 + + + + 130 + + + + + 507.0 + + + + 131 + + + + + 507.6000061035156 + + + + 132 + + + + + 508.0 + + + + 132 + + + + + 508.3999938964844 + + + + 131 + + + + + 508.79998779296875 + + + + 132 + + + + + 509.20001220703125 + + + + 131 + + + + + 509.20001220703125 + + + + 131 + + + + + 509.79998779296875 + + + + 130 + + + + + 510.20001220703125 + + + + 132 + + + + + 510.6000061035156 + + + + 131 + + + + + 510.79998779296875 + + + + 131 + + + + + 510.79998779296875 + + + + 129 + + + + + 510.79998779296875 + + + + 127 + + + + + 510.79998779296875 + + + + 126 + + + + + 510.79998779296875 + + + + 124 + + + + + 510.6000061035156 + + + + 122 + + + + + 510.79998779296875 + + + + 122 + + + + + 511.0 + + + + 123 + + + + + 511.0 + + + + 123 + + + + + 511.3999938964844 + + + + 123 + + + + + 511.6000061035156 + + + + 120 + + + + + 511.3999938964844 + + + + 119 + + + + + 511.3999938964844 + + + + 118 + + + + + 511.20001220703125 + + + + 119 + + + + + 511.3999938964844 + + + + 119 + + + + + 511.20001220703125 + + + + 119 + + + + + 510.6000061035156 + + + + 120 + + + + + 510.79998779296875 + + + + 121 + + + + + 510.79998779296875 + + + + 123 + + + + + 510.79998779296875 + + + + 123 + + + + + 511.3999938964844 + + + + 123 + + + + + 511.6000061035156 + + + + 123 + + + + + 511.6000061035156 + + + + 124 + + + + + 512.0 + + + + 125 + + + + + 512.0 + + + + 125 + + + + + 512.0 + + + + 125 + + + + + 512.4000244140625 + + + + 124 + + + + + 512.4000244140625 + + + + 125 + + + + + 512.4000244140625 + + + + 125 + + + + + 512.5999755859375 + + + + 125 + + + + + 512.7999877929688 + + + + 125 + + + + + 513.2000122070312 + + + + 125 + + + + + 513.2000122070312 + + + + 125 + + + + + 513.2000122070312 + + + + 125 + + + + + 513.2000122070312 + + + + 125 + + + + + 513.4000244140625 + + + + 126 + + + + + 513.4000244140625 + + + + 126 + + + + + 513.4000244140625 + + + + 126 + + + + + 513.5999755859375 + + + + 126 + + + + + 513.5999755859375 + + + + 126 + + + + + 513.5999755859375 + + + + 127 + + + + + 514.0 + + + + 127 + + + + + 514.4000244140625 + + + + 128 + + + + + 514.4000244140625 + + + + 127 + + + + + 514.4000244140625 + + + + 127 + + + + + 514.4000244140625 + + + + 128 + + + + + 514.7999877929688 + + + + 127 + + + + + 515.7999877929688 + + + + 127 + + + + + 516.4000244140625 + + + + 127 + + + + + 516.7999877929688 + + + + 126 + + + + + 517.2000122070312 + + + + 126 + + + + + 517.5999755859375 + + + + 125 + + + + + 517.7999877929688 + + + + 125 + + + + + 517.7999877929688 + + + + 125 + + + + + 518.0 + + + + 125 + + + + + 518.0 + + + + 125 + + + + + 518.2000122070312 + + + + 125 + + + + + 518.2000122070312 + + + + 126 + + + + + 518.4000244140625 + + + + 124 + + + + + 518.4000244140625 + + + + 123 + + + + + 518.4000244140625 + + + + 122 + + + + + 518.4000244140625 + + + + 121 + + + + + 518.5999755859375 + + + + 120 + + + + + 518.5999755859375 + + + + 120 + + + + + 519.0 + + + + 123 + + + + + 519.2000122070312 + + + + 125 + + + + + 520.4000244140625 + + + + 126 + + + + + 521.4000244140625 + + + + 127 + + + + + 521.5999755859375 + + + + 128 + + + + + 521.4000244140625 + + + + 130 + + + + + 521.4000244140625 + + + + 133 + + + + + 521.4000244140625 + + + + 133 + + + + + 521.4000244140625 + + + + 134 + + + + + 521.2000122070312 + + + + 137 + + + + + 521.0 + + + + 137 + + + + + 521.0 + + + + 138 + + + + + 521.2000122070312 + + + + 139 + + + + + 521.2000122070312 + + + + 139 + + + + + 521.4000244140625 + + + + 140 + + + + + 521.4000244140625 + + + + 140 + + + + + 522.0 + + + + 140 + + + + + 522.4000244140625 + + + + 141 + + + + + 524.0 + + + + 141 + + + + + 526.0 + + + + 142 + + + + + 528.5999755859375 + + + + 142 + + + + + 530.0 + + + + 142 + + + + + 531.2000122070312 + + + + 142 + + + + + 531.7999877929688 + + + + 141 + + + + + 532.0 + + + + 139 + + + + + 532.7999877929688 + + + + 139 + + + + + 533.7999877929688 + + + + 138 + + + + + 534.4000244140625 + + + + 138 + + + + + 534.2000122070312 + + + + 138 + + + + + 533.7999877929688 + + + + 139 + + + + + 533.5999755859375 + + + + 139 + + + + + 534.4000244140625 + + + + 139 + + + + + 536.2000122070312 + + + + 139 + + + + + 538.0 + + + + 139 + + + + + 538.7999877929688 + + + + 138 + + + + + 538.7999877929688 + + + + 138 + + + + + 538.4000244140625 + + + + 137 + + + + + 538.2000122070312 + + + + 136 + + + + + 538.2000122070312 + + + + 135 + + + + + 538.2000122070312 + + + + 135 + + + + + 538.2000122070312 + + + + 134 + + + + + 537.5999755859375 + + + + 133 + + + + + 536.5999755859375 + + + + 132 + + + + + 535.7999877929688 + + + + 132 + + + + + 535.4000244140625 + + + + 132 + + + + + 535.5999755859375 + + + + 132 + + + + + 535.7999877929688 + + + + 132 + + + + + 536.4000244140625 + + + + 132 + + + + + 536.5999755859375 + + + + 132 + + + + + 536.7999877929688 + + + + 131 + + + + + 536.4000244140625 + + + + 132 + + + + + 535.4000244140625 + + + + 132 + + + + + 535.0 + + + + 132 + + + + + 535.7999877929688 + + + + 132 + + + + + 536.4000244140625 + + + + 132 + + + + + 536.7999877929688 + + + + 132 + + + + + 538.0 + + + + 132 + + + + + 538.4000244140625 + + + + 133 + + + + + 539.2000122070312 + + + + 132 + + + + + 539.5999755859375 + + + + 132 + + + + + 539.4000244140625 + + + + 132 + + + + + 538.4000244140625 + + + + 131 + + + + + 536.0 + + + + 130 + + + + + 536.0 + + + + 130 + + + + + 535.5999755859375 + + + + 129 + + + + + 535.5999755859375 + + + + 128 + + + + + 535.4000244140625 + + + + 127 + + + + + 535.4000244140625 + + + + 126 + + + + + 534.7999877929688 + + + + 125 + + + + + 532.7999877929688 + + + + 123 + + + + + 532.4000244140625 + + + + 123 + + + + + 532.0 + + + + 122 + + + + + 532.0 + + + + 120 + + + + + 532.2000122070312 + + + + 119 + + + + + 531.5999755859375 + + + + 118 + + + + + 529.5999755859375 + + + + 118 + + + + + 527.7999877929688 + + + + 117 + + + + + 526.4000244140625 + + + + 116 + + + + + 525.7999877929688 + + + + 116 + + + + + 525.2000122070312 + + + + 117 + + + + + 525.4000244140625 + + + + 118 + + + + + 525.4000244140625 + + + + 118 + + + + + 525.2000122070312 + + + + 120 + + + + + 524.7999877929688 + + + + 121 + + + + + 524.4000244140625 + + + + 121 + + + + + 524.2000122070312 + + + + 122 + + + + + 524.0 + + + + 122 + + + + + 523.7999877929688 + + + + 123 + + + + + 523.7999877929688 + + + + 123 + + + + + 524.7999877929688 + + + + 124 + + + + + 524.7999877929688 + + + + 124 + + + + + 525.0 + + + + 125 + + + + + 524.5999755859375 + + + + 125 + + + + + 524.4000244140625 + + + + 125 + + + + + 523.5999755859375 + + + + 126 + + + + + 522.5999755859375 + + + + 126 + + + + + 522.0 + + + + 127 + + + + + 521.2000122070312 + + + + 128 + + + + + 520.7999877929688 + + + + 128 + + + + + 520.5999755859375 + + + + 129 + + + + + 519.5999755859375 + + + + 130 + + + + + 519.0 + + + + 131 + + + + + 518.2000122070312 + + + + 132 + + + + + 518.7999877929688 + + + + 133 + + + + + 519.0 + + + + 134 + + + + + 520.7999877929688 + + + + 134 + + + + + 521.2000122070312 + + + + 134 + + + + + 521.4000244140625 + + + + 135 + + + + + 522.0 + + + + 135 + + + + + 522.0 + + + + 134 + + + + + 522.2000122070312 + + + + 135 + + + + + 522.5999755859375 + + + + 134 + + + + + 523.0 + + + + 134 + + + + + 523.0 + + + + 133 + + + + + 523.5999755859375 + + + + 131 + + + + + 524.0 + + + + 131 + + + + + 524.2000122070312 + + + + 131 + + + + + 524.2000122070312 + + + + 130 + + + + + 524.4000244140625 + + + + 129 + + + + + 524.4000244140625 + + + + 128 + + + + + 524.5999755859375 + + + + 127 + + + + + 524.2000122070312 + + + + 126 + + + + + 523.4000244140625 + + + + 124 + + + + + 522.0 + + + + 123 + + + + + 521.5999755859375 + + + + 123 + + + + + 519.7999877929688 + + + + 122 + + + + + 519.4000244140625 + + + + 122 + + + + + 519.0 + + + + 122 + + + + + 516.7999877929688 + + + + 123 + + + + + 516.5999755859375 + + + + 123 + + + + + 515.7999877929688 + + + + 123 + + + + + 515.5999755859375 + + + + 123 + + + + + 514.5999755859375 + + + + 124 + + + + + 514.4000244140625 + + + + 124 + + + + + 514.2000122070312 + + + + 123 + + + + + 514.0 + + + + 123 + + + + + 514.0 + + + + 123 + + + + + 514.0 + + + + 123 + + + + + 513.5999755859375 + + + + 123 + + + + + 513.5999755859375 + + + + 123 + + + + + 513.2000122070312 + + + + 122 + + + + + 513.0 + + + + 122 + + + + + 512.5999755859375 + + + + 122 + + + + + 512.5999755859375 + + + + 122 + + + + + 512.4000244140625 + + + + 122 + + + + + 512.2000122070312 + + + + 122 + + + + + 512.5999755859375 + + + + 123 + + + + + 513.7999877929688 + + + + 123 + + + + + 514.5999755859375 + + + + 123 + + + + + 515.0 + + + + 123 + + + + + 515.2000122070312 + + + + 124 + + + + + 515.4000244140625 + + + + 124 + + + + + 515.7999877929688 + + + + 123 + + + + + 516.0 + + + + 124 + + + + + 516.0 + + + + 123 + + + + + 516.0 + + + + 122 + + + + + 516.4000244140625 + + + + 123 + + + + + 517.0 + + + + 123 + + + + + 517.4000244140625 + + + + 124 + + + + + 517.7999877929688 + + + + 127 + + + + + 518.0 + + + + 127 + + + + + 518.4000244140625 + + + + 128 + + + + + 518.5999755859375 + + + + 128 + + + + + 518.7999877929688 + + + + 129 + + + + + 519.2000122070312 + + + + 129 + + + + + 519.7999877929688 + + + + 130 + + + + + 520.4000244140625 + + + + 130 + + + + + 521.0 + + + + 129 + + + + + 521.4000244140625 + + + + 128 + + + + + 521.4000244140625 + + + + 127 + + + + + 521.4000244140625 + + + + 127 + + + + + 521.0 + + + + 126 + + + + + 520.4000244140625 + + + + 124 + + + + + 520.2000122070312 + + + + 123 + + + + + 521.2000122070312 + + + + 123 + + + + + 521.5999755859375 + + + + 122 + + + + + 521.4000244140625 + + + + 123 + + + + + 521.5999755859375 + + + + 123 + + + + + 522.0 + + + + 123 + + + + + 522.0 + + + + 122 + + + + + 523.2000122070312 + + + + 121 + + + + + 523.4000244140625 + + + + 121 + + + + + 524.5999755859375 + + + + 122 + + + + + 525.4000244140625 + + + + 121 + + + + + 526.5999755859375 + + + + 120 + + + + + 527.4000244140625 + + + + 119 + + + + + 527.7999877929688 + + + + 116 + + + + + 528.4000244140625 + + + + 114 + + + + + 529.5999755859375 + + + + 114 + + + + + 529.7999877929688 + + + + 114 + + + + + 529.7999877929688 + + + + 115 + + + + + 530.2000122070312 + + + + 114 + + + + + 530.4000244140625 + + + + 113 + + + + + 531.4000244140625 + + + + 112 + + + + + 532.0 + + + + 112 + + + + + 533.0 + + + + 111 + + + + + 533.2000122070312 + + + + 111 + + + + + 532.2000122070312 + + + + 111 + + + + + 531.4000244140625 + + + + 112 + + + + + 530.7999877929688 + + + + 114 + + + + + 530.2000122070312 + + + + 116 + + + + + 529.4000244140625 + + + + 116 + + + + + 528.4000244140625 + + + + 116 + + + + + 527.4000244140625 + + + + 116 + + + + + 526.7999877929688 + + + + 117 + + + + + 526.4000244140625 + + + + 117 + + + + + 525.5999755859375 + + + + 117 + + + + + 525.4000244140625 + + + + 117 + + + + + 525.2000122070312 + + + + 120 + + + + + 525.0 + + + + 121 + + + + + 524.7999877929688 + + + + 124 + + + + + 525.0 + + + + 125 + + + + + 525.5999755859375 + + + + 128 + + + + + 525.7999877929688 + + + + 128 + + + + + 526.2000122070312 + + + + 130 + + + + + 526.7999877929688 + + + + 133 + + + + + 527.2000122070312 + + + + 133 + + + + + 527.4000244140625 + + + + 134 + + + + + 527.7999877929688 + + + + 134 + + + + + 528.2000122070312 + + + + 134 + + + + + 528.4000244140625 + + + + 133 + + + + + 528.5999755859375 + + + + 132 + + + + + 528.5999755859375 + + + + 133 + + + + + 528.7999877929688 + + + + 134 + + + + + 529.2000122070312 + + + + 134 + + + + + 529.5999755859375 + + + + 135 + + + + + 529.7999877929688 + + + + 135 + + + + + 530.2000122070312 + + + + 135 + + + + + 530.4000244140625 + + + + 135 + + + + + 530.7999877929688 + + + + 134 + + + + + 531.4000244140625 + + + + 133 + + + + + 531.5999755859375 + + + + 132 + + + + + 531.7999877929688 + + + + 131 + + + + + 532.0 + + + + 131 + + + + + 532.0 + + + + 131 + + + + + 532.0 + + + + 128 + + + + + 532.0 + + + + 128 + + + + + 531.5999755859375 + + + + 127 + + + + + 531.2000122070312 + + + + 126 + + + + + 531.0 + + + + 125 + + + + + 530.7999877929688 + + + + 124 + + + + + 530.7999877929688 + + + + 124 + + + + + 530.7999877929688 + + + + 123 + + + + + 530.5999755859375 + + + + 123 + + + + + 530.2000122070312 + + + + 123 + + + + + 530.2000122070312 + + + + 123 + + + + + 530.4000244140625 + + + + 123 + + + + + 530.4000244140625 + + + + 123 + + + + + 530.5999755859375 + + + + 124 + + + + + 531.0 + + + + 124 + + + + + 531.4000244140625 + + + + 126 + + + + + 531.5999755859375 + + + + 126 + + + + + 531.5999755859375 + + + + 127 + + + + + 531.5999755859375 + + + + 127 + + + + + 531.2000122070312 + + + + 127 + + + + + 531.0 + + + + 127 + + + + + 530.2000122070312 + + + + 127 + + + + + 530.0 + + + + 127 + + + + + 529.4000244140625 + + + + 127 + + + + + 528.5999755859375 + + + + 127 + + + + + 528.4000244140625 + + + + 126 + + + + + 528.0 + + + + 126 + + + + + 527.7999877929688 + + + + 127 + + + + + 528.0 + + + + 128 + + + + + 528.2000122070312 + + + + 129 + + + + + 528.4000244140625 + + + + 129 + + + + + 528.4000244140625 + + + + 128 + + + + + 528.7999877929688 + + + + 127 + + + + + 529.2000122070312 + + + + 125 + + + + + 529.7999877929688 + + + + 124 + + + + + 530.0 + + + + 123 + + + + + 530.4000244140625 + + + + 123 + + + + + 530.5999755859375 + + + + 124 + + + + + 530.5999755859375 + + + + 124 + + + + + 530.7999877929688 + + + + 125 + + + + + 530.7999877929688 + + + + 125 + + + + + 531.0 + + + + 124 + + + + + 531.0 + + + + 124 + + + + + 530.7999877929688 + + + + 124 + + + + + 530.7999877929688 + + + + 124 + + + + + 530.5999755859375 + + + + 124 + + + + + 530.5999755859375 + + + + 124 + + + + + 530.5999755859375 + + + + 124 + + + + + 530.4000244140625 + + + + 125 + + + + + 530.2000122070312 + + + + 125 + + + + + 530.0 + + + + 125 + + + + + 530.4000244140625 + + + + 126 + + + + + 531.0 + + + + 126 + + + + + 531.0 + + + + 127 + + + + + 531.2000122070312 + + + + 127 + + + + + 531.4000244140625 + + + + 128 + + + + + 531.7999877929688 + + + + 129 + + + + + 532.4000244140625 + + + + 129 + + + + + 532.5999755859375 + + + + 130 + + + + + 533.2000122070312 + + + + 131 + + + + + 533.7999877929688 + + + + 133 + + + + + 534.2000122070312 + + + + 133 + + + + + 535.0 + + + + 133 + + + + + 535.2000122070312 + + + + 133 + + + + + 535.4000244140625 + + + + 133 + + + + + 535.7999877929688 + + + + 132 + + + + + 536.5999755859375 + + + + 132 + + + + + 537.0 + + + + 131 + + + + + 537.5999755859375 + + + + 131 + + + + + 538.4000244140625 + + + + 130 + + + + + 539.0 + + + + 129 + + + + + 539.2000122070312 + + + + 130 + + + + + 539.4000244140625 + + + + 129 + + + + + 539.4000244140625 + + + + 128 + + + + + 539.5999755859375 + + + + 128 + + + + + 539.7999877929688 + + + + 128 + + + + + 540.2000122070312 + + + + 128 + + + + + 540.2000122070312 + + + + 128 + + + + + 540.5999755859375 + + + + 130 + + + + + 540.7999877929688 + + + + 131 + + + + + 540.7999877929688 + + + + 131 + + + + + 541.2000122070312 + + + + 132 + + + + + 541.2000122070312 + + + + 133 + + + + + 541.4000244140625 + + + + 134 + + + + + 541.2000122070312 + + + + 135 + + + + + 541.0 + + + + 135 + + + + + 540.7999877929688 + + + + 135 + + + + + 540.7999877929688 + + + + 135 + + + + + 540.4000244140625 + + + + 134 + + + + + 540.4000244140625 + + + + 131 + + + + + 540.5999755859375 + + + + 131 + + + + + 540.7999877929688 + + + + 130 + + + + + 541.0 + + + + 129 + + + + + 541.2000122070312 + + + + 128 + + + + + 541.2000122070312 + + + + 127 + + + + + 541.2000122070312 + + + + 126 + + + + + 541.0 + + + + 125 + + + + + 540.7999877929688 + + + + 125 + + + + + 540.7999877929688 + + + + 125 + + + + + 540.5999755859375 + + + + 125 + + + + + 540.2000122070312 + + + + 124 + + + + + 538.7999877929688 + + + + 122 + + + + + 537.5999755859375 + + + + 123 + + + + + 537.0 + + + + 123 + + + + + 536.2000122070312 + + + + 122 + + + + + 536.0 + + + + 121 + + + + + 536.0 + + + + 121 + + + + + 535.7999877929688 + + + + 120 + + + + + 535.5999755859375 + + + + 120 + + + + + 535.4000244140625 + + + + 120 + + + + + 535.2000122070312 + + + + 120 + + + + + 534.2000122070312 + + + + 119 + + + + + 532.7999877929688 + + + + 118 + + + + + 532.2000122070312 + + + + 128 + + + + + 531.7999877929688 + + + + 128 + + + + + 531.0 + + + + 125 + + + + + 530.5999755859375 + + + + 123 + + + + + 530.4000244140625 + + + + 121 + + + + + 529.5999755859375 + + + + 119 + + + + + 528.7999877929688 + + + + 116 + + + + + 528.5999755859375 + + + + 116 + + + + + 528.2000122070312 + + + + 115 + + + + + 527.7999877929688 + + + + 113 + + + + + 527.5999755859375 + + + + 113 + + + + + 527.7999877929688 + + + + 112 + + + + + 527.7999877929688 + + + + 112 + + + + + 527.7999877929688 + + + + 112 + + + + + 528.0 + + + + 113 + + + + + 528.2000122070312 + + + + 113 + + + + + 528.2000122070312 + + + + 113 + + + + + 528.4000244140625 + + + + 113 + + + + + 529.0 + + + + 115 + + + + + 529.4000244140625 + + + + 116 + + + + + 529.4000244140625 + + + + 116 + + + + + 529.5999755859375 + + + + 116 + + + + + 529.5999755859375 + + + + 116 + + + + + 529.5999755859375 + + + + 116 + + + + + 530.0 + + + + 117 + + + + + 530.5999755859375 + + + + 119 + + + + + 530.4000244140625 + + + + 120 + + + + + 530.4000244140625 + + + + 120 + + + + + 530.0 + + + + 123 + + + + + 529.7999877929688 + + + + 123 + + + + + 530.0 + + + + 125 + + + + + 530.2000122070312 + + + + 125 + + + + + 530.5999755859375 + + + + 125 + + + + + 530.7999877929688 + + + + 125 + + + + + 531.2000122070312 + + + + 126 + + + + + 531.4000244140625 + + + + 126 + + + + + 531.4000244140625 + + + + 126 + + + + + 531.5999755859375 + + + + 128 + + + + + 531.7999877929688 + + + + 128 + + + + + 532.2000122070312 + + + + 129 + + + + + 532.4000244140625 + + + + 130 + + + + + 532.5999755859375 + + + + 130 + + + + + 533.0 + + + + 129 + + + + + 532.7999877929688 + + + + 128 + + + + + 531.7999877929688 + + + + 127 + + + + + 531.5999755859375 + + + + 127 + + + + + 531.0 + + + + 127 + + + + + 530.7999877929688 + + + + 126 + + + + + 530.4000244140625 + + + + 125 + + + + + 530.2000122070312 + + + + 124 + + + + + 530.7999877929688 + + + + 124 + + + + + 531.0 + + + + 124 + + + + + 531.0 + + + + 123 + + + + + 530.7999877929688 + + + + 123 + + + + + 530.2000122070312 + + + + 122 + + + + + 529.5999755859375 + + + + 121 + + + + + 529.2000122070312 + + + + 121 + + + + + 528.4000244140625 + + + + 119 + + + + + 528.0 + + + + 119 + + + + + 528.5999755859375 + + + + 117 + + + + + 528.7999877929688 + + + + 116 + + + + + 529.5999755859375 + + + + 115 + + + + + 529.4000244140625 + + + + 114 + + + + + 528.5999755859375 + + + + 115 + + + + + 528.0 + + + + 116 + + + + + 527.7999877929688 + + + + 115 + + + + + 527.7999877929688 + + + + 115 + + + + + 528.0 + + + + 115 + + + + + 527.2000122070312 + + + + 114 + + + + + 526.5999755859375 + + + + 111 + + + + + 526.0 + + + + 109 + + + + + 526.0 + + + + 108 + + + + + 526.2000122070312 + + + + 108 + + + + + 526.0 + + + + 109 + + + + + 525.2000122070312 + + + + 110 + + + + + 524.7999877929688 + + + + 110 + + + + + 524.7999877929688 + + + + 110 + + + + + 523.7999877929688 + + + + 109 + + + + + 522.4000244140625 + + + + 109 + + + + + 522.2000122070312 + + + + 109 + + + + + 521.7999877929688 + + + + 110 + + + + + 521.7999877929688 + + + + 110 + + + + + 521.5999755859375 + + + + 110 + + + + + 520.4000244140625 + + + + 111 + + + + + 518.7999877929688 + + + + 112 + + + + + 518.2000122070312 + + + + 117 + + + + + 517.7999877929688 + + + + 117 + + + + + 517.4000244140625 + + + + 116 + + + + + 516.5999755859375 + + + + 115 + + + + + 515.2000122070312 + + + + 113 + + + + + 515.0 + + + + 114 + + + + + 514.5999755859375 + + + + 114 + + + + + 515.0 + + + + 114 + + + + + 516.2000122070312 + + + + 113 + + + + + 516.7999877929688 + + + + 114 + + + + + 518.4000244140625 + + + + 114 + + + + + 519.0 + + + + 114 + + + + + 519.2000122070312 + + + + 114 + + + + + 520.0 + + + + 115 + + + + + 519.4000244140625 + + + + 117 + + + + + 519.0 + + + + 117 + + + + + 517.5999755859375 + + + + 120 + + + + + 517.0 + + + + 121 + + + + + 516.0 + + + + 124 + + + + + 515.7999877929688 + + + + 124 + + + + + 515.5999755859375 + + + + 125 + + + + + 515.2000122070312 + + + + 126 + + + + + 516.2000122070312 + + + + 127 + + + + + 516.4000244140625 + + + + 127 + + + + + 517.0 + + + + 127 + + + + + 518.5999755859375 + + + + 127 + + + + + 520.2000122070312 + + + + 127 + + + + + 520.5999755859375 + + + + 126 + + + + + 520.0 + + + + 126 + + + + + 518.5999755859375 + + + + 126 + + + + + 517.2000122070312 + + + + 127 + + + + + 515.7999877929688 + + + + 126 + + + + + 514.4000244140625 + + + + 126 + + + + + 514.0 + + + + 126 + + + + + 514.5999755859375 + + + + 125 + + + + + 515.2000122070312 + + + + 125 + + + + + 515.4000244140625 + + + + 125 + + + + + 516.4000244140625 + + + + 125 + + + + + 516.5999755859375 + + + + 125 + + + + + 517.4000244140625 + + + + 125 + + + + + 518.4000244140625 + + + + 125 + + + + + 519.2000122070312 + + + + 125 + + + + + 519.0 + + + + 126 + + + + + 518.0 + + + + 126 + + + + + 517.0 + + + + 127 + + + + + 517.2000122070312 + + + + 128 + + + + + 518.2000122070312 + + + + 128 + + + + + 519.4000244140625 + + + + 129 + + + + + 520.5999755859375 + + + + 130 + + + + + 521.7999877929688 + + + + 130 + + + + + 522.7999877929688 + + + + 131 + + + + + 523.4000244140625 + + + + 132 + + + + + 525.0 + + + + 133 + + + + + 527.7999877929688 + + + + 134 + + + + + 530.2000122070312 + + + + 135 + + + + + 531.4000244140625 + + + + 137 + + + + + 530.7999877929688 + + + + 139 + + + + + 529.2000122070312 + + + + 140 + + + + + 528.2000122070312 + + + + 140 + + + + + 526.7999877929688 + + + + 140 + + + + + 525.0 + + + + 140 + + + + + 523.4000244140625 + + + + 139 + + + + + 523.0 + + + + 139 + + + + + 523.7999877929688 + + + + 138 + + + + + 525.0 + + + + 137 + + + + + 524.4000244140625 + + + + 136 + + + + + 523.0 + + + + 135 + + + + + 522.7999877929688 + + + + 133 + + + + + 522.7999877929688 + + + + 133 + + + + + 522.4000244140625 + + + + 131 + + + + + 523.0 + + + + 130 + + + + + 523.7999877929688 + + + + 129 + + + + + 526.2000122070312 + + + + 128 + + + + + 527.0 + + + + 127 + + + + + 527.0 + + + + 126 + + + + + 526.7999877929688 + + + + 127 + + + + + 526.2000122070312 + + + + 127 + + + + + 524.7999877929688 + + + + 126 + + + + + 524.2000122070312 + + + + 126 + + + + + 523.4000244140625 + + + + 126 + + + + + 519.7999877929688 + + + + 125 + + + + + 518.0 + + + + 124 + + + + + 516.2000122070312 + + + + 123 + + + + + 515.5999755859375 + + + + 123 + + + + + 515.0 + + + + 123 + + + + + 513.7999877929688 + + + + 123 + + + + + 512.0 + + + + 122 + + + + + 511.6000061035156 + + + + 122 + + + + + 511.0 + + + + 122 + + + + + 510.0 + + + + 122 + + + + + 509.6000061035156 + + + + 123 + + + + + 509.3999938964844 + + + + 122 + + + + + 509.20001220703125 + + + + 123 + + + + + 509.3999938964844 + + + + 123 + + + + + 509.3999938964844 + + + + 123 + + + + + 509.6000061035156 + + + + 123 + + + + + 509.79998779296875 + + + + 123 + + + + + 510.20001220703125 + + + + 123 + + + + + 511.20001220703125 + + + + 124 + + + + + 511.6000061035156 + + + + 124 + + + + + 512.0 + + + + 125 + + + + + 513.0 + + + + 125 + + + + + 513.5999755859375 + + + + 125 + + + + + 514.4000244140625 + + + + 126 + + + + + 515.4000244140625 + + + + 127 + + + + + 517.2000122070312 + + + + 127 + + + + + 517.5999755859375 + + + + 128 + + + + + 518.0 + + + + 128 + + + + + 518.4000244140625 + + + + 129 + + + + + 518.2000122070312 + + + + 130 + + + + + 517.7999877929688 + + + + 131 + + + + + 514.4000244140625 + + + + 133 + + + + + 511.0 + + + + 134 + + + + + 509.79998779296875 + + + + 133 + + + + + 509.0 + + + + 133 + + + + + 508.0 + + + + 134 + + + + + 507.3999938964844 + + + + 134 + + + + + 507.0 + + + + 134 + + + + + 507.3999938964844 + + + + 133 + + + + + 507.6000061035156 + + + + 133 + + + + + 507.79998779296875 + + + + 133 + + + + + 508.6000061035156 + + + + 132 + + + + + 509.6000061035156 + + + + 132 + + + + + 510.6000061035156 + + + + 132 + + + + + 511.20001220703125 + + + + 132 + + + + + 511.20001220703125 + + + + 131 + + + + + 510.79998779296875 + + + + 131 + + + + + 512.2000122070312 + + + + 130 + + + + + 512.7999877929688 + + + + 129 + + + + + 513.4000244140625 + + + + 129 + + + + + 513.2000122070312 + + + + 129 + + + + + 511.20001220703125 + + + + 129 + + + + + 507.3999938964844 + + + + 129 + + + + + 507.20001220703125 + + + + 129 + + + + + 506.20001220703125 + + + + 130 + + + + + 506.0 + + + + 130 + + + + + 505.0 + + + + 130 + + + + + 505.20001220703125 + + + + 130 + + + + + 505.6000061035156 + + + + 131 + + + + + 505.6000061035156 + + + + 132 + + + + + 505.79998779296875 + + + + 132 + + + + + 505.79998779296875 + + + + 132 + + + + + 506.20001220703125 + + + + 132 + + + + + 506.3999938964844 + + + + 131 + + + + + 506.79998779296875 + + + + 131 + + + + + 507.6000061035156 + + + + 131 + + + + + 508.3999938964844 + + + + 131 + + + + + 509.20001220703125 + + + + 131 + + + + + 509.6000061035156 + + + + 132 + + + + + 509.79998779296875 + + + + 132 + + + + + 509.79998779296875 + + + + 132 + + + + + 509.79998779296875 + + + + 131 + + + + + 510.20001220703125 + + + + 129 + + + + + 511.0 + + + + 129 + + + + + 512.2000122070312 + + + + 128 + + + + + 513.4000244140625 + + + + 129 + + + + + 513.4000244140625 + + + + 130 + + + + + 513.7999877929688 + + + + 131 + + + + + 514.5999755859375 + + + + 132 + + + + + 515.2000122070312 + + + + 133 + + + + + 515.5999755859375 + + + + 134 + + + + + 516.4000244140625 + + + + 136 + + + + + 517.0 + + + + 136 + + + + + 518.0 + + + + 136 + + + + + 518.5999755859375 + + + + 136 + + + + + 519.4000244140625 + + + + 136 + + + + + 519.5999755859375 + + + + 136 + + + + + 520.2000122070312 + + + + 136 + + + + + 520.4000244140625 + + + + 137 + + + + + 520.7999877929688 + + + + 137 + + + + + 521.4000244140625 + + + + 136 + + + + + 522.0 + + + + 135 + + + + + 522.7999877929688 + + + + 135 + + + + + 522.7999877929688 + + + + 135 + + + + + 523.2000122070312 + + + + 135 + + + + + 523.7999877929688 + + + + 136 + + + + + 525.0 + + + + 137 + + + + + 526.2000122070312 + + + + 137 + + + + + 527.4000244140625 + + + + 138 + + + + + 527.7999877929688 + + + + 139 + + + + + 528.2000122070312 + + + + 140 + + + + + 528.4000244140625 + + + + 142 + + + + + 528.5999755859375 + + + + 141 + + + + + 529.0 + + + + 141 + + + + + 529.5999755859375 + + + + 140 + + + + + 530.7999877929688 + + + + 138 + + + + + 531.0 + + + + 137 + + + + + 531.7999877929688 + + + + 135 + + + + + 532.7999877929688 + + + + 135 + + + + + 533.4000244140625 + + + + 136 + + + + + 534.0 + + + + 136 + + + + + 534.5999755859375 + + + + 137 + + + + + 534.5999755859375 + + + + 138 + + + + + 535.0 + + + + 138 + + + + + 535.4000244140625 + + + + 139 + + + + + 535.7999877929688 + + + + 139 + + + + + 536.5999755859375 + + + + 139 + + + + + 537.7999877929688 + + + + 139 + + + + + 538.7999877929688 + + + + 141 + + + + + 539.0 + + + + 141 + + + + + 540.0 + + + + 141 + + + + + 541.2000122070312 + + + + 140 + + + + + 542.5999755859375 + + + + 139 + + + + + 543.5999755859375 + + + + 138 + + + + + 544.0 + + + + 138 + + + + + 544.4000244140625 + + + + 137 + + + + + 545.0 + + + + 138 + + + + + 545.4000244140625 + + + + 137 + + + + + 545.5999755859375 + + + + 136 + + + + + 546.2000122070312 + + + + 137 + + + + + 547.7999877929688 + + + + 137 + + + + + 548.4000244140625 + + + + 139 + + + + + 548.5999755859375 + + + + 140 + + + + + 548.0 + + + + 140 + + + + + 547.4000244140625 + + + + 139 + + + + + 545.7999877929688 + + + + 137 + + + + + 543.5999755859375 + + + + 135 + + + + + 542.5999755859375 + + + + 132 + + + + + 542.4000244140625 + + + + 131 + + + + + 542.2000122070312 + + + + 130 + + + + + 542.2000122070312 + + + + 130 + + + + + 542.0 + + + + 130 + + + + + 542.0 + + + + 130 + + + + + 542.7999877929688 + + + + 129 + + + + + 543.2000122070312 + + + + 128 + + + + + 544.2000122070312 + + + + 127 + + + + + 544.4000244140625 + + + + 126 + + + + + 544.5999755859375 + + + + 126 + + + + + 545.0 + + + + 124 + + + + + 545.5999755859375 + + + + 124 + + + + + 547.2000122070312 + + + + 123 + + + + + 548.2000122070312 + + + + 123 + + + + + 548.4000244140625 + + + + 124 + + + + + 548.5999755859375 + + + + 125 + + + + + 549.0 + + + + 125 + + + + + 549.4000244140625 + + + + 127 + + + + + 549.4000244140625 + + + + 129 + + + + + 549.5999755859375 + + + + 130 + + + + + 549.7999877929688 + + + + 130 + + + + + 550.4000244140625 + + + + 131 + + + + + 550.5999755859375 + + + + 131 + + + + + 551.2000122070312 + + + + 132 + + + + + 552.0 + + + + 133 + + + + + 552.4000244140625 + + + + 133 + + + + + 552.7999877929688 + + + + 133 + + + + + 553.2000122070312 + + + + 133 + + + + + 553.5999755859375 + + + + 133 + + + + + 554.2000122070312 + + + + 134 + + + + + 555.0 + + + + 134 + + + + + 555.4000244140625 + + + + 136 + + + + + 555.4000244140625 + + + + 137 + + + + + 555.7999877929688 + + + + 138 + + + + + 556.4000244140625 + + + + 138 + + + + + 556.7999877929688 + + + + 138 + + + + + 557.2000122070312 + + + + 139 + + + + + 557.2000122070312 + + + + 136 + + + + + 557.2000122070312 + + + + 136 + + + + + 557.2000122070312 + + + + 136 + + + + + 557.5999755859375 + + + + 133 + + + + + 557.5999755859375 + + + + 130 + + + + + 557.4000244140625 + + + + 133 + + + + + 557.4000244140625 + + + + 129 + + + + + 557.4000244140625 + + + + 128 + + + + + 557.5999755859375 + + + + 125 + + + + + 557.5999755859375 + + + + 122 + + + + + 557.5999755859375 + + + + 119 + + + + + 557.5999755859375 + + + + 122 + + + + + 557.5999755859375 + + + + 119 + + + + + 557.5999755859375 + + + + 114 + + + + + 557.5999755859375 + + + + 112 + + + + + 557.4000244140625 + + + + 112 + + + + + 557.5999755859375 + + + + 113 + + + + + 557.0 + + + + 115 + + + + + 556.4000244140625 + + + + 114 + + + + + 554.7999877929688 + + + + 114 + + + + + 553.4000244140625 + + + + 114 + + + + + 550.5999755859375 + + + + 112 + + + + + 549.7999877929688 + + + + 112 + + + + + 548.4000244140625 + + + + 112 + + + + + 547.5999755859375 + + + + 112 + + + + + 546.7999877929688 + + + + 111 + + + + + 546.2000122070312 + + + + 112 + + + + + 545.7999877929688 + + + + 113 + + + + + 545.5999755859375 + + + + 113 + + + + + 545.5999755859375 + + + + 112 + + + + + 546.0 + + + + 112 + + + + + 546.2000122070312 + + + + 111 + + + + + 546.7999877929688 + + + + 112 + + + + + 547.7999877929688 + + + + 113 + + + + + 548.0 + + + + 114 + + + + + 548.0 + + + + 114 + + + + + 548.2000122070312 + + + + 114 + + + + + 548.0 + + + + 114 + + + + + 548.0 + + + + 117 + + + + + 548.2000122070312 + + + + 117 + + + + + 548.2000122070312 + + + + 117 + + + + + 548.5999755859375 + + + + 114 + + + + + 548.5999755859375 + + + + 114 + + + + + 548.7999877929688 + + + + 114 + + + + + 549.7999877929688 + + + + 114 + + + + + 551.5999755859375 + + + + 117 + + + + + 553.7999877929688 + + + + 120 + + + + + 556.0 + + + + 123 + + + + + 557.4000244140625 + + + + 125 + + + + + 558.0 + + + + 124 + + + + + 559.5999755859375 + + + + 125 + + + + + 560.2000122070312 + + + + 135 + + + + + 560.2000122070312 + + + + 135 + + + + + 560.2000122070312 + + + + 135 + + + + + 560.5999755859375 + + + + 133 + + + + + 561.5999755859375 + + + + 135 + + + + + 562.4000244140625 + + + + 136 + + + + + 562.7999877929688 + + + + 137 + + + + + 563.0 + + + + 138 + + + + + 563.5999755859375 + + + + 141 + + + + + 563.7999877929688 + + + + 141 + + + + + 564.0 + + + + 142 + + + + + 564.0 + + + + 142 + + + + + 564.2000122070312 + + + + 143 + + + + + 564.4000244140625 + + + + 144 + + + + + 564.4000244140625 + + + + 144 + + + + + 564.5999755859375 + + + + 145 + + + + + 564.5999755859375 + + + + 146 + + + + + 564.7999877929688 + + + + 145 + + + + + 565.0 + + + + 144 + + + + + 565.2000122070312 + + + + 144 + + + + + 565.2000122070312 + + + + 144 + + + + + 565.7999877929688 + + + + 143 + + + + + 566.0 + + + + 143 + + + + + 566.5999755859375 + + + + 142 + + + + + 566.7999877929688 + + + + 142 + + + + + 567.4000244140625 + + + + 141 + + + + + 568.2000122070312 + + + + 138 + + + + + 569.0 + + + + 136 + + + + + 570.2000122070312 + + + + 135 + + + + + 571.5999755859375 + + + + 134 + + + + + 572.7999877929688 + + + + 133 + + + + + 573.7999877929688 + + + + 132 + + + + + 574.4000244140625 + + + + 133 + + + + + 574.7999877929688 + + + + 133 + + + + + 575.4000244140625 + + + + 132 + + + + + 576.0 + + + + 133 + + + + + 577.0 + + + + 132 + + + + + 577.4000244140625 + + + + 132 + + + + + 577.7999877929688 + + + + 133 + + + + + 578.2000122070312 + + + + 133 + + + + + 578.2000122070312 + + + + 133 + + + + + 578.5999755859375 + + + + 134 + + + + + 578.7999877929688 + + + + 134 + + + + + 579.4000244140625 + + + + 134 + + + + + 579.5999755859375 + + + + 133 + + + + + 580.2000122070312 + + + + 133 + + + + + 581.0 + + + + 134 + + + + + 581.2000122070312 + + + + 134 + + + + + 581.5999755859375 + + + + 134 + + + + + 582.0 + + + + 135 + + + + + 582.2000122070312 + + + + 135 + + + + + 582.5999755859375 + + + + 135 + + + + + 582.7999877929688 + + + + 135 + + + + + 583.0 + + + + 134 + + + + + 583.0 + + + + 134 + + + + + 583.5999755859375 + + + + 134 + + + + + 583.7999877929688 + + + + 134 + + + + + 584.2000122070312 + + + + 134 + + + + + 584.7999877929688 + + + + 134 + + + + + 585.0 + + + + 134 + + + + + 585.7999877929688 + + + + 134 + + + + + 586.0 + + + + 135 + + + + + 586.4000244140625 + + + + 135 + + + + + 587.5999755859375 + + + + 135 + + + + + 588.2000122070312 + + + + 135 + + + + + 588.7999877929688 + + + + 135 + + + + + 589.5999755859375 + + + + 137 + + + + + 590.4000244140625 + + + + 138 + + + + + 590.7999877929688 + + + + 138 + + + + + 591.0 + + + + 138 + + + + + 591.2000122070312 + + + + 138 + + + + + 591.4000244140625 + + + + 138 + + + + + 592.0 + + + + 138 + + + + + 593.0 + + + + 137 + + + + + 593.2000122070312 + + + + 136 + + + + + 593.4000244140625 + + + + 135 + + + + + 593.7999877929688 + + + + 136 + + + + + 594.0 + + + + 135 + + + + + 594.4000244140625 + + + + 135 + + + + + 595.0 + + + + 135 + + + + + 595.7999877929688 + + + + 135 + + + + + 596.5999755859375 + + + + 135 + + + + + 598.2000122070312 + + + + 134 + + + + + 599.0 + + + + 132 + + + + + 599.0 + + + + 131 + + + + + 598.5999755859375 + + + + 130 + + + + + 597.7999877929688 + + + + 128 + + + + + 597.5999755859375 + + + + 128 + + + + + 597.2000122070312 + + + + 126 + + + + + 596.2000122070312 + + + + 123 + + + + + 595.7999877929688 + + + + 121 + + + + + 594.4000244140625 + + + + 120 + + + + + 591.5999755859375 + + + + 118 + + + + + 590.0 + + + + 116 + + + + + 588.4000244140625 + + + + 115 + + + + + 585.7999877929688 + + + + 114 + + + + + 585.0 + + + + 115 + + + + + 585.0 + + + + 114 + + + + + 584.7999877929688 + + + + 114 + + + + + 584.5999755859375 + + + + 114 + + + + + 584.2000122070312 + + + + 114 + + + + + 583.7999877929688 + + + + 114 + + + + + 583.7999877929688 + + + + 114 + + + + + 584.0 + + + + 114 + + + + + 584.4000244140625 + + + + 115 + + + + + 584.4000244140625 + + + + 115 + + + + + 584.5999755859375 + + + + 112 + + + + + 584.5999755859375 + + + + 109 + + + + + 584.7999877929688 + + + + 112 + + + + + 584.7999877929688 + + + + 115 + + + + + 584.7999877929688 + + + + 112 + + + + + 584.7999877929688 + + + + 107 + + + + + 584.7999877929688 + + + + 107 + + + + + 585.0 + + + + 110 + + + + + 584.7999877929688 + + + + 105 + + + + + 584.7999877929688 + + + + 104 + + + + + 584.7999877929688 + + + + 107 + + + + + 584.5999755859375 + + + + 110 + + + + + 584.7999877929688 + + + + 107 + + + + + 585.7999877929688 + + + + 107 + + + + + 587.4000244140625 + + + + 109 + + + + + 587.7999877929688 + + + + 119 + + + + + 588.2000122070312 + + + + 119 + + + + + 588.7999877929688 + + + + 120 + + + + + 589.7999877929688 + + + + 122 + + + + + 590.0 + + + + 123 + + + + + 590.5999755859375 + + + + 123 + + + + + 591.2000122070312 + + + + 124 + + + + + 591.5999755859375 + + + + 125 + + + + + 592.0 + + + + 126 + + + + + 592.0 + + + + 126 + + + + + 592.5999755859375 + + + + 128 + + + + + 593.2000122070312 + + + + 128 + + + + + 593.4000244140625 + + + + 128 + + + + + 593.5999755859375 + + + + 128 + + + + + 594.2000122070312 + + + + 129 + + + + + 594.5999755859375 + + + + 129 + + + + + 595.0 + + + + 130 + + + + + 595.2000122070312 + + + + 130 + + + + + 596.4000244140625 + + + + 131 + + + + + 596.7999877929688 + + + + 131 + + + + + 597.2000122070312 + + + + 131 + + + + + 597.4000244140625 + + + + 132 + + + + + 597.7999877929688 + + + + 131 + + + + + 598.4000244140625 + + + + 132 + + + + + 599.4000244140625 + + + + 133 + + + + + 600.2000122070312 + + + + 133 + + + + + 601.4000244140625 + + + + 134 + + + + + 601.7999877929688 + + + + 134 + + + + + 602.0 + + + + 134 + + + + + 602.4000244140625 + + + + 134 + + + + + 602.7999877929688 + + + + 134 + + + + + 603.4000244140625 + + + + 134 + + + + + 604.0 + + + + 135 + + + + + 604.2000122070312 + + + + 137 + + + + + 604.5999755859375 + + + + 139 + + + + + 604.5999755859375 + + + + 139 + + + + + 604.7999877929688 + + + + 139 + + + + + 604.7999877929688 + + + + 138 + + + + + 605.4000244140625 + + + + 138 + + + + + 605.5999755859375 + + + + 138 + + + + + 606.0 + + + + 138 + + + + + 606.7999877929688 + + + + 138 + + + + + 607.5999755859375 + + + + 138 + + + + + 608.0 + + + + 139 + + + + + 608.4000244140625 + + + + 139 + + + + + 608.5999755859375 + + + + 139 + + + + + 608.5999755859375 + + + + 139 + + + + + 609.0 + + + + 139 + + + + + 609.0 + + + + 139 + + + + + 609.2000122070312 + + + + 139 + + + + + 609.7999877929688 + + + + 138 + + + + + 610.4000244140625 + + + + 137 + + + + + 610.5999755859375 + + + + 137 + + + + + 611.0 + + + + 135 + + + + + 611.2000122070312 + + + + 134 + + + + + 611.2000122070312 + + + + 134 + + + + + 611.2000122070312 + + + + 133 + + + + + 611.2000122070312 + + + + 132 + + + + + 611.2000122070312 + + + + 130 + + + + + 611.2000122070312 + + + + 128 + + + + + 611.0 + + + + 127 + + + + + 611.7999877929688 + + + + 126 + + + + + 613.2000122070312 + + + + 126 + + + + + 614.2000122070312 + + + + 125 + + + + + 615.0 + + + + 126 + + + + + 615.5999755859375 + + + + 126 + + + + + 615.7999877929688 + + + + 127 + + + + + 616.4000244140625 + + + + 127 + + + + + 616.7999877929688 + + + + 128 + + + + + 617.0 + + + + 128 + + + + + 617.4000244140625 + + + + 129 + + + + + 617.4000244140625 + + + + 128 + + + + + 618.0 + + + + 129 + + + + + 618.2000122070312 + + + + 129 + + + + + 618.2000122070312 + + + + 129 + + + + + 618.2000122070312 + + + + 130 + + + + + 618.4000244140625 + + + + 131 + + + + + 618.5999755859375 + + + + 132 + + + + + 618.7999877929688 + + + + 132 + + + + + 619.4000244140625 + + + + 132 + + + + + 619.7999877929688 + + + + 131 + + + + + 620.2000122070312 + + + + 130 + + + + + 620.7999877929688 + + + + 130 + + + + + 621.2000122070312 + + + + 131 + + + + + 621.4000244140625 + + + + 132 + + + + + 621.5999755859375 + + + + 132 + + + + + 621.7999877929688 + + + + 132 + + + + + 621.7999877929688 + + + + 133 + + + + + 622.0 + + + + 134 + + + + + 622.4000244140625 + + + + 136 + + + + + 622.7999877929688 + + + + 138 + + + + + 622.7999877929688 + + + + 138 + + + + + 623.2000122070312 + + + + 139 + + + + + 623.4000244140625 + + + + 139 + + + + + 623.5999755859375 + + + + 140 + + + + + 623.7999877929688 + + + + 140 + + + + + 624.4000244140625 + + + + 141 + + + + + 625.2000122070312 + + + + 141 + + + + + 626.0 + + + + 141 + + + + + 628.0 + + + + 140 + + + + + 629.5999755859375 + + + + 140 + + + + + 630.2000122070312 + + + + 139 + + + + + 630.5999755859375 + + + + 137 + + + + + 630.7999877929688 + + + + 136 + + + + + 631.0 + + + + 136 + + + + + 631.2000122070312 + + + + 136 + + + + + 631.2000122070312 + + + + 136 + + + + + 631.2000122070312 + + + + 136 + + + + + 631.5999755859375 + + + + 136 + + + + + 631.7999877929688 + + + + 137 + + + + + 631.7999877929688 + + + + 138 + + + + + 632.0 + + + + 138 + + + + + 632.0 + + + + 138 + + + + + 632.4000244140625 + + + + 139 + + + + + 632.4000244140625 + + + + 139 + + + + + 632.4000244140625 + + + + 139 + + + + + 632.5999755859375 + + + + 139 + + + + + 632.7999877929688 + + + + 138 + + + + + 633.4000244140625 + + + + 137 + + + + + 634.4000244140625 + + + + 135 + + + + + 634.5999755859375 + + + + 136 + + + + + 635.2000122070312 + + + + 136 + + + + + 635.4000244140625 + + + + 136 + + + + + 635.7999877929688 + + + + 136 + + + + + 636.5999755859375 + + + + 135 + + + + + 637.0 + + + + 134 + + + + + 637.2000122070312 + + + + 133 + + + + + 637.5999755859375 + + + + 132 + + + + + 638.2000122070312 + + + + 132 + + + + + 638.7999877929688 + + + + 133 + + + + + 639.2000122070312 + + + + 133 + + + + + 640.4000244140625 + + + + 135 + + + + + 641.4000244140625 + + + + 136 + + + + + 641.7999877929688 + + + + 136 + + + + + 641.7999877929688 + + + + 136 + + + + + 641.7999877929688 + + + + 135 + + + + + 641.7999877929688 + + + + 135 + + + + + 641.7999877929688 + + + + 134 + + + + + 641.7999877929688 + + + + 131 + + + + + 641.7999877929688 + + + + 128 + + + + + 641.7999877929688 + + + + 125 + + + + + 641.5999755859375 + + + + 119 + + + + + 641.7999877929688 + + + + 116 + + + + + 641.7999877929688 + + + + 115 + + + + + 642.2000122070312 + + + + 117 + + + + + 643.0 + + + + 116 + + + + + 643.5999755859375 + + + + 118 + + + + + 644.2000122070312 + + + + 119 + + + + + 644.5999755859375 + + + + 119 + + + + + 645.4000244140625 + + + + 120 + + + + + 646.2000122070312 + + + + 122 + + + + + 646.5999755859375 + + + + 122 + + + + + 647.5999755859375 + + + + 124 + + + + + 647.7999877929688 + + + + 124 + + + + + 648.7999877929688 + + + + 125 + + + + + 649.4000244140625 + + + + 125 + + + + + 650.4000244140625 + + + + 128 + + + + + 650.5999755859375 + + + + 128 + + + + + 652.0 + + + + 130 + + + + + 653.4000244140625 + + + + 133 + + + + + 654.0 + + + + 134 + + + + + 655.2000122070312 + + + + 136 + + + + + 655.7999877929688 + + + + 138 + + + + + 656.0 + + + + 138 + + + + + 657.4000244140625 + + + + 139 + + + + + 657.5999755859375 + + + + 139 + + + + + 658.2000122070312 + + + + 140 + + + + + 658.5999755859375 + + + + 140 + + + + + 659.0 + + + + 140 + + + + + 659.4000244140625 + + + + 140 + + + + + 659.5999755859375 + + + + 140 + + + + + 660.2000122070312 + + + + 140 + + + + + 660.2000122070312 + + + + 140 + + + + + 660.4000244140625 + + + + 140 + + + + + 661.0 + + + + 140 + + + + + 661.7999877929688 + + + + 141 + + + + + 662.7999877929688 + + + + 140 + + + + + 663.5999755859375 + + + + 140 + + + + + 663.7999877929688 + + + + 140 + + + + + 664.5999755859375 + + + + 139 + + + + + 665.7999877929688 + + + + 139 + + + + + 666.0 + + + + 139 + + + + + 666.4000244140625 + + + + 139 + + + + + 667.4000244140625 + + + + 139 + + + + + 667.4000244140625 + + + + 139 + + + + + 667.5999755859375 + + + + 139 + + + + + 667.7999877929688 + + + + 139 + + + + + 668.4000244140625 + + + + 139 + + + + + 669.2000122070312 + + + + 140 + + + + + 669.2000122070312 + + + + 140 + + + + + 669.5999755859375 + + + + 141 + + + + + 669.7999877929688 + + + + 141 + + + + + 670.0 + + + + 141 + + + + + 670.0 + + + + 142 + + + + + 670.2000122070312 + + + + 141 + + + + + 670.5999755859375 + + + + 141 + + + + + 671.0 + + + + 141 + + + + + 670.4000244140625 + + + + 141 + + + + + 670.4000244140625 + + + + 141 + + + + + 670.4000244140625 + + + + 141 + + + + + 670.4000244140625 + + + + 140 + + + + + 670.5999755859375 + + + + 140 + + + + + 670.4000244140625 + + + + 140 + + + + + 669.7999877929688 + + + + 139 + + + + + 669.4000244140625 + + + + 138 + + + + + 669.0 + + + + 136 + + + + + 667.7999877929688 + + + + 135 + + + + + 668.7999877929688 + + + + 134 + + + + + 669.7999877929688 + + + + 134 + + + + + 670.5999755859375 + + + + 133 + + + + + 672.4000244140625 + + + + 131 + + + + + 674.5999755859375 + + + + 131 + + + + + 675.7999877929688 + + + + 130 + + + + + 676.0 + + + + 130 + + + + + 676.4000244140625 + + + + 129 + + + + + 676.7999877929688 + + + + 130 + + + + + 677.2000122070312 + + + + 130 + + + + + 677.7999877929688 + + + + 130 + + + + + 678.0 + + + + 131 + + + + + 678.2000122070312 + + + + 131 + + + + + 678.5999755859375 + + + + 132 + + + + + 679.0 + + + + 133 + + + + + 679.0 + + + + 133 + + + + + 679.5999755859375 + + + + 134 + + + + + 680.0 + + + + 135 + + + + + 680.4000244140625 + + + + 135 + + + + + 680.7999877929688 + + + + 136 + + + + + 681.0 + + + + 137 + + + + + 680.7999877929688 + + + + 137 + + + + + 680.7999877929688 + + + + 137 + + + + + 680.7999877929688 + + + + 137 + + + + + 680.7999877929688 + + + + 137 + + + + + 681.0 + + + + 137 + + + + + 681.0 + + + + 137 + + + + + 681.4000244140625 + + + + 138 + + + + + 681.4000244140625 + + + + 138 + + + + + 681.5999755859375 + + + + 138 + + + + + 681.5999755859375 + + + + 137 + + + + + 682.0 + + + + 138 + + + + + 682.2000122070312 + + + + 138 + + + + + 682.5999755859375 + + + + 138 + + + + + 682.7999877929688 + + + + 138 + + + + + 683.2000122070312 + + + + 138 + + + + + 683.5999755859375 + + + + 138 + + + + + 683.5999755859375 + + + + 139 + + + + + 683.7999877929688 + + + + 138 + + + + + 684.0 + + + + 138 + + + + + 684.2000122070312 + + + + 138 + + + + + 685.0 + + + + 137 + + + + + 685.5999755859375 + + + + 137 + + + + + 685.7999877929688 + + + + 137 + + + + + 686.2000122070312 + + + + 136 + + + + + 686.4000244140625 + + + + 135 + + + + + 686.7999877929688 + + + + 134 + + + + + 687.4000244140625 + + + + 134 + + + + + 688.0 + + + + 131 + + + + + 687.7999877929688 + + + + 131 + + + + + 686.7999877929688 + + + + 129 + + + + + 686.2000122070312 + + + + 128 + + + + + 685.4000244140625 + + + + 127 + + + + + 685.0 + + + + 124 + + + + + 685.0 + + + + 124 + + + + + 685.4000244140625 + + + + 124 + + + + + 686.2000122070312 + + + + 124 + + + + + 687.0 + + + + 123 + + + + + 687.4000244140625 + + + + 124 + + + + + 687.5999755859375 + + + + 124 + + + + + 687.7999877929688 + + + + 124 + + + + + 687.5999755859375 + + + + 125 + + + + + 687.4000244140625 + + + + 125 + + + + + 687.0 + + + + 126 + + + + + 686.7999877929688 + + + + 127 + + + + + 687.4000244140625 + + + + 127 + + + + + 688.2000122070312 + + + + 127 + + + + + 689.0 + + + + 128 + + + + + 689.4000244140625 + + + + 129 + + + + + 689.5999755859375 + + + + 130 + + + + + 690.0 + + + + 131 + + + + + 690.4000244140625 + + + + 132 + + + + + 690.5999755859375 + + + + 133 + + + + + 690.5999755859375 + + + + 132 + + + + + 690.5999755859375 + + + + 132 + + + + + 690.5999755859375 + + + + 132 + + + + + 690.7999877929688 + + + + 132 + + + + + 690.7999877929688 + + + + 132 + + + + + 690.7999877929688 + + + + 131 + + + + + 690.5999755859375 + + + + 130 + + + + + 690.4000244140625 + + + + 130 + + + + + 690.2000122070312 + + + + 129 + + + + + 690.0 + + + + 129 + + + + + 689.7999877929688 + + + + 130 + + + + + 689.7999877929688 + + + + 130 + + + + + 689.5999755859375 + + + + 131 + + + + + 689.4000244140625 + + + + 132 + + + + + 689.2000122070312 + + + + 132 + + + + + 689.0 + + + + 132 + + + + + 688.5999755859375 + + + + 131 + + + + + 688.2000122070312 + + + + 130 + + + + + 687.5999755859375 + + + + 129 + + + + + 687.2000122070312 + + + + 128 + + + + + 685.7999877929688 + + + + 127 + + + + + 684.5999755859375 + + + + 127 + + + + + 684.4000244140625 + + + + 127 + + + + + 684.0 + + + + 126 + + + + + 684.0 + + + + 126 + + + + + 684.4000244140625 + + + + 125 + + + + + 684.0 + + + + 125 + + + + + 683.7999877929688 + + + + 125 + + + + + 683.5999755859375 + + + + 125 + + + + + 683.2000122070312 + + + + 125 + + + + + 683.2000122070312 + + + + 124 + + + + + 683.7999877929688 + + + + 124 + + + + + 683.7999877929688 + + + + 125 + + + + + 684.0 + + + + 124 + + + + + 684.4000244140625 + + + + 125 + + + + + 685.4000244140625 + + + + 125 + + + + + 686.5999755859375 + + + + 126 + + + + + 686.7999877929688 + + + + 126 + + + + + 687.4000244140625 + + + + 127 + + + + + 687.0 + + + + 129 + + + + + 685.7999877929688 + + + + 129 + + + + + 685.2000122070312 + + + + 129 + + + + + 684.7999877929688 + + + + 129 + + + + + 685.2000122070312 + + + + 129 + + + + + 685.5999755859375 + + + + 130 + + + + + 685.7999877929688 + + + + 130 + + + + + 686.2000122070312 + + + + 131 + + + + + 686.2000122070312 + + + + 131 + + + + + 686.4000244140625 + + + + 132 + + + + + 686.5999755859375 + + + + 133 + + + + + 686.7999877929688 + + + + 133 + + + + + 687.0 + + + + 134 + + + + + 687.2000122070312 + + + + 135 + + + + + 687.4000244140625 + + + + 136 + + + + + 687.4000244140625 + + + + 137 + + + + + 687.4000244140625 + + + + 138 + + + + + 687.7999877929688 + + + + 139 + + + + + 688.0 + + + + 140 + + + + + 688.0 + + + + 140 + + + + + 688.0 + + + + 141 + + + + + 688.2000122070312 + + + + 141 + + + + + 688.4000244140625 + + + + 141 + + + + + 688.5999755859375 + + + + 139 + + + + + 688.7999877929688 + + + + 138 + + + + + 688.7999877929688 + + + + 137 + + + + + 689.2000122070312 + + + + 136 + + + + + 689.5999755859375 + + + + 135 + + + + + 689.7999877929688 + + + + 135 + + + + + 690.2000122070312 + + + + 134 + + + + + 690.2000122070312 + + + + 134 + + + + + 690.4000244140625 + + + + 135 + + + + + 690.4000244140625 + + + + 137 + + + + + 690.5999755859375 + + + + 138 + + + + + 691.0 + + + + 140 + + + + + 691.2000122070312 + + + + 141 + + + + + 691.4000244140625 + + + + 141 + + + + + 691.5999755859375 + + + + 141 + + + + + 691.7999877929688 + + + + 140 + + + + + 691.7999877929688 + + + + 139 + + + + + 692.0 + + + + 139 + + + + + 691.5999755859375 + + + + 139 + + + + + 691.4000244140625 + + + + 139 + + + + + 691.0 + + + + 137 + + + + + 690.7999877929688 + + + + 137 + + + + + 690.2000122070312 + + + + 134 + + + + + 689.4000244140625 + + + + 131 + + + + + 689.2000122070312 + + + + 130 + + + + + 688.2000122070312 + + + + 128 + + + + + 688.0 + + + + 128 + + + + + 687.7999877929688 + + + + 128 + + + + + 687.2000122070312 + + + + 127 + + + + + 687.2000122070312 + + + + 127 + + + + + 687.0 + + + + 127 + + + + + 687.0 + + + + 125 + + + + + 686.7999877929688 + + + + 125 + + + + + 686.7999877929688 + + + + 124 + + + + + 686.4000244140625 + + + + 123 + + + + + 685.7999877929688 + + + + 121 + + + + + 683.7999877929688 + + + + 120 + + + + + 683.4000244140625 + + + + 120 + + + + + 683.0 + + + + 119 + + + + + 683.0 + + + + 119 + + + + + 683.5999755859375 + + + + 119 + + + + + 683.5999755859375 + + + + 118 + + + + + 683.4000244140625 + + + + 118 + + + + + 682.2000122070312 + + + + 116 + + + + + 680.5999755859375 + + + + 116 + + + + + 680.2000122070312 + + + + 115 + + + + + 679.5999755859375 + + + + 115 + + + + + 679.0 + + + + 114 + + + + + 678.7999877929688 + + + + 114 + + + + + 678.7999877929688 + + + + 114 + + + + + 678.5999755859375 + + + + 115 + + + + + 678.4000244140625 + + + + 116 + + + + + 678.5999755859375 + + + + 116 + + + + + 678.5999755859375 + + + + 115 + + + + + 678.5999755859375 + + + + 113 + + + + + 678.7999877929688 + + + + 110 + + + + + 678.7999877929688 + + + + 113 + + + + + 678.7999877929688 + + + + 116 + + + + + 678.7999877929688 + + + + 119 + + + + + 678.7999877929688 + + + + 116 + + + + + 678.5999755859375 + + + + 113 + + + + + 678.5999755859375 + + + + 110 + + + + + 678.4000244140625 + + + + 105 + + + + + 678.5999755859375 + + + + 102 + + + + + 678.5999755859375 + + + + 105 + + + + + 678.5999755859375 + + + + 108 + + + + + 678.5999755859375 + + + + 111 + + + + + 678.2000122070312 + + + + 108 + + + + + 678.5999755859375 + + + + 107 + + + + + 678.5999755859375 + + + + 104 + + + + + 678.7999877929688 + + + + 107 + + + + + 678.7999877929688 + + + + 110 + + + + + 678.7999877929688 + + + + 106 + + + + + 678.7999877929688 + + + + 109 + + + + + 678.7999877929688 + + + + 106 + + + + + 678.7999877929688 + + + + 103 + + + + + 679.0 + + + + 102 + + + + + 679.4000244140625 + + + + 104 + + + + + 680.2000122070312 + + + + 105 + + + + + 680.7999877929688 + + + + 106 + + + + + 681.0 + + + + 106 + + + + + 681.4000244140625 + + + + 108 + + + + + 681.7999877929688 + + + + 108 + + + + + 681.7999877929688 + + + + 109 + + + + + 682.2000122070312 + + + + 110 + + + + + 682.7999877929688 + + + + 111 + + + + + 683.2000122070312 + + + + 112 + + + + + 683.4000244140625 + + + + 112 + + + + + 683.7999877929688 + + + + 115 + + + + + 684.0 + + + + 116 + + + + + 684.0 + + + + 119 + + + + + 683.7999877929688 + + + + 121 + + + + + 683.2000122070312 + + + + 122 + + + + + 682.7999877929688 + + + + 123 + + + + + 683.0 + + + + 125 + + + + + 683.5999755859375 + + + + 127 + + + + + 685.0 + + + + 128 + + + + + 685.7999877929688 + + + + 130 + + + + + 686.0 + + + + 133 + + + + + 686.0 + + + + 133 + + + + + 686.4000244140625 + + + + 136 + + + + + 686.4000244140625 + + + + 136 + + + + + 686.5999755859375 + + + + 138 + + + + + 687.0 + + + + 139 + + + + + 687.7999877929688 + + + + 139 + + + + + 688.5999755859375 + + + + 140 + + + + + 689.4000244140625 + + + + 140 + + + + + 690.0 + + + + 140 + + + + + 690.4000244140625 + + + + 140 + + + + + 690.5999755859375 + + + + 140 + + + + + 691.2000122070312 + + + + 141 + + + + + 691.7999877929688 + + + + 140 + + + + + 692.0 + + + + 140 + + + + + 691.7999877929688 + + + + 140 + + + + + 691.7999877929688 + + + + 140 + + + + + 691.5999755859375 + + + + 139 + + + + + 691.4000244140625 + + + + 138 + + + + + 691.2000122070312 + + + + 138 + + + + + 691.0 + + + + 137 + + + + + 690.4000244140625 + + + + 135 + + + + + 690.4000244140625 + + + + 135 + + + + + 690.0 + + + + 133 + + + + + 689.5999755859375 + + + + 132 + + + + + 689.2000122070312 + + + + 131 + + + + + 688.7999877929688 + + + + 131 + + + + + 688.7999877929688 + + + + 131 + + + + + 688.7999877929688 + + + + 131 + + + + + 688.5999755859375 + + + + 131 + + + + + 688.2000122070312 + + + + 130 + + + + + 688.0 + + + + 130 + + + + + 687.7999877929688 + + + + 129 + + + + + 687.5999755859375 + + + + 128 + + + + + 687.4000244140625 + + + + 128 + + + + + 687.2000122070312 + + + + 127 + + + + + 687.0 + + + + 127 + + + + + 686.7999877929688 + + + + 126 + + + + + 686.4000244140625 + + + + 125 + + + + + 685.7999877929688 + + + + 124 + + + + + 685.2000122070312 + + + + 123 + + + + + 684.5999755859375 + + + + 122 + + + + + 684.4000244140625 + + + + 121 + + + + + 683.5999755859375 + + + + 123 + + + + + 683.5999755859375 + + + + 123 + + + + + 683.7999877929688 + + + + 126 + + + + + 683.7999877929688 + + + + 126 + + + + + 684.0 + + + + 127 + + + + + 684.0 + + + + 127 + + + + + 684.0 + + + + 127 + + + + + 683.7999877929688 + + + + 127 + + + + + 683.5999755859375 + + + + 127 + + + + + 682.4000244140625 + + + + 127 + + + + + 681.7999877929688 + + + + 127 + + + + + 681.2000122070312 + + + + 128 + + + + + 680.4000244140625 + + + + 127 + + + + + 679.2000122070312 + + + + 128 + + + + + 678.7999877929688 + + + + 128 + + + + + 676.7999877929688 + + + + 127 + + + + + 676.2000122070312 + + + + 127 + + + + + 675.5999755859375 + + + + 127 + + + + + 673.5999755859375 + + + + 126 + + + + + 672.7999877929688 + + + + 125 + + + + + 670.5999755859375 + + + + 124 + + + + + 669.7999877929688 + + + + 123 + + + + + 667.0 + + + + 122 + + + + + 665.7999877929688 + + + + 122 + + + + + 663.5999755859375 + + + + 122 + + + + + 662.2000122070312 + + + + 122 + + + + + 661.0 + + + + 122 + + + + + 660.5999755859375 + + + + 122 + + + + + 660.4000244140625 + + + + 122 + + + + + 660.0 + + + + 122 + + + + + 659.7999877929688 + + + + 122 + + + + + 659.4000244140625 + + + + 123 + + + + + 658.4000244140625 + + + + 122 + + + + + 657.0 + + + + 120 + + + + + 656.7999877929688 + + + + 119 + + + + + 656.4000244140625 + + + + 119 + + + + + 656.0 + + + + 119 + + + + + 655.5999755859375 + + + + 119 + + + + + 652.5999755859375 + + + + 118 + + + + + 651.4000244140625 + + + + 118 + + + + + 649.4000244140625 + + + + 119 + + + + + 648.5999755859375 + + + + 119 + + + + + 647.2000122070312 + + + + 119 + + + + + 644.4000244140625 + + + + 118 + + + + + 642.4000244140625 + + + + 117 + + + + + 640.4000244140625 + + + + 117 + + + + + 637.2000122070312 + + + + 117 + + + + + 636.4000244140625 + + + + 117 + + + + + 635.2000122070312 + + + + 116 + + + + + 630.7999877929688 + + + + 116 + + + + + 629.4000244140625 + + + + 117 + + + + + 628.4000244140625 + + + + 117 + + + + + 626.5999755859375 + + + + 117 + + + + + 624.7999877929688 + + + + 114 + + + + + 625.0 + + + + 114 + + + + + 625.5999755859375 + + + + 114 + + + + + 624.7999877929688 + + + + 114 + + + + + 623.5999755859375 + + + + 114 + + + + + 622.5999755859375 + + + + 113 + + + + + 622.4000244140625 + + + + 113 + + + + + 620.4000244140625 + + + + 113 + + + + + 617.5999755859375 + + + + 112 + + + + + 616.7999877929688 + + + + 112 + + + + + 616.4000244140625 + + + + 112 + + + + + 614.4000244140625 + + + + 113 + + + + + 611.2000122070312 + + + + 114 + + + + + 608.0 + + + + 115 + + + + + 605.5999755859375 + + + + 116 + + + + + 605.0 + + + + 116 + + + + + 604.4000244140625 + + + + 117 + + + + + 603.2000122070312 + + + + 119 + + + + + 603.0 + + + + 119 + + + + + 603.0 + + + + 120 + + + + + 603.7999877929688 + + + + 121 + + + + + 604.2000122070312 + + + + 122 + + + + + 604.5999755859375 + + + + 123 + + + + + 605.4000244140625 + + + + 122 + + + + + 605.2000122070312 + + + + 121 + + + + + 606.0 + + + + 120 + + + + + 608.2000122070312 + + + + 121 + + + + + 609.4000244140625 + + + + 121 + + + + + 610.2000122070312 + + + + 123 + + + + + 609.4000244140625 + + + + 124 + + + + + 606.5999755859375 + + + + 126 + + + + + 605.5999755859375 + + + + 126 + + + + + 601.7999877929688 + + + + 126 + + + + + 599.0 + + + + 126 + + + + + 598.5999755859375 + + + + 126 + + + + + 598.0 + + + + 126 + + + + + 597.2000122070312 + + + + 125 + + + + + 597.0 + + + + 124 + + + + + 597.2000122070312 + + + + 123 + + + + + 597.0 + + + + 123 + + + + + 596.2000122070312 + + + + 122 + + + + + 596.0 + + + + 122 + + + + + 595.5999755859375 + + + + 122 + + + + + 595.0 + + + + 122 + + + + + 593.4000244140625 + + + + 122 + + + + + 592.7999877929688 + + + + 121 + + + + + 591.5999755859375 + + + + 120 + + + + + 590.4000244140625 + + + + 120 + + + + + 589.0 + + + + 119 + + + + + 588.4000244140625 + + + + 118 + + + + + 587.2000122070312 + + + + 117 + + + + + 585.5999755859375 + + + + 116 + + + + + 583.2000122070312 + + + + 115 + + + + + 581.5999755859375 + + + + 115 + + + + + 578.7999877929688 + + + + 114 + + + + + 574.5999755859375 + + + + 112 + + + + + 573.0 + + + + 112 + + + + + 568.4000244140625 + + + + 111 + + + + + 567.4000244140625 + + + + 111 + + + + + 566.5999755859375 + + + + 110 + + + + + 564.7999877929688 + + + + 110 + + + + + 563.4000244140625 + + + + 110 + + + + + 562.2000122070312 + + + + 110 + + + + + 560.7999877929688 + + + + 109 + + + + + 560.2000122070312 + + + + 109 + + + + + 558.7999877929688 + + + + 109 + + + + + 555.7999877929688 + + + + 110 + + + + + 551.4000244140625 + + + + 109 + + + + + 550.7999877929688 + + + + 109 + + + + + 550.7999877929688 + + + + 109 + + + + + 552.0 + + + + 109 + + + + + 553.2000122070312 + + + + 109 + + + + + 553.0 + + + + 109 + + + + + 551.2000122070312 + + + + 109 + + + + + 550.0 + + + + 109 + + + + + 546.0 + + + + 109 + + + + + 544.7999877929688 + + + + 109 + + + + + 542.7999877929688 + + + + 109 + + + + + 541.7999877929688 + + + + 109 + + + + + 541.5999755859375 + + + + 109 + + + + + 541.4000244140625 + + + + 110 + + + + + 541.5999755859375 + + + + 113 + + + + + 542.0 + + + + 113 + + + + + 542.2000122070312 + + + + 116 + + + + + 541.5999755859375 + + + + 117 + + + + + 541.2000122070312 + + + + 117 + + + + + 539.2000122070312 + + + + 118 + + + + + 537.0 + + + + 117 + + + + + 535.2000122070312 + + + + 117 + + + + + 532.2000122070312 + + + + 116 + + + + + 529.7999877929688 + + + + 116 + + + + + 526.4000244140625 + + + + 114 + + + + + 525.4000244140625 + + + + 114 + + + + + 524.5999755859375 + + + + 113 + + + + + 521.7999877929688 + + + + 112 + + + + + 520.7999877929688 + + + + 112 + + + + + 517.4000244140625 + + + + 111 + + + + + 515.7999877929688 + + + + 110 + + + + + 514.5999755859375 + + + + 111 + + + + + 513.2000122070312 + + + + 111 + + + + + 512.7999877929688 + + + + 111 + + + + + 511.20001220703125 + + + + 110 + + + + + 511.20001220703125 + + + + 109 + + + + + 511.20001220703125 + + + + 108 + + + + + 509.6000061035156 + + + + 108 + + + + + 507.79998779296875 + + + + 108 + + + + + 506.20001220703125 + + + + 108 + + + + + 502.79998779296875 + + + + 109 + + + + + 500.79998779296875 + + + + 110 + + + + + 499.6000061035156 + + + + 111 + + + + + 497.3999938964844 + + + + 112 + + + + + 495.0 + + + + 111 + + + + + 494.79998779296875 + + + + 111 + + + + + 494.6000061035156 + + + + 111 + + + + + 494.3999938964844 + + + + 112 + + + + + 494.6000061035156 + + + + 112 + + + + + 495.0 + + + + 114 + + + + + 494.3999938964844 + + + + 114 + + + + + 494.0 + + + + 114 + + + + + 491.79998779296875 + + + + 114 + + + + + 490.79998779296875 + + + + 114 + + + + + 490.3999938964844 + + + + 114 + + + + + 489.20001220703125 + + + + 113 + + + + + 488.20001220703125 + + + + 114 + + + + + 487.0 + + + + 114 + + + + + 484.79998779296875 + + + + 114 + + + + + 483.0 + + + + 113 + + + + + 482.20001220703125 + + + + 113 + + + + + 480.6000061035156 + + + + 112 + + + + + 477.79998779296875 + + + + 112 + + + + + 474.79998779296875 + + + + 112 + + + + + 475.0 + + + + 113 + + + + + 475.79998779296875 + + + + 114 + + + + + 476.79998779296875 + + + + 116 + + + + + 477.0 + + + + 116 + + + + + 477.0 + + + + 119 + + + + + 476.79998779296875 + + + + 120 + + + + + 476.79998779296875 + + + + 121 + + + + + 476.6000061035156 + + + + 123 + + + + + 476.20001220703125 + + + + 125 + + + + + 476.0 + + + + 128 + + + + + 476.0 + + + + 129 + + + + + 476.0 + + + + 132 + + + + + 476.0 + + + + 134 + + + + + 476.79998779296875 + + + + 136 + + + + + 478.3999938964844 + + + + 138 + + + + + 480.0 + + + + 139 + + + + + 480.3999938964844 + + + + 139 + + + + + 480.20001220703125 + + + + 138 + + + + + 480.20001220703125 + + + + 138 + + + + + 480.0 + + + + 137 + + + + + 480.0 + + + + 136 + + + + + 480.0 + + + + 136 + + + + + 480.6000061035156 + + + + 136 + + + + + 481.3999938964844 + + + + 136 + + + + + 482.20001220703125 + + + + 136 + + + + + 482.20001220703125 + + + + 136 + + + + + 482.3999938964844 + + + + 135 + + + + + 482.0 + + + + 134 + + + + + 481.79998779296875 + + + + 133 + + + + + 481.79998779296875 + + + + 131 + + + + + 482.0 + + + + 130 + + + + + 482.0 + + + + 129 + + + + + 482.0 + + + + 129 + + + + + 482.20001220703125 + + + + 128 + + + + + 482.0 + + + + 127 + + + + + 482.0 + + + + 127 + + + + + 482.0 + + + + 127 + + + + + 482.0 + + + + 126 + + + + + 481.6000061035156 + + + + 127 + + + + + 480.6000061035156 + + + + 125 + + + + + 479.6000061035156 + + + + 123 + + + + + 479.20001220703125 + + + + 123 + + + + + 475.3999938964844 + + + + 122 + + + + + 473.0 + + + + 121 + + + + + 470.20001220703125 + + + + 120 + + + + + 469.20001220703125 + + + + 119 + + + + + 467.20001220703125 + + + + 117 + + + + + 466.6000061035156 + + + + 116 + + + + + 465.20001220703125 + + + + 116 + + + + + 464.20001220703125 + + + + 115 + + + + + 462.0 + + + + 113 + + + + + 460.0 + + + + 112 + + + + + 457.79998779296875 + + + + 112 + + + + + 457.0 + + + + 112 + + + + + 456.79998779296875 + + + + 112 + + + + + 457.20001220703125 + + + + 112 + + + + + 457.3999938964844 + + + + 113 + + + + + 457.6000061035156 + + + + 113 + + + + + 457.6000061035156 + + + + 114 + + + + + 457.3999938964844 + + + + 113 + + + + + 457.20001220703125 + + + + 113 + + + + + 456.79998779296875 + + + + 114 + + + + + 456.6000061035156 + + + + 115 + + + + + 456.3999938964844 + + + + 115 + + + + + 456.20001220703125 + + + + 115 + + + + + 456.0 + + + + 114 + + + + + 456.20001220703125 + + + + 115 + + + + + 456.3999938964844 + + + + 115 + + + + + 457.20001220703125 + + + + 116 + + + + + 458.20001220703125 + + + + 116 + + + + + 458.3999938964844 + + + + 116 + + + + + 458.79998779296875 + + + + 117 + + + + + 459.6000061035156 + + + + 118 + + + + + 460.0 + + + + 118 + + + + + 460.0 + + + + 119 + + + + + 460.3999938964844 + + + + 119 + + + + + 460.3999938964844 + + + + 121 + + + + + 460.3999938964844 + + + + 123 + + + + + 461.20001220703125 + + + + 124 + + + + + 462.3999938964844 + + + + 125 + + + + + 464.6000061035156 + + + + 127 + + + + + 468.20001220703125 + + + + 128 + + + + + 469.3999938964844 + + + + 130 + + + + + 471.0 + + + + 131 + + + + + 471.79998779296875 + + + + 133 + + + + + 472.20001220703125 + + + + 135 + + + + + 473.79998779296875 + + + + 137 + + + + + 475.3999938964844 + + + + 138 + + + + + 476.0 + + + + 139 + + + + + 476.0 + + + + 139 + + + + + 477.0 + + + + 139 + + + + + 478.3999938964844 + + + + 140 + + + + + 478.6000061035156 + + + + 142 + + + + + 478.79998779296875 + + + + 143 + + + + + 478.79998779296875 + + + + 144 + + + + + 479.20001220703125 + + + + 144 + + + + + 479.6000061035156 + + + + 143 + + + + + 479.6000061035156 + + + + 143 + + + + + 480.20001220703125 + + + + 144 + + + + + 480.3999938964844 + + + + 143 + + + + + 480.3999938964844 + + + + 143 + + + + + 480.3999938964844 + + + + 143 + + + + + 480.3999938964844 + + + + 143 + + + + + 480.6000061035156 + + + + 142 + + + + + 481.20001220703125 + + + + 141 + + + + + 481.3999938964844 + + + + 141 + + + + + 481.3999938964844 + + + + 141 + + + + + 481.79998779296875 + + + + 141 + + + + + 481.79998779296875 + + + + 140 + + + + + 482.0 + + + + 140 + + + + + 481.6000061035156 + + + + 139 + + + + + 481.79998779296875 + + + + 139 + + + + + 482.3999938964844 + + + + 139 + + + + + 482.6000061035156 + + + + 140 + + + + + 483.3999938964844 + + + + 139 + + + + + 484.3999938964844 + + + + 139 + + + + + 485.0 + + + + 139 + + + + + 485.0 + + + + 139 + + + + + 485.0 + + + + 139 + + + + + 485.6000061035156 + + + + 139 + + + + + 486.6000061035156 + + + + 139 + + + + + 488.3999938964844 + + + + 139 + + + + + 490.6000061035156 + + + + 139 + + + + + 492.79998779296875 + + + + 139 + + + + + 494.20001220703125 + + + + 139 + + + + + 495.3999938964844 + + + + 138 + + + + + 495.20001220703125 + + + + 138 + + + + + 496.3999938964844 + + + + 138 + + + + + 497.0 + + + + 137 + + + + + 497.6000061035156 + + + + 136 + + + + + 497.79998779296875 + + + + 136 + + + + + 498.0 + + + + 135 + + + + + 498.0 + + + + 134 + + + + + 498.0 + + + + 134 + + + + + 498.0 + + + + 135 + + + + + 497.6000061035156 + + + + 135 + + + + + 497.3999938964844 + + + + 134 + + + + + 497.20001220703125 + + + + 135 + + + + + 496.79998779296875 + + + + 135 + + + + + 496.6000061035156 + + + + 136 + + + + + 496.6000061035156 + + + + 136 + + + + + 496.79998779296875 + + + + 136 + + + + + 497.3999938964844 + + + + 135 + + + + + 498.0 + + + + 135 + + + + + 498.79998779296875 + + + + 135 + + + + + 499.79998779296875 + + + + 136 + + + + + 500.6000061035156 + + + + 137 + + + + + 501.0 + + + + 137 + + + + + 501.0 + + + + 137 + + + + + 501.0 + + + + 137 + + + + + 501.3999938964844 + + + + 138 + + + + + 501.79998779296875 + + + + 138 + + + + + 502.3999938964844 + + + + 138 + + + + + 500.6000061035156 + + + + 137 + + + + + 499.0 + + + + 134 + + + + + 497.6000061035156 + + + + 133 + + + + + 496.0 + + + + 130 + + + + + 495.6000061035156 + + + + 129 + + + + + 494.0 + + + + 128 + + + + + 493.3999938964844 + + + + 127 + + + + + 491.20001220703125 + + + + 125 + + + + + 490.3999938964844 + + + + 124 + + + + + 487.3999938964844 + + + + 121 + + + + + 486.79998779296875 + + + + 121 + + + + + 486.0 + + + + 120 + + + + + 484.20001220703125 + + + + 119 + + + + + 483.6000061035156 + + + + 119 + + + + + 483.20001220703125 + + + + 118 + + + + + 482.79998779296875 + + + + 117 + + + + + 483.0 + + + + 117 + + + + + 482.6000061035156 + + + + 116 + + + + + 482.20001220703125 + + + + 115 + + + + + 482.20001220703125 + + + + 115 + + + + + 481.6000061035156 + + + + 114 + + + + + 480.3999938964844 + + + + 114 + + + + + 479.20001220703125 + + + + 114 + + + + + 477.79998779296875 + + + + 113 + + + + + 477.3999938964844 + + + + 113 + + + + + 476.6000061035156 + + + + 113 + + + + + 474.20001220703125 + + + + 114 + + + + + 470.20001220703125 + + + + 114 + + + + + 467.20001220703125 + + + + 114 + + + + + 463.79998779296875 + + + + 114 + + + + + 461.79998779296875 + + + + 114 + + + + + 460.20001220703125 + + + + 115 + + + + + 460.0 + + + + 115 + + + + + 460.3999938964844 + + + + 115 + + + + + 460.79998779296875 + + + + 115 + + + + + 461.3999938964844 + + + + 115 + + + + + 462.0 + + + + 117 + + + + + 462.0 + + + + 118 + + + + + 462.79998779296875 + + + + 121 + + + + + 463.3999938964844 + + + + 122 + + + + + 464.79998779296875 + + + + 122 + + + + + 465.6000061035156 + + + + 123 + + + + + 466.6000061035156 + + + + 125 + + + + + 468.0 + + + + 126 + + + + + 469.0 + + + + 128 + + + + + 470.20001220703125 + + + + 129 + + + + + 470.6000061035156 + + + + 130 + + + + + 471.0 + + + + 131 + + + + + 471.3999938964844 + + + + 132 + + + + + 471.79998779296875 + + + + 132 + + + + + 471.79998779296875 + + + + 134 + + + + + 472.3999938964844 + + + + 134 + + + + + 471.3999938964844 + + + + 135 + + + + + 470.20001220703125 + + + + 136 + + + + + 470.20001220703125 + + + + 136 + + + + + 470.79998779296875 + + + + 137 + + + + + 472.0 + + + + 138 + + + + + 473.6000061035156 + + + + 139 + + + + + 475.3999938964844 + + + + 140 + + + + + 478.0 + + + + 141 + + + + + 480.6000061035156 + + + + 142 + + + + + 483.0 + + + + 142 + + + + + 483.79998779296875 + + + + 142 + + + + + 484.79998779296875 + + + + 142 + + + + + 485.20001220703125 + + + + 141 + + + + + 487.0 + + + + 142 + + + + + 486.0 + + + + 141 + + + + + 486.0 + + + + 141 + + + + + 485.3999938964844 + + + + 142 + + + + + 485.6000061035156 + + + + 141 + + + + + 485.6000061035156 + + + + 141 + + + + + 486.3999938964844 + + + + 141 + + + + + 487.79998779296875 + + + + 140 + + + + + 489.6000061035156 + + + + 139 + + + + + 490.0 + + + + 140 + + + + + 490.3999938964844 + + + + 140 + + + + + 490.79998779296875 + + + + 139 + + + + + 490.20001220703125 + + + + 139 + + + + + 489.79998779296875 + + + + 139 + + + + + 490.6000061035156 + + + + 138 + + + + + 491.6000061035156 + + + + 138 + + + + + 492.79998779296875 + + + + 137 + + + + + 494.3999938964844 + + + + 136 + + + + + 496.0 + + + + 137 + + + + + 497.20001220703125 + + + + 136 + + + + + 498.3999938964844 + + + + 135 + + + + + 499.0 + + + + 135 + + + + + 499.79998779296875 + + + + 134 + + + + + 499.6000061035156 + + + + 134 + + + + + 499.6000061035156 + + + + 133 + + + + + 499.20001220703125 + + + + 134 + + + + + 499.0 + + + + 133 + + + + + 498.0 + + + + 133 + + + + + 497.3999938964844 + + + + 133 + + + + + 497.20001220703125 + + + + 133 + + + + + 497.0 + + + + 132 + + + + + 497.20001220703125 + + + + 131 + + + + + 497.20001220703125 + + + + 130 + + + + + 497.3999938964844 + + + + 130 + + + + + 498.0 + + + + 128 + + + + + 498.20001220703125 + + + + 125 + + + + + 497.79998779296875 + + + + 123 + + + + + 497.20001220703125 + + + + 123 + + + + + 494.3999938964844 + + + + 122 + + + + + 492.6000061035156 + + + + 121 + + + + + 484.79998779296875 + + + + 120 + + + + + 481.6000061035156 + + + + 119 + + + + + 477.79998779296875 + + + + 119 + + + + + 477.6000061035156 + + + + 119 + + + + + 477.20001220703125 + + + + 119 + + + + + 476.3999938964844 + + + + 121 + + + + + 476.3999938964844 + + + + 121 + + + + + 476.20001220703125 + + + + 123 + + + + + 475.3999938964844 + + + + 125 + + + + + 475.3999938964844 + + + + 126 + + + + + 475.20001220703125 + + + + 126 + + + + + 475.0 + + + + 127 + + + + + 474.6000061035156 + + + + 129 + + + + + 474.6000061035156 + + + + 130 + + + + + 474.20001220703125 + + + + 131 + + + + + 474.6000061035156 + + + + 133 + + + + + 475.6000061035156 + + + + 136 + + + + + 476.79998779296875 + + + + 139 + + + + + 477.3999938964844 + + + + 139 + + + + + 477.79998779296875 + + + + 140 + + + + + 478.3999938964844 + + + + 140 + + + + + 479.20001220703125 + + + + 140 + + + + + 479.3999938964844 + + + + 140 + + + + + 480.0 + + + + 141 + + + + + 480.0 + + + + 140 + + + + + 480.6000061035156 + + + + 141 + + + + + 481.6000061035156 + + + + 141 + + + + + 482.0 + + + + 140 + + + + + 482.3999938964844 + + + + 140 + + + + + 482.3999938964844 + + + + 140 + + + + + 483.0 + + + + 141 + + + + + 484.3999938964844 + + + + 140 + + + + + 485.20001220703125 + + + + 141 + + + + + 485.79998779296875 + + + + 141 + + + + + 486.0 + + + + 141 + + + + + 486.20001220703125 + + + + 140 + + + + + 486.6000061035156 + + + + 141 + + + + + 486.79998779296875 + + + + 141 + + + + + 487.0 + + + + 141 + + + + + 487.6000061035156 + + + + 141 + + + + + 488.0 + + + + 141 + + + + + 488.0 + + + + 141 + + + + + 488.3999938964844 + + + + 141 + + + + + 489.0 + + + + 142 + + + + + 489.20001220703125 + + + + 142 + + + + + 489.6000061035156 + + + + 142 + + + + + 490.0 + + + + 140 + + + + + 490.6000061035156 + + + + 139 + + + + + 491.3999938964844 + + + + 137 + + + + + 492.3999938964844 + + + + 134 + + + + + 493.3999938964844 + + + + 133 + + + + + 493.6000061035156 + + + + 130 + + + + + 493.3999938964844 + + + + 130 + + + + + 492.6000061035156 + + + + 127 + + + + + 491.6000061035156 + + + + 124 + + + + + 490.6000061035156 + + + + 124 + + + + + 488.79998779296875 + + + + 122 + + + + + 487.3999938964844 + + + + 120 + + + + + 485.6000061035156 + + + + 118 + + + + + 485.20001220703125 + + + + 118 + + + + + 484.20001220703125 + + + + 116 + + + + + 483.0 + + + + 116 + + + + + 481.0 + + + + 115 + + + + + 480.6000061035156 + + + + 115 + + + + + 480.3999938964844 + + + + 114 + + + + + 479.79998779296875 + + + + 113 + + + + + 479.3999938964844 + + + + 114 + + + + + 479.20001220703125 + + + + 114 + + + + + 477.20001220703125 + + + + 114 + + + + + 476.6000061035156 + + + + 114 + + + + + 476.0 + + + + 115 + + + + + 475.79998779296875 + + + + 115 + + + + + 476.20001220703125 + + + + 114 + + + + + 476.79998779296875 + + + + 115 + + + + + 476.79998779296875 + + + + 115 + + + + + 477.20001220703125 + + + + 116 + + + + + 477.79998779296875 + + + + 118 + + + + + 479.0 + + + + 117 + + + + + 479.3999938964844 + + + + 117 + + + + + 480.6000061035156 + + + + 119 + + + + + 480.79998779296875 + + + + 118 + + + + + 480.6000061035156 + + + + 121 + + + + + 480.6000061035156 + + + + 121 + + + + + 481.3999938964844 + + + + 122 + + + + + 482.79998779296875 + + + + 123 + + + + + 484.0 + + + + 124 + + + + + 484.6000061035156 + + + + 123 + + + + + 485.20001220703125 + + + + 125 + + + + + 485.79998779296875 + + + + 125 + + + + + 486.0 + + + + 126 + + + + + 486.20001220703125 + + + + 127 + + + + + 486.0 + + + + 129 + + + + + 486.0 + + + + 129 + + + + + 485.79998779296875 + + + + 130 + + + + + 486.0 + + + + 130 + + + + + 485.6000061035156 + + + + 132 + + + + + 485.3999938964844 + + + + 132 + + + + + 485.20001220703125 + + + + 133 + + + + + 484.79998779296875 + + + + 133 + + + + + 484.20001220703125 + + + + 134 + + + + + 483.6000061035156 + + + + 135 + + + + + 483.0 + + + + 135 + + + + + 482.0 + + + + 134 + + + + + 481.6000061035156 + + + + 131 + + + + + 482.0 + + + + 128 + + + + + 482.20001220703125 + + + + 128 + + + + + 481.20001220703125 + + + + 124 + + + + + 480.79998779296875 + + + + 122 + + + + + 480.20001220703125 + + + + 119 + + + + + 479.20001220703125 + + + + 120 + + + + + 478.20001220703125 + + + + 119 + + + + + 477.20001220703125 + + + + 119 + + + + + 476.79998779296875 + + + + 119 + + + + + 475.0 + + + + 119 + + + + + 474.3999938964844 + + + + 119 + + + + + 472.20001220703125 + + + + 118 + + + + + 471.6000061035156 + + + + 118 + + + + + 471.0 + + + + 117 + + + + + 468.79998779296875 + + + + 114 + + + + + 467.6000061035156 + + + + 114 + + + + + 466.6000061035156 + + + + 114 + + + + + 466.3999938964844 + + + + 114 + + + + + 466.6000061035156 + + + + 115 + + + + + 463.6000061035156 + + + + 115 + + + + + 463.6000061035156 + + + + 115 + + + + + 462.3999938964844 + + + + 118 + + + + + 462.20001220703125 + + + + 120 + + + + + 462.20001220703125 + + + + 120 + + + + + 462.79998779296875 + + + + 121 + + + + + 463.20001220703125 + + + + 121 + + + + + 464.0 + + + + 121 + + + + + 464.3999938964844 + + + + 121 + + + + + 465.20001220703125 + + + + 118 + + + + + 465.0 + + + + 117 + + + + + 465.0 + + + + 116 + + + + + 465.3999938964844 + + + + 115 + + + + + 465.3999938964844 + + + + 115 + + + + + 464.0 + + + + 116 + + + + + 463.3999938964844 + + + + 117 + + + + + 462.79998779296875 + + + + 118 + + + + + 462.79998779296875 + + + + 119 + + + + + 463.20001220703125 + + + + 120 + + + + + 463.0 + + + + 121 + + + + + 463.0 + + + + 121 + + + + + 462.6000061035156 + + + + 121 + + + + + 463.20001220703125 + + + + 122 + + + + + 464.20001220703125 + + + + 123 + + + + + 464.79998779296875 + + + + 124 + + + + + 465.20001220703125 + + + + 126 + + + + + 465.3999938964844 + + + + 127 + + + + + 465.79998779296875 + + + + 130 + + + + + 466.0 + + + + 131 + + + + + 466.20001220703125 + + + + 132 + + + + + 466.3999938964844 + + + + 133 + + + + + 466.3999938964844 + + + + 134 + + + + + 467.6000061035156 + + + + 135 + + + + + 467.6000061035156 + + + + 135 + + + + + 468.20001220703125 + + + + 135 + + + + + 468.6000061035156 + + + + 135 + + + + + 468.6000061035156 + + + + 134 + + + + + 468.79998779296875 + + + + 134 + + + + + 469.0 + + + + 133 + + + + + 469.0 + + + + 132 + + + + + 471.0 + + + + 130 + + + + + 472.79998779296875 + + + + 128 + + + + + 473.0 + + + + 128 + + + + + 473.79998779296875 + + + + 127 + + + + + 474.0 + + + + 127 + + + + + 475.20001220703125 + + + + 127 + + + + + 476.3999938964844 + + + + 127 + + + + + 476.6000061035156 + + + + 127 + + + + + 477.20001220703125 + + + + 127 + + + + + 477.79998779296875 + + + + 126 + + + + + 478.0 + + + + 125 + + + + + 478.20001220703125 + + + + 125 + + + + + 476.79998779296875 + + + + 123 + + + + + 472.20001220703125 + + + + 120 + + + + + 471.20001220703125 + + + + 120 + + + + + 467.3999938964844 + + + + 119 + + + + + 465.3999938964844 + + + + 118 + + + + + 462.3999938964844 + + + + 118 + + + + + 459.79998779296875 + + + + 117 + + + + + 459.6000061035156 + + + + 118 + + + + + 458.6000061035156 + + + + 118 + + + + + 458.20001220703125 + + + + 118 + + + + + 458.20001220703125 + + + + 118 + + + + + 458.0 + + + + 117 + + + + + 458.0 + + + + 117 + + + + + 458.0 + + + + 116 + + + + + 457.79998779296875 + + + + 115 + + + + + 457.6000061035156 + + + + 115 + + + + + 459.20001220703125 + + + + 115 + + + + + 460.79998779296875 + + + + 117 + + + + + 461.20001220703125 + + + + 118 + + + + + 461.20001220703125 + + + + 119 + + + + + 461.0 + + + + 120 + + + + + 461.20001220703125 + + + + 122 + + + + + 462.6000061035156 + + + + 123 + + + + + 465.3999938964844 + + + + 125 + + + + + 466.20001220703125 + + + + 125 + + + + + 467.6000061035156 + + + + 126 + + + + + 468.79998779296875 + + + + 127 + + + + + 469.0 + + + + 127 + + + + + 469.0 + + + + 127 + + + + + 468.6000061035156 + + + + 128 + + + + + 468.6000061035156 + + + + 128 + + + + + 468.3999938964844 + + + + 129 + + + + + 468.0 + + + + 130 + + + + + 467.20001220703125 + + + + 131 + + + + + 467.20001220703125 + + + + 132 + + + + + 467.0 + + + + 132 + + + + + 467.0 + + + + 132 + + + + + 466.79998779296875 + + + + 134 + + + + + 466.79998779296875 + + + + 134 + + + + + 466.6000061035156 + + + + 134 + + + + + 466.20001220703125 + + + + 134 + + + + + 466.0 + + + + 134 + + + + + 465.6000061035156 + + + + 134 + + + + + 465.20001220703125 + + + + 133 + + + + + 464.6000061035156 + + + + 132 + + + + + 464.20001220703125 + + + + 132 + + + + + 464.3999938964844 + + + + 132 + + + + + 465.20001220703125 + + + + 132 + + + + + 465.3999938964844 + + + + 132 + + + + + 466.0 + + + + 131 + + + + + 466.6000061035156 + + + + 132 + + + + + 468.20001220703125 + + + + 132 + + + + + 471.0 + + + + 133 + + + + + 473.20001220703125 + + + + 133 + + + + + 473.6000061035156 + + + + 133 + + + + + 475.0 + + + + 134 + + + + + 477.79998779296875 + + + + 135 + + + + + 480.20001220703125 + + + + 134 + + + + + 480.79998779296875 + + + + 134 + + + + + 481.0 + + + + 135 + + + + + 481.3999938964844 + + + + 135 + + + + + 481.79998779296875 + + + + 136 + + + + + 482.0 + + + + 136 + + + + + 482.3999938964844 + + + + 136 + + + + + 482.3999938964844 + + + + 137 + + + + + 482.20001220703125 + + + + 137 + + + + + 482.20001220703125 + + + + 137 + + + + + 482.79998779296875 + + + + 138 + + + + + 483.20001220703125 + + + + 138 + + + + + 483.79998779296875 + + + + 138 + + + + + 483.79998779296875 + + + + 138 + + + + + 484.6000061035156 + + + + 139 + + + + + 485.3999938964844 + + + + 139 + + + + + 485.79998779296875 + + + + 140 + + + + + 486.6000061035156 + + + + 141 + + + + + 487.20001220703125 + + + + 141 + + + + + 487.3999938964844 + + + + 141 + + + + + 487.79998779296875 + + + + 142 + + + + + 488.20001220703125 + + + + 143 + + + + + 489.0 + + + + 143 + + + + + 489.79998779296875 + + + + 142 + + + + + 490.0 + + + + 142 + + + + + 490.3999938964844 + + + + 142 + + + + + 490.79998779296875 + + + + 142 + + + + + 491.3999938964844 + + + + 141 + + + + + 491.3999938964844 + + + + 141 + + + + + 492.20001220703125 + + + + 140 + + + + + 492.3999938964844 + + + + 139 + + + + + 492.0 + + + + 138 + + + + + 491.6000061035156 + + + + 136 + + + + + 491.0 + + + + 136 + + + + + 490.6000061035156 + + + + 135 + + + + + 490.3999938964844 + + + + 135 + + + + + 490.0 + + + + 136 + + + + + 489.79998779296875 + + + + 136 + + + + + 489.6000061035156 + + + + 136 + + + + + 489.79998779296875 + + + + 136 + + + + + 490.6000061035156 + + + + 136 + + + + + 490.79998779296875 + + + + 136 + + + + + 491.6000061035156 + + + + 136 + + + + + 492.6000061035156 + + + + 136 + + + + + 494.0 + + + + 136 + + + + + 494.3999938964844 + + + + 136 + + + + + 494.3999938964844 + + + + 136 + + + + + 494.20001220703125 + + + + 136 + + + + + 494.20001220703125 + + + + 136 + + + + + 494.79998779296875 + + + + 135 + + + + + 495.6000061035156 + + + + 136 + + + + + 496.79998779296875 + + + + 136 + + + + + 497.3999938964844 + + + + 136 + + + + + 498.0 + + + + 137 + + + + + 499.0 + + + + 136 + + + + + 500.0 + + + + 137 + + + + + 500.3999938964844 + + + + 138 + + + + + 501.0 + + + + 138 + + + + + 501.3999938964844 + + + + 139 + + + + + 502.20001220703125 + + + + 138 + + + + + 503.20001220703125 + + + + 136 + + + + + 503.79998779296875 + + + + 136 + + + + + 504.3999938964844 + + + + 137 + + + + + 505.0 + + + + 136 + + + + + 505.79998779296875 + + + + 135 + + + + + 505.79998779296875 + + + + 135 + + + + + 506.20001220703125 + + + + 134 + + + + + 506.79998779296875 + + + + 134 + + + + + 507.20001220703125 + + + + 134 + + + + + 508.0 + + + + 134 + + + + + 508.3999938964844 + + + + 133 + + + + + 508.6000061035156 + + + + 133 + + + + + 509.20001220703125 + + + + 133 + + + + + 509.3999938964844 + + + + 133 + + + + + 509.79998779296875 + + + + 133 + + + + + 510.0 + + + + 133 + + + + + 510.0 + + + + 132 + + + + + 510.0 + + + + 132 + + + + + 509.79998779296875 + + + + 132 + + + + + 509.6000061035156 + + + + 132 + + + + + 509.20001220703125 + + + + 131 + + + + + 509.20001220703125 + + + + 130 + + + + + 509.20001220703125 + + + + 130 + + + + + 509.20001220703125 + + + + 130 + + + + + 508.79998779296875 + + + + 130 + + + + + 508.6000061035156 + + + + 131 + + + + + 508.79998779296875 + + + + 131 + + + + + 509.0 + + + + 130 + + + + + 509.20001220703125 + + + + 130 + + + + + 509.3999938964844 + + + + 130 + + + + + 509.3999938964844 + + + + 129 + + + + + 509.3999938964844 + + + + 129 + + + + + 509.3999938964844 + + + + 127 + + + + + 509.6000061035156 + + + + 127 + + + + + 509.6000061035156 + + + + 127 + + + + + 509.20001220703125 + + + + 124 + + + + + 508.20001220703125 + + + + 122 + + + + + 507.6000061035156 + + + + 122 + + + + + 506.0 + + + + 119 + + + + + 504.79998779296875 + + + + 118 + + + + + 504.20001220703125 + + + + 118 + + + + + 504.0 + + + + 117 + + + + + 503.79998779296875 + + + + 118 + + + + + 503.20001220703125 + + + + 119 + + + + + 503.20001220703125 + + + + 118 + + + + + 502.79998779296875 + + + + 117 + + + + + 503.0 + + + + 118 + + + + + 503.20001220703125 + + + + 117 + + + + + 503.0 + + + + 117 + + + + + 503.0 + + + + 116 + + + + + 502.79998779296875 + + + + 118 + + + + + 502.6000061035156 + + + + 118 + + + + + 502.6000061035156 + + + + 120 + + + + + 502.6000061035156 + + + + 120 + + + + + 502.79998779296875 + + + + 119 + + + + + 503.3999938964844 + + + + 120 + + + + + 503.6000061035156 + + + + 119 + + + + + 503.20001220703125 + + + + 118 + + + + + 503.0 + + + + 118 + + + + + 502.3999938964844 + + + + 117 + + + + + 500.6000061035156 + + + + 117 + + + + + 499.0 + + + + 116 + + + + + 497.6000061035156 + + + + 115 + + + + + 495.3999938964844 + + + + 115 + + + + + 494.0 + + + + 114 + + + + + 493.6000061035156 + + + + 115 + + + + + 494.0 + + + + 116 + + + + + 495.0 + + + + 116 + + + + + 496.3999938964844 + + + + 118 + + + + + 496.3999938964844 + + + + 119 + + + + + 496.79998779296875 + + + + 119 + + + + + 497.3999938964844 + + + + 122 + + + + + 497.20001220703125 + + + + 122 + + + + + 497.3999938964844 + + + + 122 + + + + + 497.6000061035156 + + + + 123 + + + + + 497.6000061035156 + + + + 124 + + + + + 497.79998779296875 + + + + 125 + + + + + 498.20001220703125 + + + + 126 + + + + + 498.6000061035156 + + + + 127 + + + + + 498.20001220703125 + + + + 128 + + + + + 498.20001220703125 + + + + 128 + + + + + 498.20001220703125 + + + + 129 + + + + + 498.3999938964844 + + + + 129 + + + + + 499.20001220703125 + + + + 128 + + + + + 499.0 + + + + 129 + + + + + 499.20001220703125 + + + + 130 + + + + + 499.20001220703125 + + + + 130 + + + + + 499.3999938964844 + + + + 130 + + + + + 499.20001220703125 + + + + 129 + + + + + 499.3999938964844 + + + + 128 + + + + + 498.79998779296875 + + + + 127 + + + + + 497.6000061035156 + + + + 127 + + + + + 497.3999938964844 + + + + 128 + + + + + 497.3999938964844 + + + + 129 + + + + + 497.6000061035156 + + + + 131 + + + + + 498.0 + + + + 132 + + + + + 498.0 + + + + 132 + + + + + 498.20001220703125 + + + + 133 + + + + + 498.6000061035156 + + + + 134 + + + + + 499.6000061035156 + + + + 135 + + + + + 499.79998779296875 + + + + 135 + + + + + 500.0 + + + + 134 + + + + + 499.79998779296875 + + + + 134 + + + + + 499.0 + + + + 133 + + + + + 498.6000061035156 + + + + 132 + + + + + 497.79998779296875 + + + + 132 + + + + + 497.3999938964844 + + + + 131 + + + + + 496.79998779296875 + + + + 130 + + + + + 496.20001220703125 + + + + 129 + + + + + 496.3999938964844 + + + + 129 + + + + + 497.6000061035156 + + + + 129 + + + + + 499.0 + + + + 128 + + + + + 499.20001220703125 + + + + 127 + + + + + 499.6000061035156 + + + + 127 + + + + + 500.0 + + + + 126 + + + + + 500.20001220703125 + + + + 126 + + + + + 500.3999938964844 + + + + 126 + + + + + 501.0 + + + + 125 + + + + + 501.3999938964844 + + + + 125 + + + + + 501.0 + + + + 125 + + + + + 501.0 + + + + 125 + + + + + 501.0 + + + + 126 + + + + + 502.20001220703125 + + + + 127 + + + + + 503.79998779296875 + + + + 127 + + + + + 503.20001220703125 + + + + 127 + + + + + 501.79998779296875 + + + + 126 + + + + + 500.6000061035156 + + + + 124 + + + + + 500.3999938964844 + + + + 124 + + + + + 500.0 + + + + 123 + + + + + 499.6000061035156 + + + + 123 + + + + + 498.6000061035156 + + + + 123 + + + + + 495.79998779296875 + + + + 122 + + + + + 492.0 + + + + 121 + + + + + 492.0 + + + + 121 + + + + + 493.0 + + + + 121 + + + + + 493.3999938964844 + + + + 121 + + + + + 493.20001220703125 + + + + 122 + + + + + 491.79998779296875 + + + + 122 + + + + + 489.6000061035156 + + + + 121 + + + + + 489.3999938964844 + + + + 121 + + + + + 489.0 + + + + 123 + + + + + 488.20001220703125 + + + + 125 + + + + + 487.6000061035156 + + + + 125 + + + + + 486.6000061035156 + + + + 125 + + + + + 486.6000061035156 + + + + 126 + + + + + 488.0 + + + + 126 + + + + + 489.0 + + + + 127 + + + + + 493.6000061035156 + + + + 128 + + + + + 495.6000061035156 + + + + 129 + + + + + 496.3999938964844 + + + + 130 + + + + + 500.3999938964844 + + + + 132 + + + + + 501.0 + + + + 133 + + + + + 503.20001220703125 + + + + 136 + + + + + 504.3999938964844 + + + + 138 + + + + + 505.20001220703125 + + + + 140 + + + + + 506.0 + + + + 142 + + + + + 505.79998779296875 + + + + 144 + + + + + 506.79998779296875 + + + + 145 + + + + + 506.79998779296875 + + + + 146 + + + + + 507.20001220703125 + + + + 147 + + + + + 508.20001220703125 + + + + 148 + + + + + 508.20001220703125 + + + + 148 + + + + + 508.0 + + + + 149 + + + + + 508.20001220703125 + + + + 149 + + + + + 509.0 + + + + 150 + + + + + 508.79998779296875 + + + + 150 + + + + + 509.0 + + + + 150 + + + + + 508.79998779296875 + + + + 150 + + + + + 508.79998779296875 + + + + 151 + + + + + 508.6000061035156 + + + + 151 + + + + + 509.3999938964844 + + + + 150 + + + + + 509.6000061035156 + + + + 150 + + + + + 509.6000061035156 + + + + 150 + + + + + 509.79998779296875 + + + + 149 + + + + + 510.0 + + + + 149 + + + + + 510.20001220703125 + + + + 149 + + + + + 510.20001220703125 + + + + 149 + + + + + 510.20001220703125 + + + + 148 + + + + + 510.20001220703125 + + + + 148 + + + + + 510.0 + + + + 149 + + + + + 510.20001220703125 + + + + 149 + + + + + 510.6000061035156 + + + + 149 + + + + + 510.6000061035156 + + + + 149 + + + + + 511.0 + + + + 150 + + + + + 507.79998779296875 + + + + 150 + + + + + 508.0 + + + + 150 + + + + + 507.6000061035156 + + + + 151 + + + + + 507.79998779296875 + + + + 150 + + + + + 508.0 + + + + 150 + + + + + 508.0 + + + + 150 + + + + + 508.20001220703125 + + + + 150 + + + + + 508.0 + + + + 150 + + + + + 508.6000061035156 + + + + 150 + + + + + 508.79998779296875 + + + + 150 + + + + + 509.0 + + + + 149 + + + + + 509.20001220703125 + + + + 149 + + + + + 510.0 + + + + 148 + + + + + 510.20001220703125 + + + + 148 + + + + + 510.6000061035156 + + + + 147 + + + + + 512.2000122070312 + + + + 147 + + + + + 513.7999877929688 + + + + 145 + + + + + 515.4000244140625 + + + + 145 + + + + + 516.0 + + + + 144 + + + + + 516.5999755859375 + + + + 144 + + + + + 516.7999877929688 + + + + 144 + + + + + 517.2000122070312 + + + + 144 + + + + + 517.2000122070312 + + + + 144 + + + + + 517.4000244140625 + + + + 145 + + + + + 517.5999755859375 + + + + 145 + + + + + 518.0 + + + + 145 + + + + + 518.0 + + + + 145 + + + + + 518.0 + + + + 146 + + + + + 518.2000122070312 + + + + 147 + + + + + 518.4000244140625 + + + + 147 + + + + + 518.5999755859375 + + + + 147 + + + + + 518.7999877929688 + + + + 147 + + + + + 519.7999877929688 + + + + 146 + + + + + 520.4000244140625 + + + + 145 + + + + + 521.5999755859375 + + + + 145 + + + + + 522.5999755859375 + + + + 142 + + + + + 523.4000244140625 + + + + 139 + + + + + 523.4000244140625 + + + + 138 + + + + + 523.7999877929688 + + + + 138 + + + + + 523.7999877929688 + + + + 137 + + + + + 523.5999755859375 + + + + 136 + + + + + 523.4000244140625 + + + + 134 + + + + + 523.0 + + + + 133 + + + + + 522.7999877929688 + + + + 133 + + + + + 522.7999877929688 + + + + 133 + + + + + 523.0 + + + + 133 + + + + + 523.0 + + + + 132 + + + + + 523.0 + + + + 132 + + + + + 523.0 + + + + 131 + + + + + 523.0 + + + + 130 + + + + + 523.2000122070312 + + + + 129 + + + + + 523.4000244140625 + + + + 129 + + + + + 523.5999755859375 + + + + 130 + + + + + 523.4000244140625 + + + + 129 + + + + + 523.0 + + + + 128 + + + + + 522.4000244140625 + + + + 127 + + + + + 522.0 + + + + 126 + + + + + 521.5999755859375 + + + + 126 + + + + + 521.0 + + + + 126 + + + + + 520.5999755859375 + + + + 126 + + + + + 520.0 + + + + 126 + + + + + 519.2000122070312 + + + + 126 + + + + + 518.7999877929688 + + + + 126 + + + + + 517.5999755859375 + + + + 125 + + + + + 516.5999755859375 + + + + 124 + + + + + 516.4000244140625 + + + + 123 + + + + + 516.2000122070312 + + + + 124 + + + + + 515.2000122070312 + + + + 124 + + + + + 514.5999755859375 + + + + 125 + + + + + 514.0 + + + + 124 + + + + + 513.4000244140625 + + + + 124 + + + + + 512.0 + + + + 123 + + + + + 511.3999938964844 + + + + 123 + + + + + 510.20001220703125 + + + + 122 + + + + + 509.3999938964844 + + + + 121 + + + + + 508.20001220703125 + + + + 120 + + + + + 505.3999938964844 + + + + 119 + + + + + 504.0 + + + + 118 + + + + + 503.20001220703125 + + + + 118 + + + + + 502.20001220703125 + + + + 119 + + + + + 501.20001220703125 + + + + 120 + + + + + 500.3999938964844 + + + + 119 + + + + + 500.0 + + + + 117 + + + + + 498.20001220703125 + + + + 116 + + + + + 498.20001220703125 + + + + 115 + + + + + 497.3999938964844 + + + + 115 + + + + + 496.79998779296875 + + + + 114 + + + + + 496.20001220703125 + + + + 114 + + + + + 496.20001220703125 + + + + 113 + + + + + 496.0 + + + + 113 + + + + + 494.79998779296875 + + + + 114 + + + + + 494.20001220703125 + + + + 114 + + + + + 492.6000061035156 + + + + 115 + + + + + 492.0 + + + + 115 + + + + + 491.3999938964844 + + + + 115 + + + + + 492.0 + + + + 117 + + + + + 492.6000061035156 + + + + 120 + + + + + 492.79998779296875 + + + + 120 + + + + + 493.20001220703125 + + + + 121 + + + + + 493.6000061035156 + + + + 121 + + + + + 493.79998779296875 + + + + 121 + + + + + 494.3999938964844 + + + + 120 + + + + + 494.20001220703125 + + + + 120 + + + + + 493.3999938964844 + + + + 120 + + + + + 493.3999938964844 + + + + 120 + + + + + 493.3999938964844 + + + + 118 + + + + + 492.3999938964844 + + + + 117 + + + + + 490.3999938964844 + + + + 115 + + + + + 487.79998779296875 + + + + 114 + + + + + 486.0 + + + + 113 + + + + + 485.0 + + + + 113 + + + + + 484.3999938964844 + + + + 112 + + + + + 483.0 + + + + 113 + + + + + 479.79998779296875 + + + + 113 + + + + + 477.6000061035156 + + + + 112 + + + + + 474.20001220703125 + + + + 113 + + + + + 473.0 + + + + 112 + + + + + 472.79998779296875 + + + + 113 + + + + + 472.3999938964844 + + + + 114 + + + + + 472.0 + + + + 113 + + + + + 471.20001220703125 + + + + 113 + + + + + 470.6000061035156 + + + + 113 + + + + + 470.3999938964844 + + + + 113 + + + + + 470.6000061035156 + + + + 113 + + + + + 470.6000061035156 + + + + 112 + + + + + 470.20001220703125 + + + + 113 + + + + + 469.20001220703125 + + + + 113 + + + + + 467.6000061035156 + + + + 112 + + + + + 465.79998779296875 + + + + 113 + + + + + 463.79998779296875 + + + + 115 + + + + + 463.0 + + + + 115 + + + + + 462.79998779296875 + + + + 116 + + + + + 463.0 + + + + 117 + + + + + 463.20001220703125 + + + + 118 + + + + + 463.3999938964844 + + + + 118 + + + + + 463.3999938964844 + + + + 119 + + + + + 463.79998779296875 + + + + 119 + + + + + 464.3999938964844 + + + + 121 + + + + + 465.0 + + + + 123 + + + + + 465.3999938964844 + + + + 123 + + + + + 465.20001220703125 + + + + 124 + + + + + 464.79998779296875 + + + + 124 + + + + + 464.6000061035156 + + + + 125 + + + + + 464.3999938964844 + + + + 126 + + + + + 464.20001220703125 + + + + 125 + + + + + 464.0 + + + + 124 + + + + + 464.0 + + + + 121 + + + + + 464.0 + + + + 121 + + + + + 464.20001220703125 + + + + 118 + + + + + 464.20001220703125 + + + + 117 + + + + + 464.3999938964844 + + + + 118 + + + + + 464.3999938964844 + + + + 118 + + + + + 464.6000061035156 + + + + 118 + + + + + 464.79998779296875 + + + + 119 + + + + + 465.20001220703125 + + + + 119 + + + + + 465.3999938964844 + + + + 120 + + + + + 465.79998779296875 + + + + 121 + + + + + 466.20001220703125 + + + + 122 + + + + + 466.6000061035156 + + + + 121 + + + + + 466.79998779296875 + + + + 121 + + + + + 467.20001220703125 + + + + 122 + + + + + 467.20001220703125 + + + + 122 + + + + + 467.3999938964844 + + + + 122 + + + + + 467.6000061035156 + + + + 123 + + + + + 467.6000061035156 + + + + 124 + + + + + 467.6000061035156 + + + + 125 + + + + + 467.6000061035156 + + + + 125 + + + + + 468.20001220703125 + + + + 126 + + + + + 468.3999938964844 + + + + 127 + + + + + 468.79998779296875 + + + + 127 + + + + + 469.0 + + + + 127 + + + + + 469.79998779296875 + + + + 128 + + + + + 470.0 + + + + 128 + + + + + 471.0 + + + + 129 + + + + + 471.20001220703125 + + + + 129 + + + + + 471.6000061035156 + + + + 130 + + + + + 472.0 + + + + 130 + + + + + 472.3999938964844 + + + + 131 + + + + + 473.6000061035156 + + + + 131 + + + + + 474.79998779296875 + + + + 131 + + + + + 475.6000061035156 + + + + 130 + + + + + 475.20001220703125 + + + + 130 + + + + + 475.3999938964844 + + + + 130 + + + + + 476.20001220703125 + + + + 130 + + + + + 476.79998779296875 + + + + 131 + + + + + 477.3999938964844 + + + + 131 + + + + + 477.3999938964844 + + + + 132 + + + + + 477.20001220703125 + + + + 132 + + + + + 476.79998779296875 + + + + 131 + + + + + 476.6000061035156 + + + + 132 + + + + + 475.0 + + + + 133 + + + + + 474.3999938964844 + + + + 134 + + + + + 474.3999938964844 + + + + 134 + + + + + 475.0 + + + + 135 + + + + + 475.0 + + + + 135 + + + + + 474.3999938964844 + + + + 134 + + + + + 473.3999938964844 + + + + 133 + + + + + 473.3999938964844 + + + + 133 + + + + + 472.6000061035156 + + + + 132 + + + + + 472.0 + + + + 131 + + + + + 471.6000061035156 + + + + 131 + + + + + 471.0 + + + + 130 + + + + + 469.79998779296875 + + + + 129 + + + + + 469.0 + + + + 128 + + + + + 469.3999938964844 + + + + 128 + + + + + 469.3999938964844 + + + + 128 + + + + + 469.6000061035156 + + + + 128 + + + + + 469.3999938964844 + + + + 128 + + + + + 469.20001220703125 + + + + 128 + + + + + 468.79998779296875 + + + + 130 + + + + + 468.6000061035156 + + + + 130 + + + + + 468.0 + + + + 131 + + + + + 467.6000061035156 + + + + 131 + + + + + 467.0 + + + + 131 + + + + + 466.79998779296875 + + + + 131 + + + + + 465.79998779296875 + + + + 131 + + + + + 465.3999938964844 + + + + 132 + + + + + 465.0 + + + + 132 + + + + + 464.79998779296875 + + + + 132 + + + + + 464.6000061035156 + + + + 132 + + + + + 464.3999938964844 + + + + 131 + + + + + 464.3999938964844 + + + + 131 + + + + + 464.0 + + + + 131 + + + + + 464.0 + + + + 131 + + + + + 464.0 + + + + 130 + + + + + 464.20001220703125 + + + + 130 + + + + + 464.20001220703125 + + + + 131 + + + + + 464.0 + + + + 132 + + + + + 464.6000061035156 + + + + 133 + + + + + 464.79998779296875 + + + + 133 + + + + + 465.3999938964844 + + + + 133 + + + + + 465.79998779296875 + + + + 134 + + + + + 466.0 + + + + 134 + + + + + 466.79998779296875 + + + + 135 + + + + + 466.6000061035156 + + + + 136 + + + + + 466.3999938964844 + + + + 136 + + + + + 466.3999938964844 + + + + 137 + + + + + 466.20001220703125 + + + + 138 + + + + + 466.0 + + + + 139 + + + + + 466.0 + + + + 139 + + + + + 465.79998779296875 + + + + 139 + + + + + 465.6000061035156 + + + + 139 + + + + + 465.3999938964844 + + + + 139 + + + + + 465.20001220703125 + + + + 139 + + + + + 465.0 + + + + 139 + + + + + 465.0 + + + + 139 + + + + + 465.20001220703125 + + + + 138 + + + + + 465.20001220703125 + + + + 138 + + + + + 465.20001220703125 + + + + 138 + + + + + 465.3999938964844 + + + + 137 + + + + + 465.79998779296875 + + + + 137 + + + + + 465.79998779296875 + + + + 137 + + + + + 466.0 + + + + 136 + + + + + 466.20001220703125 + + + + 135 + + + + + 466.79998779296875 + + + + 135 + + + + + 467.0 + + + + 134 + + + + + 467.20001220703125 + + + + 134 + + + + + 467.3999938964844 + + + + 134 + + + + + 467.79998779296875 + + + + 134 + + + + + 468.6000061035156 + + + + 134 + + + + + 469.0 + + + + 133 + + + + + 469.6000061035156 + + + + 133 + + + + + 470.79998779296875 + + + + 134 + + + + + 471.0 + + + + 134 + + + + + 471.3999938964844 + + + + 134 + + + + + 471.3999938964844 + + + + 133 + + + + + 471.6000061035156 + + + + 133 + + + + + 471.79998779296875 + + + + 134 + + + + + 471.79998779296875 + + + + 134 + + + + + 472.20001220703125 + + + + 133 + + + + + 473.0 + + + + 133 + + + + + 473.6000061035156 + + + + 132 + + + + + 473.79998779296875 + + + + 132 + + + + + 474.0 + + + + 131 + + + + + 473.6000061035156 + + + + 131 + + + + + 473.3999938964844 + + + + 131 + + + + + 473.0 + + + + 130 + + + + + 472.6000061035156 + + + + 129 + + + + + 472.0 + + + + 128 + + + + + 471.0 + + + + 127 + + + + + 470.6000061035156 + + + + 127 + + + + + 469.20001220703125 + + + + 125 + + + + + 469.0 + + + + 125 + + + + + 468.3999938964844 + + + + 123 + + + + + 468.0 + + + + 121 + + + + + 467.3999938964844 + + + + 120 + + + + + 467.20001220703125 + + + + 120 + + + + + 466.20001220703125 + + + + 120 + + + + + 466.20001220703125 + + + + 120 + + + + + 466.3999938964844 + + + + 120 + + + + + 466.3999938964844 + + + + 120 + + + + + 466.20001220703125 + + + + 120 + + + + + 465.79998779296875 + + + + 120 + + + + + 466.20001220703125 + + + + 120 + + + + + 466.3999938964844 + + + + 120 + + + + + 466.3999938964844 + + + + 119 + + + + + 466.20001220703125 + + + + 119 + + + + + 465.6000061035156 + + + + 119 + + + + + 465.20001220703125 + + + + 119 + + + + + 464.79998779296875 + + + + 120 + + + + + 464.79998779296875 + + + + 121 + + + + + 464.6000061035156 + + + + 122 + + + + + 463.79998779296875 + + + + 122 + + + + + 462.79998779296875 + + + + 122 + + + + + 462.3999938964844 + + + + 123 + + + + + 462.0 + + + + 122 + + + + + 462.0 + + + + 122 + + + + + 462.3999938964844 + + + + 121 + + + + + 463.0 + + + + 121 + + + + + 463.0 + + + + 121 + + + + + 462.3999938964844 + + + + 120 + + + + + 462.0 + + + + 120 + + + + + 462.0 + + + + 120 + + + + + 462.0 + + + + 121 + + + + + 462.0 + + + + 121 + + + + + 462.0 + + + + 123 + + + + + 462.0 + + + + 123 + + + + + 462.0 + + + + 124 + + + + + 462.3999938964844 + + + + 125 + + + + + 463.20001220703125 + + + + 125 + + + + + 464.0 + + + + 125 + + + + + 465.0 + + + + 126 + + + + + 465.6000061035156 + + + + 129 + + + + + 466.20001220703125 + + + + 130 + + + + + 467.20001220703125 + + + + 131 + + + + + 467.6000061035156 + + + + 131 + + + + + 468.20001220703125 + + + + 131 + + + + + 468.20001220703125 + + + + 131 + + + + + 468.79998779296875 + + + + 132 + + + + + 469.6000061035156 + + + + 133 + + + + + 469.79998779296875 + + + + 133 + + + + + 470.6000061035156 + + + + 133 + + + + + 471.79998779296875 + + + + 133 + + + + + 473.20001220703125 + + + + 134 + + + + + 475.6000061035156 + + + + 134 + + + + + 476.79998779296875 + + + + 135 + + + + + 477.3999938964844 + + + + 136 + + + + + 477.3999938964844 + + + + 136 + + + + + 478.3999938964844 + + + + 137 + + + + + 479.20001220703125 + + + + 138 + + + + + 479.3999938964844 + + + + 138 + + + + + 480.20001220703125 + + + + 138 + + + + + 480.6000061035156 + + + + 138 + + + + + 481.0 + + + + 138 + + + + + 481.6000061035156 + + + + 138 + + + + + 481.79998779296875 + + + + 139 + + + + + 482.0 + + + + 139 + + + + + 482.3999938964844 + + + + 137 + + + + + 482.6000061035156 + + + + 134 + + + + + 482.6000061035156 + + + + 134 + + + + + 482.79998779296875 + + + + 131 + + + + + 482.79998779296875 + + + + 128 + + + + + 482.6000061035156 + + + + 127 + + + + + 482.6000061035156 + + + + 126 + + + + + 482.6000061035156 + + + + 125 + + + + + 483.20001220703125 + + + + 120 + + + + + 483.20001220703125 + + + + 120 + + + + + 483.20001220703125 + + + + 120 + + + + + 537.7999877929688 + + + + 116 + + + + + 537.2000122070312 + + + + 116 + + + + + 535.5999755859375 + + + + 115 + + + + + 535.0 + + + + 115 + + + + + 534.0 + + + + 116 + + + + + 533.7999877929688 + + + + 116 + + + + + 533.5999755859375 + + + + 115 + + + + + 533.4000244140625 + + + + 115 + + + + + 532.0 + + + + 114 + + + + + 531.2000122070312 + + + + 114 + + + + + 529.4000244140625 + + + + 113 + + + + + 528.7999877929688 + + + + 113 + + + + + 528.0 + + + + 112 + + + + + 526.0 + + + + 111 + + + + + 525.4000244140625 + + + + 110 + + + + + 524.0 + + + + 110 + + + + + 522.4000244140625 + + + + 110 + + + + + 522.0 + + + + 109 + + + + + 521.4000244140625 + + + + 109 + + + + + 520.2000122070312 + + + + 109 + + + + + 516.5999755859375 + + + + 110 + + + + + 515.2000122070312 + + + + 111 + + + + + 514.2000122070312 + + + + 112 + + + + + 513.4000244140625 + + + + 111 + + + + + 513.2000122070312 + + + + 111 + + + + + 512.5999755859375 + + + + 111 + + + + + 512.7999877929688 + + + + 111 + + + + + 512.4000244140625 + + + + 111 + + + + + 511.0 + + + + 112 + + + + + 509.79998779296875 + + + + 113 + + + + + 509.20001220703125 + + + + 114 + + + + + 508.20001220703125 + + + + 115 + + + + + 507.79998779296875 + + + + 115 + + + + + 506.20001220703125 + + + + 114 + + + + + 505.0 + + + + 113 + + + + + 504.3999938964844 + + + + 112 + + + + + 503.20001220703125 + + + + 112 + + + + + 502.6000061035156 + + + + 111 + + + + + 501.3999938964844 + + + + 110 + + + + + 501.0 + + + + 110 + + + + + 499.79998779296875 + + + + 109 + + + + + 498.20001220703125 + + + + 108 + + + + + 496.0 + + + + 108 + + + + + 495.0 + + + + 108 + + + + + 494.3999938964844 + + + + 107 + + + + + 492.20001220703125 + + + + 108 + + + + + 491.79998779296875 + + + + 108 + + + + + 489.0 + + + + 109 + + + + + 487.20001220703125 + + + + 108 + + + + + 486.20001220703125 + + + + 108 + + + + + 483.3999938964844 + + + + 108 + + + + + 481.3999938964844 + + + + 107 + + + + + 479.79998779296875 + + + + 108 + + + + + 479.0 + + + + 108 + + + + + 478.0 + + + + 107 + + + + + 474.3999938964844 + + + + 106 + + + + + 471.3999938964844 + + + + 107 + + + + + 470.6000061035156 + + + + 108 + + + + + 469.79998779296875 + + + + 108 + + + + + 468.20001220703125 + + + + 108 + + + + + 467.79998779296875 + + + + 109 + + + + + 467.0 + + + + 109 + + + + + 466.20001220703125 + + + + 108 + + + + + 465.20001220703125 + + + + 107 + + + + + 462.0 + + + + 108 + + + + + 461.0 + + + + 108 + + + + + 458.6000061035156 + + + + 109 + + + + + 457.6000061035156 + + + + 109 + + + + + 455.0 + + + + 109 + + + + + 454.0 + + + + 109 + + + + + 451.6000061035156 + + + + 111 + + + + + 450.79998779296875 + + + + 112 + + + + + 449.20001220703125 + + + + 114 + + + + + 447.79998779296875 + + + + 115 + + + + + 445.20001220703125 + + + + 113 + + + + + 444.3999938964844 + + + + 113 + + + + + 443.6000061035156 + + + + 112 + + + + + 441.0 + + + + 111 + + + + + 440.3999938964844 + + + + 111 + + + + + 438.0 + + + + 110 + + + + + 436.3999938964844 + + + + 109 + + + + + 432.6000061035156 + + + + 109 + + + + + 431.3999938964844 + + + + 109 + + + + + 427.79998779296875 + + + + 109 + + + + + 426.79998779296875 + + + + 109 + + + + + 424.20001220703125 + + + + 108 + + + + + 423.3999938964844 + + + + 109 + + + + + 422.6000061035156 + + + + 110 + + + + + 420.20001220703125 + + + + 110 + + + + + 419.0 + + + + 110 + + + + + 416.79998779296875 + + + + 109 + + + + + 416.0 + + + + 110 + + + + + 415.79998779296875 + + + + 110 + + + + + 415.79998779296875 + + + + 110 + + + + + 415.20001220703125 + + + + 111 + + + + + 412.20001220703125 + + + + 111 + + + + + 409.6000061035156 + + + + 110 + + + + + 409.20001220703125 + + + + 110 + + + + + 407.79998779296875 + + + + 109 + + + + + 407.3999938964844 + + + + 109 + + + + + 407.20001220703125 + + + + 109 + + + + + 407.3999938964844 + + + + 109 + + + + + 407.3999938964844 + + + + 106 + + + + + 407.20001220703125 + + + + 108 + + + + + 407.0 + + + + 108 + + + + + 407.0 + + + + 107 + + + + + 407.20001220703125 + + + + 106 + + + + + 407.20001220703125 + + + + 105 + + + + + 407.20001220703125 + + + + 105 + + + + + 407.0 + + + + 106 + + + + + 406.79998779296875 + + + + 109 + + + + + 406.79998779296875 + + + + 110 + + + + + 406.6000061035156 + + + + 112 + + + + + 406.6000061035156 + + + + 106 + + + + + 406.6000061035156 + + + + 102 + + + + + 406.79998779296875 + + + + 106 + + + + + 406.79998779296875 + + + + 107 + + + + + 407.0 + + + + 110 + + + + + 407.0 + + + + 113 + + + + + 407.20001220703125 + + + + 116 + + + + + 407.3999938964844 + + + + 119 + + + + + 407.79998779296875 + + + + 122 + + + + + 408.20001220703125 + + + + 123 + + + + + 409.3999938964844 + + + + 125 + + + + + 410.20001220703125 + + + + 125 + + + + + 411.0 + + + + 126 + + + + + 412.20001220703125 + + + + 125 + + + + + 413.79998779296875 + + + + 125 + + + + + 415.20001220703125 + + + + 125 + + + + + 416.0 + + + + 125 + + + + + 416.20001220703125 + + + + 126 + + + + + 417.0 + + + + 127 + + + + + 417.20001220703125 + + + + 127 + + + + + 418.20001220703125 + + + + 130 + + + + + 418.3999938964844 + + + + 131 + + + + + 419.0 + + + + 133 + + + + + 419.20001220703125 + + + + 134 + + + + + 419.20001220703125 + + + + 134 + + + + + 419.3999938964844 + + + + 135 + + + + + 419.3999938964844 + + + + 136 + + + + + 419.3999938964844 + + + + 137 + + + + + 419.6000061035156 + + + + 138 + + + + + 419.79998779296875 + + + + 138 + + + + + 419.3999938964844 + + + + 136 + + + + + 419.20001220703125 + + + + 135 + + + + + 418.79998779296875 + + + + 132 + + + + + 418.3999938964844 + + + + 130 + + + + + 418.0 + + + + 128 + + + + + 417.3999938964844 + + + + 126 + + + + + 417.0 + + + + 125 + + + + + 416.3999938964844 + + + + 123 + + + + + 416.0 + + + + 122 + + + + + 415.79998779296875 + + + + 122 + + + + + 415.6000061035156 + + + + 123 + + + + + 415.20001220703125 + + + + 123 + + + + + 415.0 + + + + 123 + + + + + 414.79998779296875 + + + + 122 + + + + + 414.6000061035156 + + + + 121 + + + + + 414.6000061035156 + + + + 118 + + + + + 414.20001220703125 + + + + 115 + + + + + 413.79998779296875 + + + + 115 + + + + + 413.20001220703125 + + + + 115 + + + + + 412.79998779296875 + + + + 114 + + + + + 411.3999938964844 + + + + 113 + + + + + 409.20001220703125 + + + + 111 + + + + + 408.20001220703125 + + + + 110 + + + + + 407.0 + + + + 110 + + + + + 406.3999938964844 + + + + 110 + + + + + 404.6000061035156 + + + + 109 + + + + + 403.79998779296875 + + + + 109 + + + + + 402.0 + + + + 110 + + + + + 401.0 + + + + 110 + + + + + 398.20001220703125 + + + + 110 + + + + + 397.0 + + + + 110 + + + + + 396.6000061035156 + + + + 110 + + + + + 396.6000061035156 + + + + 109 + + + + + 396.79998779296875 + + + + 108 + + + + + 397.20001220703125 + + + + 108 + + + + + 397.20001220703125 + + + + 109 + + + + + 397.79998779296875 + + + + 112 + + + + + 398.79998779296875 + + + + 115 + + + + + 399.20001220703125 + + + + 116 + + + + + 399.79998779296875 + + + + 117 + + + + + 400.79998779296875 + + + + 119 + + + + + 402.20001220703125 + + + + 119 + + + + + 402.79998779296875 + + + + 120 + + + + + 403.3999938964844 + + + + 121 + + + + + 403.6000061035156 + + + + 122 + + + + + 403.79998779296875 + + + + 123 + + + + + 404.0 + + + + 125 + + + + + 404.3999938964844 + + + + 127 + + + + + 405.0 + + + + 129 + + + + + 405.6000061035156 + + + + 130 + + + + + 406.3999938964844 + + + + 131 + + + + + 407.0 + + + + 132 + + + + + 407.20001220703125 + + + + 132 + + + + + 407.3999938964844 + + + + 132 + + + + + 407.6000061035156 + + + + 131 + + + + + 407.6000061035156 + + + + 130 + + + + + 408.20001220703125 + + + + 129 + + + + + 408.6000061035156 + + + + 130 + + + + + 409.20001220703125 + + + + 131 + + + + + 409.0 + + + + 132 + + + + + 409.0 + + + + 134 + + + + + 409.79998779296875 + + + + 136 + + + + + 410.6000061035156 + + + + 137 + + + + + 410.79998779296875 + + + + 137 + + + + + 411.20001220703125 + + + + 138 + + + + + 411.79998779296875 + + + + 139 + + + + + 412.20001220703125 + + + + 139 + + + + + 413.20001220703125 + + + + 140 + + + + + 413.79998779296875 + + + + 140 + + + + + 414.0 + + + + 140 + + + + + 414.6000061035156 + + + + 141 + + + + + 414.6000061035156 + + + + 140 + + + + + 414.79998779296875 + + + + 140 + + + + + 415.3999938964844 + + + + 140 + + + + + 416.3999938964844 + + + + 139 + + + + + 417.3999938964844 + + + + 138 + + + + + 418.0 + + + + 136 + + + + + 418.6000061035156 + + + + 136 + + + + + 419.20001220703125 + + + + 135 + + + + + 420.0 + + + + 135 + + + + + 420.79998779296875 + + + + 138 + + + + + 421.79998779296875 + + + + 139 + + + + + 423.20001220703125 + + + + 139 + + + + + 424.20001220703125 + + + + 139 + + + + + 425.0 + + + + 139 + + + + + 425.3999938964844 + + + + 139 + + + + + 425.79998779296875 + + + + 139 + + + + + 426.20001220703125 + + + + 138 + + + + + 426.6000061035156 + + + + 139 + + + + + 427.0 + + + + 139 + + + + + 428.3999938964844 + + + + 138 + + + + + 429.6000061035156 + + + + 137 + + + + + 430.79998779296875 + + + + 135 + + + + + 431.6000061035156 + + + + 135 + + + + + 432.79998779296875 + + + + 133 + + + + + 434.20001220703125 + + + + 133 + + + + + 434.79998779296875 + + + + 134 + + + + + 435.20001220703125 + + + + 134 + + + + + 437.20001220703125 + + + + 134 + + + + + 438.79998779296875 + + + + 135 + + + + + 439.3999938964844 + + + + 135 + + + + + 439.6000061035156 + + + + 134 + + + + + 439.6000061035156 + + + + 134 + + + + + 439.6000061035156 + + + + 134 + + + + + 439.6000061035156 + + + + 134 + + + + + 439.3999938964844 + + + + 134 + + + + + 439.3999938964844 + + + + 134 + + + + + 439.20001220703125 + + + + 134 + + + + + 439.20001220703125 + + + + 134 + + + + + 439.3999938964844 + + + + 133 + + + + + 439.79998779296875 + + + + 134 + + + + + 440.0 + + + + 134 + + + + + 440.6000061035156 + + + + 134 + + + + + 441.0 + + + + 134 + + + + + 441.3999938964844 + + + + 135 + + + + + 443.0 + + + + 137 + + + + + 444.3999938964844 + + + + 137 + + + + + 445.3999938964844 + + + + 137 + + + + + 446.0 + + + + 138 + + + + + 446.20001220703125 + + + + 138 + + + + + 446.6000061035156 + + + + 138 + + + + + 447.0 + + + + 139 + + + + + 448.0 + + + + 139 + + + + + 449.0 + + + + 139 + + + + + 450.20001220703125 + + + + 138 + + + + + 451.79998779296875 + + + + 137 + + + + + 453.0 + + + + 137 + + + + + 453.20001220703125 + + + + 136 + + + + + 454.20001220703125 + + + + 136 + + + + + 455.0 + + + + 136 + + + + + 455.3999938964844 + + + + 135 + + + + + 455.6000061035156 + + + + 135 + + + + + 456.3999938964844 + + + + 134 + + + + + 456.3999938964844 + + + + 134 + + + + + 456.79998779296875 + + + + 135 + + + + + 457.79998779296875 + + + + 135 + + + + + 457.79998779296875 + + + + 135 + + + + + 458.0 + + + + 134 + + + + + 458.6000061035156 + + + + 134 + + + + + 458.79998779296875 + + + + 131 + + + + + 458.79998779296875 + + + + 130 + + + + + 459.6000061035156 + + + + 130 + + + + + 460.0 + + + + 130 + + + + + 461.0 + + + + 131 + + + + + 461.3999938964844 + + + + 130 + + + + + 462.6000061035156 + + + + 131 + + + + + 463.3999938964844 + + + + 132 + + + + + 463.6000061035156 + + + + 132 + + + + + 464.0 + + + + 131 + + + + + 464.6000061035156 + + + + 131 + + + + + 464.79998779296875 + + + + 131 + + + + + 465.0 + + + + 132 + + + + + 465.20001220703125 + + + + 133 + + + + + 465.6000061035156 + + + + 133 + + + + + 465.79998779296875 + + + + 134 + + + + + 465.79998779296875 + + + + 134 + + + + + 466.0 + + + + 135 + + + + + 466.0 + + + + 135 + + + + + 466.0 + + + + 135 + + + + + 466.0 + + + + 134 + + + + + 466.0 + + + + 134 + + + + + 466.20001220703125 + + + + 134 + + + + + 466.3999938964844 + + + + 133 + + + + + 466.79998779296875 + + + + 132 + + + + + 467.0 + + + + 132 + + + + + 467.3999938964844 + + + + 133 + + + + + 468.0 + + + + 133 + + + + + 468.0 + + + + 134 + + + + + 468.20001220703125 + + + + 134 + + + + + 468.6000061035156 + + + + 133 + + + + + 469.20001220703125 + + + + 132 + + + + + 470.0 + + + + 131 + + + + + 470.6000061035156 + + + + 131 + + + + + 471.3999938964844 + + + + 130 + + + + + 471.6000061035156 + + + + 130 + + + + + 472.20001220703125 + + + + 130 + + + + + 472.20001220703125 + + + + 130 + + + + + 472.79998779296875 + + + + 130 + + + + + 473.0 + + + + 130 + + + + + 473.79998779296875 + + + + 131 + + + + + 474.79998779296875 + + + + 132 + + + + + 475.79998779296875 + + + + 132 + + + + + 476.6000061035156 + + + + 133 + + + + + 477.20001220703125 + + + + 134 + + + + + 478.3999938964844 + + + + 134 + + + + + 478.6000061035156 + + + + 134 + + + + + 480.0 + + + + 134 + + + + + 480.20001220703125 + + + + 134 + + + + + 481.0 + + + + 133 + + + + + 481.6000061035156 + + + + 133 + + + + + 481.79998779296875 + + + + 133 + + + + + 482.0 + + + + 132 + + + + + 482.20001220703125 + + + + 133 + + + + + 483.0 + + + + 131 + + + + + 483.79998779296875 + + + + 131 + + + + + 484.6000061035156 + + + + 132 + + + + + 484.79998779296875 + + + + 132 + + + + + 485.20001220703125 + + + + 132 + + + + + 485.6000061035156 + + + + 132 + + + + + 486.0 + + + + 132 + + + + + 486.3999938964844 + + + + 132 + + + + + 487.20001220703125 + + + + 132 + + + + + 487.3999938964844 + + + + 132 + + + + + 487.6000061035156 + + + + 132 + + + + + 488.79998779296875 + + + + 131 + + + + + 489.0 + + + + 131 + + + + + 489.79998779296875 + + + + 131 + + + + + 490.6000061035156 + + + + 131 + + + + + 491.3999938964844 + + + + 132 + + + + + 492.0 + + + + 132 + + + + + 492.3999938964844 + + + + 132 + + + + + 492.3999938964844 + + + + 133 + + + + + 492.6000061035156 + + + + 133 + + + + + 492.6000061035156 + + + + 133 + + + + + 493.0 + + + + 132 + + + + + 493.3999938964844 + + + + 133 + + + + + 493.6000061035156 + + + + 132 + + + + + 493.6000061035156 + + + + 133 + + + + + 493.79998779296875 + + + + 132 + + + + + 493.6000061035156 + + + + 132 + + + + + 493.3999938964844 + + + + 131 + + + + + 493.3999938964844 + + + + 131 + + + + + 493.20001220703125 + + + + 131 + + + + + 493.20001220703125 + + + + 130 + + + + + 493.20001220703125 + + + + 130 + + + + + 493.20001220703125 + + + + 130 + + + + + 493.20001220703125 + + + + 131 + + + + + 493.20001220703125 + + + + 131 + + + + + 493.3999938964844 + + + + 131 + + + + + 493.3999938964844 + + + + 131 + + + + + 493.79998779296875 + + + + 131 + + + + + 494.3999938964844 + + + + 131 + + + + + 494.3999938964844 + + + + 131 + + + + + 494.79998779296875 + + + + 131 + + + + + 495.0 + + + + 131 + + + + + 495.20001220703125 + + + + 131 + + + + + 495.3999938964844 + + + + 131 + + + + + 495.3999938964844 + + + + 131 + + + + + 495.6000061035156 + + + + 131 + + + + + 495.79998779296875 + + + + 132 + + + + + 496.0 + + + + 132 + + + + + 496.20001220703125 + + + + 132 + + + + + 496.3999938964844 + + + + 131 + + + + + 496.6000061035156 + + + + 131 + + + + + 496.79998779296875 + + + + 131 + + + + + 497.20001220703125 + + + + 131 + + + + + 498.0 + + + + 129 + + + + + 498.20001220703125 + + + + 129 + + + + + 498.6000061035156 + + + + 129 + + + + + 499.0 + + + + 129 + + + + + 499.20001220703125 + + + + 129 + + + + + 499.20001220703125 + + + + 129 + + + + + 499.6000061035156 + + + + 128 + + + + + 499.79998779296875 + + + + 127 + + + + + 500.0 + + + + 127 + + + + + 500.3999938964844 + + + + 127 + + + + + 500.3999938964844 + + + + 128 + + + + + 500.6000061035156 + + + + 127 + + + + + 500.79998779296875 + + + + 127 + + + + + 501.3999938964844 + + + + 128 + + + + + 501.79998779296875 + + + + 128 + + + + + 502.0 + + + + 128 + + + + + 502.6000061035156 + + + + 128 + + + + + 504.0 + + + + 128 + + + + + 504.79998779296875 + + + + 128 + + + + + 505.3999938964844 + + + + 128 + + + + + 505.79998779296875 + + + + 127 + + + + + 507.20001220703125 + + + + 127 + + + + + 507.79998779296875 + + + + 126 + + + + + 508.0 + + + + 127 + + + + + 509.0 + + + + 126 + + + + + 509.79998779296875 + + + + 126 + + + + + 510.3999938964844 + + + + 127 + + + + + 511.0 + + + + 127 + + + + + 511.3999938964844 + + + + 127 + + + + + 512.4000244140625 + + + + 127 + + + + + 513.5999755859375 + + + + 127 + + + + + 514.0 + + + + 127 + + + + + 514.7999877929688 + + + + 128 + + + + + 515.2000122070312 + + + + 128 + + + + + 515.4000244140625 + + + + 128 + + + + + 515.7999877929688 + + + + 130 + + + + + 516.0 + + + + 130 + + + + + 516.2000122070312 + + + + 130 + + + + + 516.4000244140625 + + + + 131 + + + + + 517.0 + + + + 133 + + + + + 517.2000122070312 + + + + 133 + + + + + 517.4000244140625 + + + + 134 + + + + + 517.4000244140625 + + + + 134 + + + + + 517.5999755859375 + + + + 135 + + + + + 517.5999755859375 + + + + 135 + + + + + 517.5999755859375 + + + + 135 + + + + + 517.5999755859375 + + + + 136 + + + + + 517.5999755859375 + + + + 137 + + + + + 517.5999755859375 + + + + 137 + + + + + 517.5999755859375 + + + + 137 + + + + + 517.7999877929688 + + + + 137 + + + + + 517.7999877929688 + + + + 136 + + + + + 518.0 + + + + 137 + + + + + 518.4000244140625 + + + + 137 + + + + + 518.7999877929688 + + + + 136 + + + + + 519.4000244140625 + + + + 136 + + + + + 519.7999877929688 + + + + 136 + + + + + 519.7999877929688 + + + + 136 + + + + + 520.0 + + + + 136 + + + + + 519.5999755859375 + + + + 135 + + + + + 519.5999755859375 + + + + 135 + + + + + 519.7999877929688 + + + + 134 + + + + + 519.5999755859375 + + + + 133 + + + + + 519.5999755859375 + + + + 134 + + + + + 519.4000244140625 + + + + 133 + + + + + 519.4000244140625 + + + + 133 + + + + + 519.2000122070312 + + + + 134 + + + + + 519.2000122070312 + + + + 133 + + + + + 518.7999877929688 + + + + 132 + + + + + 518.5999755859375 + + + + 131 + + + + + 519.0 + + + + 131 + + + + + 519.4000244140625 + + + + 130 + + + + + 519.5999755859375 + + + + 130 + + + + + 519.7999877929688 + + + + 129 + + + + + 520.4000244140625 + + + + 129 + + + + + 521.4000244140625 + + + + 128 + + + + + 522.4000244140625 + + + + 127 + + + + + 522.5999755859375 + + + + 127 + + + + + 522.4000244140625 + + + + 128 + + + + + 522.4000244140625 + + + + 128 + + + + + 521.7999877929688 + + + + 129 + + + + + 521.7999877929688 + + + + 131 + + + + + 522.0 + + + + 131 + + + + + 522.2000122070312 + + + + 132 + + + + + 522.5999755859375 + + + + 133 + + + + + 523.2000122070312 + + + + 133 + + + + + 523.2000122070312 + + + + 132 + + + + + 523.4000244140625 + + + + 132 + + + + + 523.4000244140625 + + + + 132 + + + + + 523.4000244140625 + + + + 129 + + + + + 523.5999755859375 + + + + 129 + + + + + 523.5999755859375 + + + + 128 + + + + + 523.5999755859375 + + + + 127 + + + + + 523.5999755859375 + + + + 124 + + + + + 523.7999877929688 + + + + 121 + + + + + 523.7999877929688 + + + + 121 + + + + + 524.0 + + + + 124 + + + + + 524.0 + + + + 124 + + + + + 524.2000122070312 + + + + 125 + + + + + 524.4000244140625 + + + + 125 + + + + + 524.4000244140625 + + + + 125 + + + + + 524.7999877929688 + + + + 125 + + + + + 525.0 + + + + 126 + + + + + 525.0 + + + + 126 + + + + + 525.4000244140625 + + + + 125 + + + + + 525.4000244140625 + + + + 125 + + + + + 526.0 + + + + 125 + + + + + 526.0 + + + + 125 + + + + + 526.5999755859375 + + + + 125 + + + + + 526.7999877929688 + + + + 126 + + + + + 527.2000122070312 + + + + 127 + + + + + 527.4000244140625 + + + + 127 + + + + + 527.5999755859375 + + + + 127 + + + + + 528.2000122070312 + + + + 127 + + + + + 528.4000244140625 + + + + 127 + + + + + 528.5999755859375 + + + + 127 + + + + + 529.2000122070312 + + + + 127 + + + + + 529.5999755859375 + + + + 127 + + + + + 530.5999755859375 + + + + 128 + + + + + 531.7999877929688 + + + + 129 + + + + + 532.5999755859375 + + + + 129 + + + + + 532.7999877929688 + + + + 129 + + + + + 532.7999877929688 + + + + 128 + + + + + 532.0 + + + + 127 + + + + + 531.7999877929688 + + + + 127 + + + + + 531.5999755859375 + + + + 125 + + + + + 531.7999877929688 + + + + 123 + + + + + 532.2000122070312 + + + + 122 + + + + + 532.4000244140625 + + + + 121 + + + + + 533.0 + + + + 121 + + + + + 533.2000122070312 + + + + 120 + + + + + 533.5999755859375 + + + + 119 + + + + + 533.2000122070312 + + + + 119 + + + + + 533.0 + + + + 118 + + + + + 532.2000122070312 + + + + 117 + + + + + 532.0 + + + + 116 + + + + + 531.5999755859375 + + + + 115 + + + + + 531.4000244140625 + + + + 115 + + + + + 531.0 + + + + 115 + + + + + 531.5999755859375 + + + + 114 + + + + + 531.4000244140625 + + + + 114 + + + + + 531.2000122070312 + + + + 113 + + + + + 530.7999877929688 + + + + 112 + + + + + 530.5999755859375 + + + + 112 + + + + + 528.2000122070312 + + + + 110 + + + + + 524.5999755859375 + + + + 108 + + + + + 522.0 + + + + 109 + + + + + 520.2000122070312 + + + + 109 + + + + + 516.4000244140625 + + + + 110 + + + + + 511.6000061035156 + + + + 110 + + + + + 508.6000061035156 + + + + 111 + + + + + 508.0 + + + + 111 + + + + + 506.20001220703125 + + + + 114 + + + + + 506.0 + + + + 114 + + + + + 505.6000061035156 + + + + 116 + + + + + 505.3999938964844 + + + + 116 + + + + + 504.79998779296875 + + + + 117 + + + + + 503.6000061035156 + + + + 118 + + + + + 502.79998779296875 + + + + 117 + + + + + 502.0 + + + + 116 + + + + + 501.3999938964844 + + + + 115 + + + + + 501.3999938964844 + + + + 114 + + + + + 501.3999938964844 + + + + 115 + + + + + 501.20001220703125 + + + + 116 + + + + + 500.79998779296875 + + + + 118 + + + + + 501.0 + + + + 119 + + + + + 501.0 + + + + 119 + + + + + 501.6000061035156 + + + + 119 + + + + + 501.79998779296875 + + + + 120 + + + + + 502.0 + + + + 120 + + + + + 502.0 + + + + 120 + + + + + 502.20001220703125 + + + + 120 + + + + + 502.6000061035156 + + + + 120 + + + + + 502.6000061035156 + + + + 120 + + + + + 502.79998779296875 + + + + 120 + + + + + 502.20001220703125 + + + + 120 + + + + + 501.6000061035156 + + + + 119 + + + + + 501.3999938964844 + + + + 119 + + + + + 501.0 + + + + 119 + + + + + 500.79998779296875 + + + + 119 + + + + + 500.0 + + + + 119 + + + + + 499.20001220703125 + + + + 120 + + + + + 499.79998779296875 + + + + 122 + + + + + 500.6000061035156 + + + + 123 + + + + + 500.79998779296875 + + + + 123 + + + + + 501.20001220703125 + + + + 124 + + + + + 501.79998779296875 + + + + 125 + + + + + 502.20001220703125 + + + + 126 + + + + + 502.20001220703125 + + + + 126 + + + + + 502.3999938964844 + + + + 126 + + + + + 502.20001220703125 + + + + 127 + + + + + 502.20001220703125 + + + + 127 + + + + + 501.79998779296875 + + + + 127 + + + + + 501.79998779296875 + + + + 127 + + + + + 501.79998779296875 + + + + 128 + + + + + 502.0 + + + + 129 + + + + + 502.20001220703125 + + + + 129 + + + + + 502.20001220703125 + + + + 129 + + + + + 502.3999938964844 + + + + 130 + + + + + 503.0 + + + + 129 + + + + + 503.3999938964844 + + + + 129 + + + + + 503.6000061035156 + + + + 130 + + + + + 504.20001220703125 + + + + 130 + + + + + 504.79998779296875 + + + + 131 + + + + + 505.0 + + + + 131 + + + + + 505.20001220703125 + + + + 131 + + + + + 505.3999938964844 + + + + 132 + + + + + 505.6000061035156 + + + + 132 + + + + + 506.3999938964844 + + + + 132 + + + + + 507.79998779296875 + + + + 133 + + + + + 508.6000061035156 + + + + 134 + + + + + 509.20001220703125 + + + + 135 + + + + + 510.0 + + + + 136 + + + + + 511.0 + + + + 136 + + + + + 511.3999938964844 + + + + 136 + + + + + 511.6000061035156 + + + + 136 + + + + + 511.79998779296875 + + + + 136 + + + + + 511.79998779296875 + + + + 137 + + + + + 511.79998779296875 + + + + 137 + + + + + 512.0 + + + + 137 + + + + + 512.4000244140625 + + + + 137 + + + + + 512.4000244140625 + + + + 138 + + + + + 512.5999755859375 + + + + 138 + + + + + 512.5999755859375 + + + + 138 + + + + + 513.0 + + + + 140 + + + + + 513.5999755859375 + + + + 140 + + + + + 514.2000122070312 + + + + 139 + + + + + 515.0 + + + + 137 + + + + + 515.4000244140625 + + + + 136 + + + + + 515.2000122070312 + + + + 135 + + + + + 515.0 + + + + 134 + + + + + 514.7999877929688 + + + + 134 + + + + + 514.0 + + + + 134 + + + + + 513.4000244140625 + + + + 132 + + + + + 513.2000122070312 + + + + 129 + + + + + 513.2000122070312 + + + + 126 + + + + + 513.0 + + + + 124 + + + + + 512.2000122070312 + + + + 121 + + + + + 510.79998779296875 + + + + 120 + + + + + 510.20001220703125 + + + + 120 + + + + + 508.6000061035156 + + + + 118 + + + + + 507.6000061035156 + + + + 118 + + + + + 506.6000061035156 + + + + 119 + + + + + 505.20001220703125 + + + + 121 + + + + + 505.0 + + + + 121 + + + + + 504.3999938964844 + + + + 124 + + + + + 504.20001220703125 + + + + 124 + + + + + 503.79998779296875 + + + + 124 + + + + + 503.3999938964844 + + + + 123 + + + + + 503.20001220703125 + + + + 124 + + + + + 503.20001220703125 + + + + 124 + + + + + 503.20001220703125 + + + + 124 + + + + + 503.0 + + + + 125 + + + + + 502.6000061035156 + + + + 125 + + + + + 502.3999938964844 + + + + 125 + + + + + 502.20001220703125 + + + + 125 + + + + + 502.0 + + + + 125 + + + + + 502.0 + + + + 124 + + + + + 502.0 + + + + 124 + + + + + 502.20001220703125 + + + + 126 + + + + + 502.3999938964844 + + + + 127 + + + + + 502.6000061035156 + + + + 128 + + + + + 502.79998779296875 + + + + 129 + + + + + 502.79998779296875 + + + + 130 + + + + + 503.0 + + + + 131 + + + + + 503.3999938964844 + + + + 131 + + + + + 504.6000061035156 + + + + 132 + + + + + 505.3999938964844 + + + + 131 + + + + + 505.3999938964844 + + + + 131 + + + + + 505.3999938964844 + + + + 131 + + + + + 505.20001220703125 + + + + 130 + + + + + 505.20001220703125 + + + + 130 + + + + + 505.6000061035156 + + + + 130 + + + + + 506.6000061035156 + + + + 129 + + + + + 506.6000061035156 + + + + 129 + + + + + 506.6000061035156 + + + + 129 + + + + + 506.0 + + + + 128 + + + + + 505.79998779296875 + + + + 128 + + + + + 504.79998779296875 + + + + 127 + + + + + 504.20001220703125 + + + + 126 + + + + + 503.0 + + + + 126 + + + + + 502.6000061035156 + + + + 125 + + + + + 501.6000061035156 + + + + 125 + + + + + 501.20001220703125 + + + + 124 + + + + + 500.79998779296875 + + + + 124 + + + + + 500.6000061035156 + + + + 123 + + + + + 500.6000061035156 + + + + 123 + + + + + 500.6000061035156 + + + + 123 + + + + + 500.6000061035156 + + + + 122 + + + + + 499.6000061035156 + + + + 121 + + + + + 498.79998779296875 + + + + 120 + + + + + 498.20001220703125 + + + + 120 + + + + + 497.20001220703125 + + + + 119 + + + + + 496.6000061035156 + + + + 118 + + + + + 494.3999938964844 + + + + 117 + + + + + 493.79998779296875 + + + + 117 + + + + + 493.3999938964844 + + + + 117 + + + + + 490.20001220703125 + + + + 117 + + + + + 489.3999938964844 + + + + 117 + + + + + 487.6000061035156 + + + + 117 + + + + + 487.3999938964844 + + + + 116 + + + + + 487.0 + + + + 115 + + + + + 487.6000061035156 + + + + 114 + + + + + 488.6000061035156 + + + + 114 + + + + + 488.79998779296875 + + + + 115 + + + + + 490.20001220703125 + + + + 114 + + + + + 491.0 + + + + 114 + + + + + 491.20001220703125 + + + + 114 + + + + + 491.6000061035156 + + + + 114 + + + + + 490.6000061035156 + + + + 115 + + + + + 490.20001220703125 + + + + 115 + + + + + 489.6000061035156 + + + + 116 + + + + + 487.6000061035156 + + + + 116 + + + + + 486.6000061035156 + + + + 116 + + + + + 485.3999938964844 + + + + 116 + + + + + 484.79998779296875 + + + + 115 + + + + + 484.0 + + + + 115 + + + + + 482.20001220703125 + + + + 115 + + + + + 481.3999938964844 + + + + 116 + + + + + 480.79998779296875 + + + + 116 + + + + + 480.6000061035156 + + + + 117 + + + + + 479.6000061035156 + + + + 117 + + + + + 479.20001220703125 + + + + 117 + + + + + 478.3999938964844 + + + + 116 + + + + + 478.0 + + + + 115 + + + + + 477.6000061035156 + + + + 113 + + + + + 477.0 + + + + 113 + + + + + 476.79998779296875 + + + + 113 + + + + + 475.6000061035156 + + + + 114 + + + + + 475.20001220703125 + + + + 115 + + + + + 474.0 + + + + 115 + + + + + 472.20001220703125 + + + + 113 + + + + + 471.0 + + + + 112 + + + + + 470.20001220703125 + + + + 112 + + + + + 469.6000061035156 + + + + 111 + + + + + 469.3999938964844 + + + + 112 + + + + + 469.3999938964844 + + + + 112 + + + + + 469.20001220703125 + + + + 112 + + + + + 468.79998779296875 + + + + 111 + + + + + 469.0 + + + + 111 + + + + + 468.3999938964844 + + + + 112 + + + + + 467.79998779296875 + + + + 112 + + + + + 466.6000061035156 + + + + 112 + + + + + 464.20001220703125 + + + + 112 + + + + + 463.6000061035156 + + + + 112 + + + + + 461.0 + + + + 112 + + + + + 460.6000061035156 + + + + 113 + + + + + 458.20001220703125 + + + + 114 + + + + + 457.20001220703125 + + + + 114 + + + + + 453.20001220703125 + + + + 114 + + + + + 452.79998779296875 + + + + 114 + + + + + 450.6000061035156 + + + + 114 + + + + + 449.79998779296875 + + + + 114 + + + + + 448.0 + + + + 114 + + + + + 446.79998779296875 + + + + 115 + + + + + 443.20001220703125 + + + + 116 + + + + + 442.0 + + + + 116 + + + + + 438.79998779296875 + + + + 117 + + + + + 437.3999938964844 + + + + 118 + + + + + 436.3999938964844 + + + + 118 + + + + + 434.79998779296875 + + + + 118 + + + + + 434.6000061035156 + + + + 118 + + + + + 432.3999938964844 + + + + 118 + + + + + 429.3999938964844 + + + + 120 + + + + + 428.20001220703125 + + + + 120 + + + + + 424.79998779296875 + + + + 119 + + + + + 423.0 + + + + 119 + + + + + 420.6000061035156 + + + + 119 + + + + + 420.0 + + + + 119 + + + + + 419.3999938964844 + + + + 119 + + + + + 416.6000061035156 + + + + 118 + + + + + 415.79998779296875 + + + + 118 + + + + + 415.20001220703125 + + + + 118 + + + + + 413.79998779296875 + + + + 118 + + + + + 413.20001220703125 + + + + 118 + + + + + 412.79998779296875 + + + + 118 + + + + + 411.3999938964844 + + + + 119 + + + + + 410.20001220703125 + + + + 120 + + + + + 409.6000061035156 + + + + 121 + + + + + 409.20001220703125 + + + + 122 + + + + + 409.0 + + + + 121 + + + + + 408.3999938964844 + + + + 122 + + + + + 408.0 + + + + 122 + + + + + 407.79998779296875 + + + + 121 + + + + + 407.0 + + + + 122 + + + + + 407.3999938964844 + + + + 123 + + + + + 407.6000061035156 + + + + 124 + + + + + 408.0 + + + + 124 + + + + + 408.6000061035156 + + + + 125 + + + + + 408.79998779296875 + + + + 126 + + + + + 409.3999938964844 + + + + 127 + + + + + 409.3999938964844 + + + + 128 + + + + + 408.79998779296875 + + + + 130 + + + + + 408.79998779296875 + + + + 130 + + + + + 407.79998779296875 + + + + 130 + + + + + 407.3999938964844 + + + + 131 + + + + + 407.0 + + + + 131 + + + + + 407.6000061035156 + + + + 132 + + + + + 408.0 + + + + 132 + + + + + 408.0 + + + + 133 + + + + + 407.79998779296875 + + + + 133 + + + + + 407.79998779296875 + + + + 133 + + + + + 407.79998779296875 + + + + 133 + + + + + 407.79998779296875 + + + + 134 + + + + + 408.0 + + + + 134 + + + + + 409.3999938964844 + + + + 135 + + + + + 409.79998779296875 + + + + 135 + + + + + 409.79998779296875 + + + + 135 + + + + + 410.20001220703125 + + + + 136 + + + + + 410.3999938964844 + + + + 136 + + + + + 411.20001220703125 + + + + 136 + + + + + 411.20001220703125 + + + + 136 + + + + + 410.0 + + + + 136 + + + + + 409.20001220703125 + + + + 137 + + + + + 408.79998779296875 + + + + 137 + + + + + 408.3999938964844 + + + + 138 + + + + + 408.3999938964844 + + + + 139 + + + + + 408.6000061035156 + + + + 139 + + + + + 408.6000061035156 + + + + 139 + + + + + 408.79998779296875 + + + + 140 + + + + + 409.0 + + + + 140 + + + + + 407.79998779296875 + + + + 141 + + + + + 407.6000061035156 + + + + 141 + + + + + 407.0 + + + + 141 + + + + + 406.6000061035156 + + + + 141 + + + + + 406.0 + + + + 141 + + + + + 405.79998779296875 + + + + 142 + + + + + 405.79998779296875 + + + + 142 + + + + + 406.0 + + + + 142 + + + + + 406.20001220703125 + + + + 142 + + + + + 406.79998779296875 + + + + 143 + + + + + 406.79998779296875 + + + + 143 + + + + + 407.0 + + + + 142 + + + + + 405.79998779296875 + + + + 141 + + + + + 403.20001220703125 + + + + 141 + + + + + 403.0 + + + + 141 + + + + + 399.6000061035156 + + + + 139 + + + + + 398.3999938964844 + + + + 138 + + + + + 396.79998779296875 + + + + 137 + + + + + 396.0 + + + + 136 + + + + + 396.0 + + + + 134 + + + + + 396.20001220703125 + + + + 134 + + + + + 396.20001220703125 + + + + 133 + + + + + 394.3999938964844 + + + + 131 + + + + + 393.79998779296875 + + + + 131 + + + + + 391.79998779296875 + + + + 129 + + + + + 391.79998779296875 + + + + 128 + + + + + 392.20001220703125 + + + + 128 + + + + + 392.3999938964844 + + + + 126 + + + + + 392.3999938964844 + + + + 124 + + + + + 392.20001220703125 + + + + 123 + + + + + 392.20001220703125 + + + + 123 + + + + + 392.0 + + + + 123 + + + + + 392.20001220703125 + + + + 123 + + + + + 392.3999938964844 + + + + 124 + + + + + 392.20001220703125 + + + + 124 + + + + + 391.79998779296875 + + + + 126 + + + + + 391.6000061035156 + + + + 125 + + + + + 391.79998779296875 + + + + 122 + + + + + 392.0 + + + + 123 + + + + + 392.20001220703125 + + + + 123 + + + + + 392.6000061035156 + + + + 125 + + + + + 392.6000061035156 + + + + 126 + + + + + 392.79998779296875 + + + + 127 + + + + + 392.79998779296875 + + + + 126 + + + + + 393.0 + + + + 126 + + + + + 393.20001220703125 + + + + 126 + + + + + 393.6000061035156 + + + + 126 + + + + + 394.20001220703125 + + + + 126 + + + + + 394.3999938964844 + + + + 125 + + + + + 392.6000061035156 + + + + 123 + + + + + 391.6000061035156 + + + + 123 + + + + + 390.79998779296875 + + + + 123 + + + + + 389.3999938964844 + + + + 122 + + + + + 389.0 + + + + 121 + + + + + 388.3999938964844 + + + + 120 + + + + + 387.6000061035156 + + + + 120 + + + + + 386.6000061035156 + + + + 119 + + + + + 383.3999938964844 + + + + 118 + + + + + 381.6000061035156 + + + + 118 + + + + + 380.0 + + + + 118 + + + + + 377.20001220703125 + + + + 117 + + + + + 376.3999938964844 + + + + 117 + + + + + 373.20001220703125 + + + + 117 + + + + + 373.20001220703125 + + + + 117 + + + + + 373.6000061035156 + + + + 114 + + + + + 373.3999938964844 + + + + 113 + + + + + 372.79998779296875 + + + + 115 + + + + + 372.6000061035156 + + + + 115 + + + + + 372.20001220703125 + + + + 117 + + + + + 372.20001220703125 + + + + 115 + + + + + 371.79998779296875 + + + + 115 + + + + + 371.6000061035156 + + + + 114 + + + + + 370.6000061035156 + + + + 114 + + + + + 370.20001220703125 + + + + 113 + + + + + 369.3999938964844 + + + + 113 + + + + + 368.6000061035156 + + + + 112 + + + + + 367.3999938964844 + + + + 111 + + + + + 367.20001220703125 + + + + 111 + + + + + 366.0 + + + + 110 + + + + + 365.79998779296875 + + + + 110 + + + + + 365.6000061035156 + + + + 110 + + + + + 365.6000061035156 + + + + 110 + + + + + 365.3999938964844 + + + + 111 + + + + + 365.3999938964844 + + + + 111 + + + + + 361.3999938964844 + + + + 92 + + + + + 361.3999938964844 + + + + 92 + + + + + 360.79998779296875 + + + + 95 + + + + + 360.79998779296875 + + + + 95 + + + + + 362.0 + + + + 96 + + + + + 362.79998779296875 + + + + 97 + + + + + 362.6000061035156 + + + + 98 + + + + + 362.79998779296875 + + + + 99 + + + + + 363.0 + + + + 99 + + + + + 362.6000061035156 + + + + 101 + + + + + 362.3999938964844 + + + + 101 + + + + + 362.20001220703125 + + + + 101 + + + + + 361.3999938964844 + + + + 104 + + + + + 361.0 + + + + 105 + + + + + 360.20001220703125 + + + + 106 + + + + + 359.6000061035156 + + + + 107 + + + + + 359.20001220703125 + + + + 107 + + + + + 358.3999938964844 + + + + 107 + + + + + 358.0 + + + + 106 + + + + + 358.0 + + + + 99 + + + + + 358.0 + + + + 96 + + + + + 358.0 + + + + 99 + + + + + 357.79998779296875 + + + + 102 + + + + + 357.79998779296875 + + + + 103 + + + + + 357.6000061035156 + + + + 106 + + + + + 358.20001220703125 + + + + 108 + + + + + 359.3999938964844 + + + + 108 + + + + + 359.79998779296875 + + + + 109 + + + + + 360.3999938964844 + + + + 110 + + + + + 361.20001220703125 + + + + 113 + + + + + 361.3999938964844 + + + + 114 + + + + + 361.3999938964844 + + + + 117 + + + + + 361.20001220703125 + + + + 117 + + + + + 360.79998779296875 + + + + 118 + + + + + 360.3999938964844 + + + + 120 + + + + + 361.3999938964844 + + + + 122 + + + + + 362.3999938964844 + + + + 121 + + + + + 362.79998779296875 + + + + 122 + + + + + 363.0 + + + + 122 + + + + + 363.20001220703125 + + + + 122 + + + + + 364.0 + + + + 122 + + + + + 364.3999938964844 + + + + 121 + + + + + 364.6000061035156 + + + + 121 + + + + + 364.6000061035156 + + + + 121 + + + + + 365.3999938964844 + + + + 119 + + + + + 367.3999938964844 + + + + 119 + + + + + 368.20001220703125 + + + + 120 + + + + + 368.79998779296875 + + + + 120 + + + + + 369.3999938964844 + + + + 121 + + + + + 369.79998779296875 + + + + 121 + + + + + 370.79998779296875 + + + + 124 + + + + + 371.3999938964844 + + + + 126 + + + + + 371.3999938964844 + + + + 127 + + + + + 371.20001220703125 + + + + 130 + + + + + 371.3999938964844 + + + + 131 + + + + + 372.0 + + + + 132 + + + + + 372.20001220703125 + + + + 132 + + + + + 373.20001220703125 + + + + 132 + + + + + 374.3999938964844 + + + + 133 + + + + + 374.6000061035156 + + + + 133 + + + + + 374.79998779296875 + + + + 134 + + + + + 375.6000061035156 + + + + 134 + + + + + 376.6000061035156 + + + + 135 + + + + + 377.20001220703125 + + + + 137 + + + + + 377.3999938964844 + + + + 137 + + + + + 378.0 + + + + 138 + + + + + 378.20001220703125 + + + + 139 + + + + + 378.3999938964844 + + + + 139 + + + + + 379.0 + + + + 141 + + + + + 379.0 + + + + 140 + + + + + 379.79998779296875 + + + + 140 + + + + + 380.3999938964844 + + + + 140 + + + + + 381.20001220703125 + + + + 140 + + + + + 381.6000061035156 + + + + 140 + + + + + 382.6000061035156 + + + + 140 + + + + + 383.6000061035156 + + + + 140 + + + + + 384.6000061035156 + + + + 140 + + + + + 385.3999938964844 + + + + 140 + + + + + 386.0 + + + + 140 + + + + + 386.3999938964844 + + + + 140 + + + + + 386.79998779296875 + + + + 140 + + + + + 384.3999938964844 + + + + 140 + + + + + 381.79998779296875 + + + + 138 + + + + + 380.20001220703125 + + + + 136 + + + + + 378.3999938964844 + + + + 135 + + + + + 377.20001220703125 + + + + 134 + + + + + 375.20001220703125 + + + + 132 + + + + + 374.3999938964844 + + + + 131 + + + + + 373.0 + + + + 129 + + + + + 371.20001220703125 + + + + 127 + + + + + 367.3999938964844 + + + + 125 + + + + + 365.0 + + + + 124 + + + + + 364.6000061035156 + + + + 124 + + + + + 364.20001220703125 + + + + 124 + + + + + 363.3999938964844 + + + + 122 + + + + + 362.79998779296875 + + + + 121 + + + + + 362.3999938964844 + + + + 120 + + + + + 361.3999938964844 + + + + 119 + + + + + 360.6000061035156 + + + + 117 + + + + + 360.3999938964844 + + + + 117 + + + + + 359.79998779296875 + + + + 116 + + + + + 359.6000061035156 + + + + 116 + + + + + 359.6000061035156 + + + + 116 + + + + + 359.3999938964844 + + + + 118 + + + + + 359.3999938964844 + + + + 119 + + + + + 359.20001220703125 + + + + 121 + + + + + 359.0 + + + + 121 + + + + + 358.79998779296875 + + + + 121 + + + + + 358.79998779296875 + + + + 124 + + + + + 358.6000061035156 + + + + 124 + + + + + 358.0 + + + + 126 + + + + + 356.79998779296875 + + + + 126 + + + + + 356.20001220703125 + + + + 126 + + + + + 355.79998779296875 + + + + 125 + + + + + 355.6000061035156 + + + + 125 + + + + + 355.3999938964844 + + + + 123 + + + + + 355.0 + + + + 120 + + + + + 354.79998779296875 + + + + 119 + + + + + 354.6000061035156 + + + + 120 + + + + + 354.20001220703125 + + + + 120 + + + + + 353.6000061035156 + + + + 122 + + + + + 352.79998779296875 + + + + 121 + + + + + 352.3999938964844 + + + + 119 + + + + + 352.0 + + + + 119 + + + + + 351.6000061035156 + + + + 120 + + + + + 351.3999938964844 + + + + 121 + + + + + 351.20001220703125 + + + + 122 + + + + + 350.79998779296875 + + + + 123 + + + + + 350.6000061035156 + + + + 123 + + + + + 350.6000061035156 + + + + 124 + + + + + 351.0 + + + + 124 + + + + + 351.79998779296875 + + + + 124 + + + + + 352.3999938964844 + + + + 123 + + + + + 352.6000061035156 + + + + 124 + + + + + 352.20001220703125 + + + + 125 + + + + + 351.6000061035156 + + + + 125 + + + + + 351.0 + + + + 127 + + + + + 351.20001220703125 + + + + 127 + + + + + 351.6000061035156 + + + + 127 + + + + + 352.0 + + + + 126 + + + + + 352.6000061035156 + + + + 126 + + + + + 353.20001220703125 + + + + 126 + + + + + 353.6000061035156 + + + + 125 + + + + + 353.6000061035156 + + + + 125 + + + + + 353.6000061035156 + + + + 126 + + + + + 353.6000061035156 + + + + 125 + + + + + 353.6000061035156 + + + + 125 + + + + + 353.79998779296875 + + + + 125 + + + + + 354.20001220703125 + + + + 125 + + + + + 355.6000061035156 + + + + 125 + + + + + 356.3999938964844 + + + + 124 + + + + + 357.0 + + + + 124 + + + + + 359.79998779296875 + + + + 122 + + + + + 362.20001220703125 + + + + 122 + + + + + 363.3999938964844 + + + + 121 + + + + + 363.3999938964844 + + + + 120 + + + + + 363.79998779296875 + + + + 120 + + + + + 363.6000061035156 + + + + 119 + + + + + 363.79998779296875 + + + + 118 + + + + + 363.79998779296875 + + + + 115 + + + + + 364.0 + + + + 112 + + + + + 364.20001220703125 + + + + 115 + + + + + 364.3999938964844 + + + + 116 + + + + + 364.6000061035156 + + + + 119 + + + + + 364.79998779296875 + + + + 120 + + + + + 365.3999938964844 + + + + 123 + + + + + 365.6000061035156 + + + + 124 + + + + + 366.6000061035156 + + + + 127 + + + + + 367.20001220703125 + + + + 128 + + + + + 367.3999938964844 + + + + 128 + + + + + 367.79998779296875 + + + + 129 + + + + + 368.0 + + + + 129 + + + + + 368.6000061035156 + + + + 129 + + + + + 369.0 + + + + 129 + + + + + 370.20001220703125 + + + + 130 + + + + + 371.6000061035156 + + + + 133 + + + + + 371.79998779296875 + + + + 133 + + + + + 372.6000061035156 + + + + 135 + + + + + 373.20001220703125 + + + + 137 + + + + + 373.20001220703125 + + + + 138 + + + + + 373.20001220703125 + + + + 138 + + + + + 373.3999938964844 + + + + 139 + + + + + 373.0 + + + + 139 + + + + + 373.0 + + + + 139 + + + + + 373.0 + + + + 139 + + + + + 373.0 + + + + 138 + + + + + 372.79998779296875 + + + + 138 + + + + + 372.3999938964844 + + + + 136 + + + + + 372.20001220703125 + + + + 136 + + + + + 372.3999938964844 + + + + 135 + + + + + 372.79998779296875 + + + + 134 + + + + + 373.20001220703125 + + + + 134 + + + + + 375.6000061035156 + + + + 133 + + + + + 377.0 + + + + 133 + + + + + 378.0 + + + + 133 + + + + + 378.6000061035156 + + + + 133 + + + + + 379.0 + + + + 133 + + + + + 378.6000061035156 + + + + 135 + + + + + 378.20001220703125 + + + + 135 + + + + + 377.6000061035156 + + + + 135 + + + + + 377.20001220703125 + + + + 135 + + + + + 376.6000061035156 + + + + 135 + + + + + 376.6000061035156 + + + + 135 + + + + + 376.79998779296875 + + + + 134 + + + + + 376.79998779296875 + + + + 134 + + + + + 376.79998779296875 + + + + 133 + + + + + 376.20001220703125 + + + + 132 + + + + + 376.20001220703125 + + + + 132 + + + + + 376.0 + + + + 131 + + + + + 375.6000061035156 + + + + 132 + + + + + 375.6000061035156 + + + + 132 + + + + + 375.79998779296875 + + + + 133 + + + + + 376.0 + + + + 133 + + + + + 376.79998779296875 + + + + 133 + + + + + 377.6000061035156 + + + + 134 + + + + + 377.79998779296875 + + + + 134 + + + + + 377.79998779296875 + + + + 134 + + + + + 377.79998779296875 + + + + 135 + + + + + 378.0 + + + + 136 + + + + + 378.3999938964844 + + + + 136 + + + + + 378.3999938964844 + + + + 137 + + + + + 378.3999938964844 + + + + 139 + + + + + 378.20001220703125 + + + + 140 + + + + + 378.3999938964844 + + + + 140 + + + + + 378.6000061035156 + + + + 142 + + + + + 378.6000061035156 + + + + 142 + + + + + 379.6000061035156 + + + + 143 + + + + + 379.79998779296875 + + + + 143 + + + + + 379.79998779296875 + + + + 143 + + + + + 379.6000061035156 + + + + 143 + + + + + 379.6000061035156 + + + + 143 + + + + + 380.20001220703125 + + + + 142 + + + + + 380.6000061035156 + + + + 142 + + + + + 381.20001220703125 + + + + 141 + + + + + 381.79998779296875 + + + + 141 + + + + + 381.79998779296875 + + + + 141 + + + + + 382.79998779296875 + + + + 141 + + + + + 383.3999938964844 + + + + 141 + + + + + 384.20001220703125 + + + + 142 + + + + + 384.6000061035156 + + + + 143 + + + + + 385.6000061035156 + + + + 143 + + + + + 386.6000061035156 + + + + 143 + + + + + 388.20001220703125 + + + + 142 + + + + + 388.6000061035156 + + + + 142 + + + + + 389.20001220703125 + + + + 142 + + + + + 389.79998779296875 + + + + 142 + + + + + 390.3999938964844 + + + + 141 + + + + + 391.6000061035156 + + + + 141 + + + + + 391.79998779296875 + + + + 140 + + + + + 391.20001220703125 + + + + 139 + + + + + 390.3999938964844 + + + + 138 + + + + + 389.0 + + + + 137 + + + + + 388.20001220703125 + + + + 136 + + + + + 388.3999938964844 + + + + 135 + + + + + 389.0 + + + + 136 + + + + + 389.3999938964844 + + + + 135 + + + + + 389.6000061035156 + + + + 135 + + + + + 390.20001220703125 + + + + 134 + + + + + 390.6000061035156 + + + + 134 + + + + + 391.20001220703125 + + + + 134 + + + + + 392.20001220703125 + + + + 133 + + + + + 393.20001220703125 + + + + 133 + + + + + 393.3999938964844 + + + + 133 + + + + + 394.20001220703125 + + + + 134 + + + + + 395.0 + + + + 134 + + + + + 395.6000061035156 + + + + 134 + + + + + 396.20001220703125 + + + + 136 + + + + + 396.3999938964844 + + + + 136 + + + + + 397.0 + + + + 137 + + + + + 397.79998779296875 + + + + 137 + + + + + 398.3999938964844 + + + + 138 + + + + + 399.20001220703125 + + + + 139 + + + + + 400.20001220703125 + + + + 139 + + + + + 400.6000061035156 + + + + 139 + + + + + 401.3999938964844 + + + + 140 + + + + + 402.20001220703125 + + + + 140 + + + + + 403.0 + + + + 141 + + + + + 403.20001220703125 + + + + 142 + + + + + 403.3999938964844 + + + + 142 + + + + + 405.3999938964844 + + + + 142 + + + + + 407.3999938964844 + + + + 142 + + + + + 410.3999938964844 + + + + 141 + + + + + 412.20001220703125 + + + + 142 + + + + + 415.3999938964844 + + + + 143 + + + + + 417.6000061035156 + + + + 144 + + + + + 419.0 + + + + 146 + + + + + 421.20001220703125 + + + + 147 + + + + + 422.0 + + + + 147 + + + + + 422.20001220703125 + + + + 147 + + + + + 422.79998779296875 + + + + 147 + + + + + 423.0 + + + + 147 + + + + + 423.79998779296875 + + + + 147 + + + + + 424.20001220703125 + + + + 147 + + + + + 425.0 + + + + 147 + + + + + 425.20001220703125 + + + + 147 + + + + + 425.6000061035156 + + + + 147 + + + + + 426.20001220703125 + + + + 146 + + + + + 426.20001220703125 + + + + 146 + + + + + 426.3999938964844 + + + + 146 + + + + + 426.6000061035156 + + + + 146 + + + + + 426.79998779296875 + + + + 146 + + + + + 427.20001220703125 + + + + 145 + + + + + 427.3999938964844 + + + + 144 + + + + + 428.3999938964844 + + + + 145 + + + + + 429.20001220703125 + + + + 144 + + + + + 430.0 + + + + 144 + + + + + 430.3999938964844 + + + + 144 + + + + + 431.20001220703125 + + + + 144 + + + + + 432.20001220703125 + + + + 144 + + + + + 432.3999938964844 + + + + 144 + + + + + 433.0 + + + + 144 + + + + + 433.20001220703125 + + + + 144 + + + + + 434.0 + + + + 144 + + + + + 435.0 + + + + 144 + + + + + 436.0 + + + + 144 + + + + + 436.3999938964844 + + + + 144 + + + + + 436.6000061035156 + + + + 143 + + + + + 437.0 + + + + 143 + + + + + 437.6000061035156 + + + + 143 + + + + + 437.79998779296875 + + + + 142 + + + + + 438.0 + + + + 142 + + + + + 438.3999938964844 + + + + 141 + + + + + 438.6000061035156 + + + + 141 + + + + + 438.79998779296875 + + + + 141 + + + + + 439.20001220703125 + + + + 141 + + + + + 439.6000061035156 + + + + 141 + + + + + 440.20001220703125 + + + + 141 + + + + + 440.3999938964844 + + + + 141 + + + + + 441.20001220703125 + + + + 140 + + + + + 441.20001220703125 + + + + 140 + + + + + 441.20001220703125 + + + + 138 + + + + + 441.3999938964844 + + + + 137 + + + + + 441.20001220703125 + + + + 137 + + + + + 442.20001220703125 + + + + 136 + + + + + 442.79998779296875 + + + + 135 + + + + + 443.0 + + + + 135 + + + + + 443.6000061035156 + + + + 137 + + + + + 444.20001220703125 + + + + 139 + + + + + 444.3999938964844 + + + + 139 + + + + + 445.20001220703125 + + + + 140 + + + + + 445.20001220703125 + + + + 141 + + + + + 445.3999938964844 + + + + 142 + + + + + 445.20001220703125 + + + + 142 + + + + + 445.0 + + + + 142 + + + + + 444.79998779296875 + + + + 142 + + + + + 444.6000061035156 + + + + 141 + + + + + 445.20001220703125 + + + + 141 + + + + + 446.20001220703125 + + + + 140 + + + + + 446.3999938964844 + + + + 141 + + + + + 446.3999938964844 + + + + 140 + + + + + 446.3999938964844 + + + + 141 + + + + + 446.79998779296875 + + + + 140 + + + + + 447.0 + + + + 139 + + + + + 447.0 + + + + 138 + + + + + 447.0 + + + + 138 + + + + + 446.79998779296875 + + + + 138 + + + + + 446.79998779296875 + + + + 138 + + + + + 446.6000061035156 + + + + 137 + + + + + 446.20001220703125 + + + + 134 + + + + + 446.0 + + + + 134 + + + + + 445.79998779296875 + + + + 134 + + + + + 446.0 + + + + 134 + + + + + 445.79998779296875 + + + + 133 + + + + + 445.79998779296875 + + + + 130 + + + + + 445.79998779296875 + + + + 127 + + + + + 445.79998779296875 + + + + 123 + + + + + 446.0 + + + + 120 + + + + + 446.20001220703125 + + + + 117 + + + + + 446.20001220703125 + + + + 114 + + + + + 446.0 + + + + 117 + + + + + 446.0 + + + + 114 + + + + + 445.79998779296875 + + + + 111 + + + + + 445.79998779296875 + + + + 108 + + + + + 446.0 + + + + 111 + + + + + 445.79998779296875 + + + + 107 + + + + + 445.79998779296875 + + + + 105 + + + + + 445.79998779296875 + + + + 107 + + + + + 445.79998779296875 + + + + 109 + + + + + 445.79998779296875 + + + + 109 + + + + + 445.20001220703125 + + + + 110 + + + + + 444.3999938964844 + + + + 111 + + + + + 444.0 + + + + 112 + + + + + 443.79998779296875 + + + + 114 + + + + + 443.6000061035156 + + + + 115 + + + + + 443.3999938964844 + + + + 116 + + + + + 443.20001220703125 + + + + 117 + + + + + 443.0 + + + + 117 + + + + + 443.0 + + + + 119 + + + + + 443.20001220703125 + + + + 120 + + + + + 443.6000061035156 + + + + 121 + + + + + 443.6000061035156 + + + + 121 + + + + + 444.0 + + + + 121 + + + + + 444.20001220703125 + + + + 122 + + + + + 444.20001220703125 + + + + 122 + + + + + 444.79998779296875 + + + + 123 + + + + + 445.6000061035156 + + + + 124 + + + + + 447.3999938964844 + + + + 125 + + + + + 449.20001220703125 + + + + 127 + + + + + 450.20001220703125 + + + + 127 + + + + + 451.20001220703125 + + + + 127 + + + + + 451.79998779296875 + + + + 128 + + + + + 451.79998779296875 + + + + 129 + + + + + 452.0 + + + + 129 + + + + + 451.79998779296875 + + + + 130 + + + + + 452.0 + + + + 131 + + + + + 452.79998779296875 + + + + 132 + + + + + 453.20001220703125 + + + + 132 + + + + + 453.20001220703125 + + + + 133 + + + + + 453.0 + + + + 134 + + + + + 452.3999938964844 + + + + 135 + + + + + 451.0 + + + + 136 + + + + + 449.20001220703125 + + + + 136 + + + + + 448.3999938964844 + + + + 136 + + + + + 448.20001220703125 + + + + 136 + + + + + 448.20001220703125 + + + + 136 + + + + + 448.20001220703125 + + + + 135 + + + + + 448.20001220703125 + + + + 134 + + + + + 448.20001220703125 + + + + 133 + + + + + 448.20001220703125 + + + + 132 + + + + + 448.20001220703125 + + + + 132 + + + + + 448.3999938964844 + + + + 133 + + + + + 448.3999938964844 + + + + 132 + + + + + 448.79998779296875 + + + + 134 + + + + + 449.0 + + + + 134 + + + + + 449.3999938964844 + + + + 135 + + + + + 449.6000061035156 + + + + 136 + + + + + 449.79998779296875 + + + + 137 + + + + + 450.0 + + + + 137 + + + + + 450.79998779296875 + + + + 138 + + + + + 452.20001220703125 + + + + 138 + + + + + 453.20001220703125 + + + + 137 + + + + + 454.20001220703125 + + + + 137 + + + + + 455.3999938964844 + + + + 136 + + + + + 456.20001220703125 + + + + 136 + + + + + 456.6000061035156 + + + + 136 + + + + + 456.0 + + + + 135 + + + + + 455.6000061035156 + + + + 134 + + + + + 455.0 + + + + 135 + + + + + 454.6000061035156 + + + + 135 + + + + + 453.79998779296875 + + + + 135 + + + + + 453.3999938964844 + + + + 136 + + + + + 451.3999938964844 + + + + 135 + + + + + 450.79998779296875 + + + + 135 + + + + + 450.20001220703125 + + + + 135 + + + + + 448.79998779296875 + + + + 135 + + + + + 446.79998779296875 + + + + 133 + + + + + 446.20001220703125 + + + + 133 + + + + + 444.79998779296875 + + + + 132 + + + + + 443.79998779296875 + + + + 130 + + + + + 443.79998779296875 + + + + 130 + + + + + 443.79998779296875 + + + + 130 + + + + + 443.79998779296875 + + + + 129 + + + + + 444.0 + + + + 128 + + + + + 444.20001220703125 + + + + 128 + + + + + 444.20001220703125 + + + + 128 + + + + + 444.0 + + + + 127 + + + + + 444.0 + + + + 127 + + + + + 444.0 + + + + 126 + + + + + 444.0 + + + + 126 + + + + + 444.0 + + + + 126 + + + + + 444.0 + + + + 127 + + + + + 443.6000061035156 + + + + 127 + + + + + 443.3999938964844 + + + + 127 + + + + + 443.20001220703125 + + + + 128 + + + + + 443.0 + + + + 128 + + + + + 442.6000061035156 + + + + 128 + + + + + 442.0 + + + + 129 + + + + + 441.79998779296875 + + + + 129 + + + + + 441.6000061035156 + + + + 129 + + + + + 441.6000061035156 + + + + 130 + + + + + 441.0 + + + + 130 + + + + + 440.79998779296875 + + + + 129 + + + + + 440.6000061035156 + + + + 130 + + + + + 440.20001220703125 + + + + 130 + + + + + 439.6000061035156 + + + + 130 + + + + + 439.3999938964844 + + + + 131 + + + + + 440.6000061035156 + + + + 130 + + + + + 441.6000061035156 + + + + 129 + + + + + 441.6000061035156 + + + + 129 + + + + + 441.20001220703125 + + + + 128 + + + + + 440.79998779296875 + + + + 128 + + + + + 440.3999938964844 + + + + 128 + + + + + 439.3999938964844 + + + + 127 + + + + + 439.6000061035156 + + + + 126 + + + + + 440.20001220703125 + + + + 126 + + + + + 441.0 + + + + 125 + + + + + 441.20001220703125 + + + + 125 + + + + + 442.0 + + + + 124 + + + + + 442.20001220703125 + + + + 124 + + + + + 442.20001220703125 + + + + 125 + + + + + 441.3999938964844 + + + + 125 + + + + + 442.79998779296875 + + + + 123 + + + + + 443.6000061035156 + + + + 123 + + + + + 443.79998779296875 + + + + 123 + + + + + 444.3999938964844 + + + + 125 + + + + + 444.20001220703125 + + + + 126 + + + + + 443.79998779296875 + + + + 126 + + + + + 443.3999938964844 + + + + 126 + + + + + 442.6000061035156 + + + + 126 + + + + + 441.79998779296875 + + + + 125 + + + + + 441.79998779296875 + + + + 125 + + + + + 441.0 + + + + 124 + + + + + 440.3999938964844 + + + + 124 + + + + + 439.3999938964844 + + + + 123 + + + + + 439.3999938964844 + + + + 124 + + + + + 440.0 + + + + 124 + + + + + 440.20001220703125 + + + + 124 + + + + + 440.20001220703125 + + + + 124 + + + + + 440.3999938964844 + + + + 124 + + + + + 440.6000061035156 + + + + 124 + + + + + 441.0 + + + + 124 + + + + + 441.20001220703125 + + + + 123 + + + + + 441.3999938964844 + + + + 124 + + + + + 441.3999938964844 + + + + 124 + + + + + 440.79998779296875 + + + + 125 + + + + + 440.3999938964844 + + + + 126 + + + + + 440.0 + + + + 126 + + + + + 440.0 + + + + 127 + + + + + 440.3999938964844 + + + + 128 + + + + + 440.6000061035156 + + + + 128 + + + + + 440.6000061035156 + + + + 129 + + + + + 440.0 + + + + 130 + + + + + 437.79998779296875 + + + + 130 + + + + + 435.6000061035156 + + + + 130 + + + + + 431.79998779296875 + + + + 128 + + + + + 426.79998779296875 + + + + 127 + + + + + 426.79998779296875 + + + + 125 + + + + + 426.79998779296875 + + + + 123 + + + + + 426.20001220703125 + + + + 120 + + + + + 426.0 + + + + 119 + + + + + 425.20001220703125 + + + + 118 + + + + + 424.6000061035156 + + + + 117 + + + + + 423.0 + + + + 116 + + + + + 422.6000061035156 + + + + 115 + + + + + 421.20001220703125 + + + + 113 + + + + + 419.20001220703125 + + + + 112 + + + + + 417.20001220703125 + + + + 112 + + + + + 416.79998779296875 + + + + 112 + + + + + 415.79998779296875 + + + + 111 + + + + + 414.0 + + + + 111 + + + + + 410.79998779296875 + + + + 111 + + + + + 409.79998779296875 + + + + 111 + + + + + 407.0 + + + + 111 + + + + + 405.20001220703125 + + + + 110 + + + + + 403.0 + + + + 110 + + + + + 402.6000061035156 + + + + 110 + + + + + 402.6000061035156 + + + + 110 + + + + + 402.20001220703125 + + + + 110 + + + + + 400.6000061035156 + + + + 110 + + + + + 400.0 + + + + 111 + + + + + 398.6000061035156 + + + + 110 + + + + + 397.6000061035156 + + + + 110 + + + + + 397.20001220703125 + + + + 111 + + + + + 398.6000061035156 + + + + 112 + + + + + 399.3999938964844 + + + + 113 + + + + + 400.20001220703125 + + + + 113 + + + + + 402.20001220703125 + + + + 114 + + + + + 402.3999938964844 + + + + 114 + + + + + 402.79998779296875 + + + + 113 + + + + + 402.6000061035156 + + + + 113 + + + + + 400.20001220703125 + + + + 112 + + + + + 395.6000061035156 + + + + 111 + + + + + 393.20001220703125 + + + + 110 + + + + + 391.20001220703125 + + + + 110 + + + + + 389.3999938964844 + + + + 110 + + + + + 389.0 + + + + 110 + + + + + 386.3999938964844 + + + + 110 + + + + + 384.6000061035156 + + + + 110 + + + + + 380.79998779296875 + + + + 110 + + + + + 380.3999938964844 + + + + 111 + + + + + 379.0 + + + + 111 + + + + + 378.3999938964844 + + + + 111 + + + + + 377.79998779296875 + + + + 111 + + + + + 376.20001220703125 + + + + 110 + + + + + 377.0 + + + + 111 + + + + + 378.3999938964844 + + + + 112 + + + + + 378.3999938964844 + + + + 113 + + + + + 378.79998779296875 + + + + 115 + + + + + 379.20001220703125 + + + + 117 + + + + + 379.79998779296875 + + + + 118 + + + + + 380.6000061035156 + + + + 121 + + + + + 380.6000061035156 + + + + 121 + + + + + 380.79998779296875 + + + + 122 + + + + + 381.0 + + + + 122 + + + + + 381.79998779296875 + + + + 124 + + + + + 383.20001220703125 + + + + 126 + + + + + 386.3999938964844 + + + + 127 + + + + + 387.3999938964844 + + + + 128 + + + + + 385.6000061035156 + + + + 129 + + + + + 383.3999938964844 + + + + 130 + + + + + 382.6000061035156 + + + + 130 + + + + + 380.6000061035156 + + + + 132 + + + + + 380.6000061035156 + + + + 133 + + + + + 380.20001220703125 + + + + 133 + + + + + 378.20001220703125 + + + + 133 + + + + + 376.79998779296875 + + + + 133 + + + + + 376.3999938964844 + + + + 133 + + + + + 376.20001220703125 + + + + 133 + + + + + 376.0 + + + + 133 + + + + + 375.6000061035156 + + + + 132 + + + + + 373.0 + + + + 131 + + + + + 370.6000061035156 + + + + 129 + + + + + 370.3999938964844 + + + + 127 + + + + + 370.0 + + + + 127 + + + + + 369.0 + + + + 126 + + + + + 367.6000061035156 + + + + 125 + + + + + 366.79998779296875 + + + + 124 + + + + + 364.79998779296875 + + + + 121 + + + + + 364.6000061035156 + + + + 121 + + + + + 362.79998779296875 + + + + 120 + + + + + 359.0 + + + + 117 + + + + + 358.79998779296875 + + + + 117 + + + + + 358.20001220703125 + + + + 115 + + + + + 356.0 + + + + 115 + + + + + 352.79998779296875 + + + + 113 + + + + + 352.6000061035156 + + + + 113 + + + + + 354.6000061035156 + + + + 112 + + + + + 353.6000061035156 + + + + 111 + + + + + 352.0 + + + + 112 + + + + + 350.20001220703125 + + + + 112 + + + + + 350.79998779296875 + + + + 115 + + + + + 349.3999938964844 + + + + 119 + + + + + 348.6000061035156 + + + + 120 + + + + + 347.20001220703125 + + + + 120 + + + + + 346.6000061035156 + + + + 119 + + + + + 347.20001220703125 + + + + 117 + + + + + 349.0 + + + + 116 + + + + + 350.0 + + + + 115 + + + + + 350.3999938964844 + + + + 115 + + + + + 347.20001220703125 + + + + 114 + + + + + 345.6000061035156 + + + + 114 + + + + + 343.20001220703125 + + + + 113 + + + + + 342.79998779296875 + + + + 113 + + + + + 340.79998779296875 + + + + 113 + + + + + 342.79998779296875 + + + + 112 + + + + + 342.3999938964844 + + + + 113 + + + + + 341.3999938964844 + + + + 114 + + + + + 344.0 + + + + 112 + + + + + 344.3999938964844 + + + + 112 + + + + + 344.79998779296875 + + + + 113 + + + + + 345.3999938964844 + + + + 113 + + + + + 346.0 + + + + 113 + + + + + 346.3999938964844 + + + + 113 + + + + + 345.6000061035156 + + + + 112 + + + + + 345.0 + + + + 111 + + + + + 344.0 + + + + 111 + + + + + 342.3999938964844 + + + + 111 + + + + + 342.20001220703125 + + + + 111 + + + + + 341.6000061035156 + + + + 111 + + + + + 340.79998779296875 + + + + 111 + + + + + 337.79998779296875 + + + + 112 + + + + + 335.79998779296875 + + + + 112 + + + + + 334.3999938964844 + + + + 112 + + + + + 334.20001220703125 + + + + 112 + + + + + 333.20001220703125 + + + + 112 + + + + + 330.20001220703125 + + + + 113 + + + + + 327.3999938964844 + + + + 112 + + + + + 326.79998779296875 + + + + 112 + + + + + 326.6000061035156 + + + + 111 + + + + + 324.20001220703125 + + + + 110 + + + + + 321.20001220703125 + + + + 109 + + + + + 320.0 + + + + 109 + + + + + 317.79998779296875 + + + + 110 + + + + + 317.6000061035156 + + + + 111 + + + + + 321.0 + + + + 111 + + + + + 320.79998779296875 + + + + 111 + + + + + 318.6000061035156 + + + + 110 + + + + + 316.79998779296875 + + + + 109 + + + + + 313.79998779296875 + + + + 107 + + + + + 313.6000061035156 + + + + 106 + + + + + 313.20001220703125 + + + + 106 + + + + + 313.79998779296875 + + + + 106 + + + + + 315.20001220703125 + + + + 105 + + + + + 315.20001220703125 + + + + 106 + + + + + 312.6000061035156 + + + + 107 + + + + + 312.3999938964844 + + + + 107 + + + + + 311.0 + + + + 107 + + + + + 307.3999938964844 + + + + 108 + + + + + 306.6000061035156 + + + + 109 + + + + + 304.79998779296875 + + + + 110 + + + + + 304.0 + + + + 109 + + + + + 302.79998779296875 + + + + 106 + + + + + 301.79998779296875 + + + + 105 + + + + + 302.79998779296875 + + + + 104 + + + + + 302.3999938964844 + + + + 104 + + + + + 302.20001220703125 + + + + 104 + + + + + 302.20001220703125 + + + + 104 + + + + + 302.6000061035156 + + + + 104 + + + + + 301.6000061035156 + + + + 104 + + + + + 298.0 + + + + 105 + + + + + 296.20001220703125 + + + + 104 + + + + + 294.6000061035156 + + + + 104 + + + + + 293.79998779296875 + + + + 104 + + + + + 293.79998779296875 + + + + 104 + + + + + 293.6000061035156 + + + + 104 + + + + + 290.20001220703125 + + + + 103 + + + + + 291.0 + + + + 102 + + + + + 290.3999938964844 + + + + 102 + + + + + 290.20001220703125 + + + + 103 + + + + + 291.6000061035156 + + + + 102 + + + + + 293.0 + + + + 101 + + + + + 292.20001220703125 + + + + 101 + + + + + 292.0 + + + + 101 + + + + + 291.6000061035156 + + + + 100 + + + + + 291.3999938964844 + + + + 99 + + + + + 290.3999938964844 + + + + 99 + + + + + 288.0 + + + + 99 + + + + + 286.0 + + + + 99 + + + + + 279.79998779296875 + + + + 100 + + + + + 278.6000061035156 + + + + 100 + + + + + 277.3999938964844 + + + + 99 + + + + + 273.20001220703125 + + + + 100 + + + + + 272.20001220703125 + + + + 100 + + + + + 271.6000061035156 + + + + 101 + + + + + 271.6000061035156 + + + + 102 + + + + + 270.79998779296875 + + + + 102 + + + + + 271.0 + + + + 102 + + + + + 272.0 + + + + 102 + + + + + 273.6000061035156 + + + + 102 + + + + + 274.20001220703125 + + + + 101 + + + + + 272.0 + + + + 101 + + + + + 270.0 + + + + 100 + + + + + 267.6000061035156 + + + + 100 + + + + + 265.20001220703125 + + + + 99 + + + + + 262.0 + + + + 99 + + + + + 260.6000061035156 + + + + 99 + + + + + 259.6000061035156 + + + + 98 + + + + + 258.20001220703125 + + + + 100 + + + + + 257.3999938964844 + + + + 102 + + + + + 257.20001220703125 + + + + 102 + + + + + 257.79998779296875 + + + + 102 + + + + + 258.79998779296875 + + + + 102 + + + + + 260.6000061035156 + + + + 103 + + + + + 261.3999938964844 + + + + 101 + + + + + 258.79998779296875 + + + + 100 + + + + + 258.0 + + + + 100 + + + + + 255.8000030517578 + + + + 100 + + + + + 253.60000610351562 + + + + 100 + + + + + 250.60000610351562 + + + + 99 + + + + + 249.60000610351562 + + + + 99 + + + + + 249.39999389648438 + + + + 99 + + + + + 248.8000030517578 + + + + 100 + + + + + 247.8000030517578 + + + + 99 + + + + + 247.0 + + + + 99 + + + + + 246.60000610351562 + + + + 100 + + + + + 246.1999969482422 + + + + 99 + + + + + 246.1999969482422 + + + + 99 + + + + + 245.39999389648438 + + + + 103 + + + + + 245.39999389648438 + + + + 104 + + + + + 245.0 + + + + 107 + + + + + 243.8000030517578 + + + + 109 + + + + + 241.8000030517578 + + + + 109 + + + + + 241.1999969482422 + + + + 109 + + + + + 241.1999969482422 + + + + 110 + + + + + 240.60000610351562 + + + + 110 + + + + + 240.8000030517578 + + + + 112 + + + + + 240.8000030517578 + + + + 112 + + + + + 238.60000610351562 + + + + 112 + + + + + 237.1999969482422 + + + + 111 + + + + + 237.1999969482422 + + + + 111 + + + + + 237.8000030517578 + + + + 111 + + + + + 238.1999969482422 + + + + 112 + + + + + 239.0 + + + + 112 + + + + + 238.8000030517578 + + + + 110 + + + + + 238.0 + + + + 110 + + + + + 237.60000610351562 + + + + 110 + + + + + 236.39999389648438 + + + + 107 + + + + + 235.60000610351562 + + + + 106 + + + + + 234.60000610351562 + + + + 106 + + + + + 231.60000610351562 + + + + 104 + + + + + 228.60000610351562 + + + + 105 + + + + + 225.1999969482422 + + + + 103 + + + + + 223.0 + + + + 103 + + + + + 222.0 + + + + 104 + + + + + 221.1999969482422 + + + + 105 + + + + + 219.39999389648438 + + + + 102 + + + + + 219.1999969482422 + + + + 102 + + + + + 217.0 + + + + 102 + + + + + 215.8000030517578 + + + + 102 + + + + + 214.60000610351562 + + + + 103 + + + + + 213.60000610351562 + + + + 104 + + + + + 212.39999389648438 + + + + 102 + + + + + 212.1999969482422 + + + + 102 + + + + + 211.39999389648438 + + + + 103 + + + + + 210.39999389648438 + + + + 101 + + + + + 208.8000030517578 + + + + 100 + + + + + 207.39999389648438 + + + + 99 + + + + + 205.60000610351562 + + + + 100 + + + + + 204.1999969482422 + + + + 100 + + + + + 203.0 + + + + 99 + + + + + 202.0 + + + + 98 + + + + + 201.39999389648438 + + + + 99 + + + + + 201.39999389648438 + + + + 99 + + + + + 200.1999969482422 + + + + 101 + + + + + 200.1999969482422 + + + + 102 + + + + + 199.60000610351562 + + + + 102 + + + + + 197.39999389648438 + + + + 103 + + + + + 194.39999389648438 + + + + 104 + + + + + 191.39999389648438 + + + + 104 + + + + + 191.0 + + + + 103 + + + + + 189.8000030517578 + + + + 101 + + + + + 187.0 + + + + 101 + + + + + 184.60000610351562 + + + + 100 + + + + + 183.60000610351562 + + + + 100 + + + + + 183.39999389648438 + + + + 100 + + + + + 181.8000030517578 + + + + 99 + + + + + 181.60000610351562 + + + + 99 + + + + + 181.60000610351562 + + + + 96 + + + + + 181.60000610351562 + + + + 99 + + + + + 181.60000610351562 + + + + 102 + + + + + 181.39999389648438 + + + + 102 + + + + + 181.60000610351562 + + + + 105 + + + + + 181.8000030517578 + + + + 100 + + + + + 181.8000030517578 + + + + 97 + + + + + 181.8000030517578 + + + + 97 + + + + + 181.39999389648438 + + + + 94 + + + + + 181.39999389648438 + + + + 91 + + + + + 181.1999969482422 + + + + 94 + + + + + 181.39999389648438 + + + + 97 + + + + + 181.1999969482422 + + + + 100 + + + + + 181.39999389648438 + + + + 101 + + + + + 181.39999389648438 + + + + 97 + + + + + 181.39999389648438 + + + + 100 + + + + + 181.60000610351562 + + + + 97 + + + + + 181.60000610351562 + + + + 94 + + + + + 181.39999389648438 + + + + 95 + + + + + 181.0 + + + + 98 + + + + + 181.0 + + + + 100 + + + + + 180.8000030517578 + + + + 103 + + + + + 180.8000030517578 + + + + 106 + + + + + 180.8000030517578 + + + + 107 + + + + + 181.1999969482422 + + + + 110 + + + + + 181.0 + + + + 113 + + + + + 181.1999969482422 + + + + 110 + + + + + 181.1999969482422 + + + + 107 + + + + + 180.60000610351562 + + + + 109 + + + + + 180.1999969482422 + + + + 106 + + + + + 179.39999389648438 + + + + 105 + + + + + 176.8000030517578 + + + + 104 + + + + + 176.0 + + + + 103 + + + + + 174.8000030517578 + + + + 102 + + + + + 173.0 + + + + 102 + + + + + 172.1999969482422 + + + + 102 + + + + + 171.8000030517578 + + + + 102 + + + + + 172.0 + + + + 103 + + + + + 172.60000610351562 + + + + 103 + + + + + 173.60000610351562 + + + + 102 + + + + + 175.0 + + + + 103 + + + + + 175.39999389648438 + + + + 102 + + + + + 176.0 + + + + 101 + + + + + 176.8000030517578 + + + + 101 + + + + + 177.39999389648438 + + + + 101 + + + + + 177.39999389648438 + + + + 104 + + + + + 177.1999969482422 + + + + 107 + + + + + 176.39999389648438 + + + + 110 + + + + + 176.0 + + + + 112 + + + + + 176.0 + + + + 113 + + + + + 175.39999389648438 + + + + 115 + + + + + 174.8000030517578 + + + + 118 + + + + + 175.60000610351562 + + + + 119 + + + + + 177.1999969482422 + + + + 118 + + + + + 177.60000610351562 + + + + 119 + + + + + 177.39999389648438 + + + + 119 + + + + + 177.39999389648438 + + + + 122 + + + + + 177.1999969482422 + + + + 124 + + + + + 177.1999969482422 + + + + 124 + + + + + 176.39999389648438 + + + + 124 + + + + + 175.39999389648438 + + + + 123 + + + + + 174.60000610351562 + + + + 124 + + + + + 174.0 + + + + 125 + + + + + 173.60000610351562 + + + + 125 + + + + + 172.8000030517578 + + + + 124 + + + + + 172.39999389648438 + + + + 125 + + + + + 171.8000030517578 + + + + 125 + + + + + 170.8000030517578 + + + + 127 + + + + + 170.39999389648438 + + + + 126 + + + + + 169.8000030517578 + + + + 126 + + + + + 169.1999969482422 + + + + 127 + + + + + 168.8000030517578 + + + + 127 + + + + + 169.0 + + + + 127 + + + + + 169.60000610351562 + + + + 128 + + + + + 170.0 + + + + 127 + + + + + 170.1999969482422 + + + + 127 + + + + + 171.0 + + + + 128 + + + + + 171.60000610351562 + + + + 128 + + + + + 171.0 + + + + 129 + + + + + 170.39999389648438 + + + + 129 + + + + + 170.0 + + + + 130 + + + + + 169.8000030517578 + + + + 131 + + + + + 169.39999389648438 + + + + 133 + + + + + 169.0 + + + + 133 + + + + + 168.39999389648438 + + + + 133 + + + + + 167.60000610351562 + + + + 133 + + + + + 166.8000030517578 + + + + 134 + + + + + 167.0 + + + + 135 + + + + + 167.60000610351562 + + + + 137 + + + + + 168.39999389648438 + + + + 137 + + + + + 169.1999969482422 + + + + 137 + + + + + 170.0 + + + + 137 + + + + + 170.39999389648438 + + + + 134 + + + + + 170.39999389648438 + + + + 134 + + + + + 170.8000030517578 + + + + 131 + + + + + 170.8000030517578 + + + + 131 + + + + + 171.0 + + + + 130 + + + + + 171.0 + + + + 127 + + + + + 170.8000030517578 + + + + 124 + + + + + 170.8000030517578 + + + + 123 + + + + + 171.0 + + + + 120 + + + + + 171.1999969482422 + + + + 118 + + + + + 171.60000610351562 + + + + 121 + + + + + 171.60000610351562 + + + + 122 + + + + + 172.0 + + + + 125 + + + + + 172.0 + + + + 126 + + + + + 172.1999969482422 + + + + 128 + + + + + 172.60000610351562 + + + + 127 + + + + + 173.0 + + + + 127 + + + + + 173.8000030517578 + + + + 129 + + + + + 174.60000610351562 + + + + 128 + + + + + 175.1999969482422 + + + + 125 + + + + + 175.39999389648438 + + + + 125 + + + + + 176.0 + + + + 122 + + + + + 176.39999389648438 + + + + 121 + + + + + 177.1999969482422 + + + + 120 + + + + + 177.60000610351562 + + + + 120 + + + + + 178.1999969482422 + + + + 118 + + + + + 179.0 + + + + 118 + + + + + 179.8000030517578 + + + + 115 + + + + + 179.60000610351562 + + + + 115 + + + + + 179.1999969482422 + + + + 114 + + + + + 178.8000030517578 + + + + 113 + + + + + 178.60000610351562 + + + + 111 + + + + + 178.39999389648438 + + + + 109 + + + + + 178.1999969482422 + + + + 118 + + + + + 178.1999969482422 + + + + 118 + + + + + 178.1999969482422 + + + + 115 + + + + + 178.1999969482422 + + + + 111 + + + + + 178.0 + + + + 108 + + + + + 178.0 + + + + 105 + + + + + 178.0 + + + + 105 + + + + + 178.0 + + + + 104 + + + + + 178.0 + + + + 104 + + + + + 178.0 + + + + 104 + + + + + 178.1999969482422 + + + + 102 + + + + + 178.1999969482422 + + + + 103 + + + + + 178.1999969482422 + + + + 103 + + + + + 178.1999969482422 + + + + 105 + + + + + 178.1999969482422 + + + + 105 + + + + + 178.1999969482422 + + + + 106 + + + + + 178.1999969482422 + + + + 105 + + + + + 178.39999389648438 + + + + 106 + + + + + 178.39999389648438 + + + + 102 + + + + + 178.39999389648438 + + + + 97 + + + + + 178.39999389648438 + + + + 94 + + + + + 178.39999389648438 + + + + 91 + + + + + 178.39999389648438 + + + + 94 + + + + + 178.39999389648438 + + + + 97 + + + + + 178.39999389648438 + + + + 99 + + + + + 178.39999389648438 + + + + 102 + + + + + 178.39999389648438 + + + + 104 + + + + + 178.60000610351562 + + + + 101 + + + + + 178.60000610351562 + + + + 101 + + + + + 178.60000610351562 + + + + 99 + + + + + 178.8000030517578 + + + + 97 + + + + + 178.60000610351562 + + + + 98 + + + + + 178.39999389648438 + + + + 97 + + + + + 178.1999969482422 + + + + 97 + + + + + 178.1999969482422 + + + + 96 + + + + + 178.1999969482422 + + + + 94 + + + + + 178.1999969482422 + + + + 91 + + + + + + diff --git a/Source/Examples/WPF/DemoCore/BitmapTools.cs b/Source/Examples/WPF/DemoCore/BitmapTools.cs new file mode 100644 index 000000000..36086bfca --- /dev/null +++ b/Source/Examples/WPF/DemoCore/BitmapTools.cs @@ -0,0 +1,18 @@ +namespace DemoCore +{ + using System.Drawing; + using System.Drawing.Drawing2D; + + public static class BitmapTools + { + public static Bitmap Resize(Bitmap bitmap, int newWidth, int newHeight) + { + var resizedBitmap = new Bitmap(newWidth, newHeight); + var g = Graphics.FromImage(resizedBitmap); + g.InterpolationMode = InterpolationMode.HighQualityBicubic; + g.DrawImage(bitmap, 0, 0, newWidth, newHeight); + g.Dispose(); + return resizedBitmap; + } + } +} \ No newline at end of file diff --git a/Source/Examples/WPF/DemoCore/DelegateCommand.cs b/Source/Examples/WPF/DemoCore/DelegateCommand.cs new file mode 100644 index 000000000..16f3e7155 --- /dev/null +++ b/Source/Examples/WPF/DemoCore/DelegateCommand.cs @@ -0,0 +1,125 @@ +// -------------------------------------------------------------------------------------------------------------------- +// +// The MIT License (MIT) +// +// Copyright (c) 2014 OxyPlot contributors +// +// Permission is hereby granted, free of charge, to any person obtaining a +// copy of this software and associated documentation files (the +// "Software"), to deal in the Software without restriction, including +// without limitation the rights to use, copy, modify, merge, publish, +// distribute, sublicense, and/or sell copies of the Software, and to +// permit persons to whom the Software is furnished to do so, subject to +// the following conditions: +// +// The above copyright notice and this permission notice shall be included +// in all copies or substantial portions of the Software. +// +// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS +// OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF +// MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. +// IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY +// CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, +// TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE +// SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. +// +// +// Represents a delegate command. +// +// -------------------------------------------------------------------------------------------------------------------- + +namespace DemoCore +{ + using System; + using System.Windows.Input; + + /// + /// Represents a delegate command. + /// + public class DelegateCommand : ICommand + { + /// + /// The can execute. + /// + private readonly Func canExecute; + + /// + /// The execute. + /// + private readonly Action execute; + + /// + /// Initializes a new instance of the class. + /// + /// The execute. + public DelegateCommand(Action execute) + : this(execute, null) + { + } + + /// + /// Initializes a new instance of the class. + /// + /// The execute. + /// The can execute. + public DelegateCommand(Action execute, Func canExecute) + { + if (execute == null) + { + throw new ArgumentNullException("execute"); + } + + this.execute = execute; + this.canExecute = canExecute; + } + + /// + /// Occurs when changes occur that affect whether or not the command should execute. + /// + public event EventHandler CanExecuteChanged + { + add + { + if (this.canExecute != null) + { + CommandManager.RequerySuggested += value; + } + } + + remove + { + if (this.canExecute != null) + { + CommandManager.RequerySuggested -= value; + } + } + } + + /// + /// Defines the method that determines whether the command can execute in its current state. + /// + /// Data used by the command. If the command does not require data to be passed, this object can be set to null. + /// true if this command can be executed; otherwise, false. + public bool CanExecute(object parameter) + { + return this.canExecute == null || this.canExecute(); + } + + /// + /// Defines the method to be called when the command is invoked. + /// + /// Data used by the command. If the command does not require data to be passed, this object can be set to null. + public void Execute(object parameter) + { + this.execute(); + } + + /// + /// Raises the can execute changed. + /// + public void RaiseCanExecuteChanged() + { + CommandManager.InvalidateRequerySuggested(); + } + } +} \ No newline at end of file diff --git a/Source/Examples/WPF/DemoCore/DemoCore.csproj b/Source/Examples/WPF/DemoCore/DemoCore.csproj new file mode 100644 index 000000000..a37127aa1 --- /dev/null +++ b/Source/Examples/WPF/DemoCore/DemoCore.csproj @@ -0,0 +1,12 @@ + + + + net47 + + + + + + + + \ No newline at end of file diff --git a/Source/Examples/WPF/DemoCore/Example.cs b/Source/Examples/WPF/DemoCore/Example.cs new file mode 100644 index 000000000..438f45b90 --- /dev/null +++ b/Source/Examples/WPF/DemoCore/Example.cs @@ -0,0 +1,77 @@ +// -------------------------------------------------------------------------------------------------------------------- +// +// The MIT License (MIT) +// +// Copyright (c) 2014 OxyPlot contributors +// +// Permission is hereby granted, free of charge, to any person obtaining a +// copy of this software and associated documentation files (the +// "Software"), to deal in the Software without restriction, including +// without limitation the rights to use, copy, modify, merge, publish, +// distribute, sublicense, and/or sell copies of the Software, and to +// permit persons to whom the Software is furnished to do so, subject to +// the following conditions: +// +// The above copyright notice and this permission notice shall be included +// in all copies or substantial portions of the Software. +// +// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS +// OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF +// MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. +// IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY +// CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, +// TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE +// SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. +// +// -------------------------------------------------------------------------------------------------------------------- + +namespace DemoCore +{ + using System; + using System.Diagnostics; + using System.Windows; + using System.Windows.Media; + using System.Windows.Media.Imaging; + + public class Demo + { + public Demo(Type mainWindowType, string title = null, string description = null) + { + this.MainWindowType = mainWindowType; + this.Title = title ?? mainWindowType.Namespace; + this.Description = description; + try + { + this.Thumbnail = new BitmapImage(new Uri("pack://application:,,,/Images/" + this.ThumbnailFileName)); + } + catch (Exception e) + { + Debug.WriteLine(e); + } + } + + public string Title { get; private set; } + public string Description { get; set; } + private Type MainWindowType { get; set; } + + public ImageSource Thumbnail { get; set; } + + public string ThumbnailFileName + { + get + { + return this.MainWindowType.Namespace + ".png"; + } + } + + public override string ToString() + { + return this.Title; + } + + public Window Create() + { + return Activator.CreateInstance(this.MainWindowType) as Window; + } + } +} diff --git a/Source/Examples/WPF/DemoCore/ExampleAttribute.cs b/Source/Examples/WPF/DemoCore/ExampleAttribute.cs new file mode 100644 index 000000000..340bf2113 --- /dev/null +++ b/Source/Examples/WPF/DemoCore/ExampleAttribute.cs @@ -0,0 +1,22 @@ +namespace DemoCore +{ + using System; + + public class DemoAttribute : Attribute + { + public DemoAttribute(string description) + : this(null, description) + { + } + + public DemoAttribute(string title, string description) + { + this.Title = title; + this.Description = description; + } + + public string Title { get; private set; } + + public string Description { get; private set; } + } +} \ No newline at end of file diff --git a/Source/Examples/WPF/DemoCore/Observable.cs b/Source/Examples/WPF/DemoCore/Observable.cs new file mode 100644 index 000000000..b5607f078 --- /dev/null +++ b/Source/Examples/WPF/DemoCore/Observable.cs @@ -0,0 +1,73 @@ +// -------------------------------------------------------------------------------------------------------------------- +// +// The MIT License (MIT) +// +// Copyright (c) 2014 OxyPlot contributors +// +// Permission is hereby granted, free of charge, to any person obtaining a +// copy of this software and associated documentation files (the +// "Software"), to deal in the Software without restriction, including +// without limitation the rights to use, copy, modify, merge, publish, +// distribute, sublicense, and/or sell copies of the Software, and to +// permit persons to whom the Software is furnished to do so, subject to +// the following conditions: +// +// The above copyright notice and this permission notice shall be included +// in all copies or substantial portions of the Software. +// +// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS +// OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF +// MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. +// IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY +// CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, +// TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE +// SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. +// +// -------------------------------------------------------------------------------------------------------------------- + + +namespace DemoCore +{ + using System; + using System.ComponentModel; + using System.Linq.Expressions; + using System.Reflection; + + public class Observable : INotifyPropertyChanged + { + public event PropertyChangedEventHandler PropertyChanged; + + protected void RaisePropertyChanged(string property) + { + var handler = PropertyChanged; + if (handler != null) + { + handler(this, new PropertyChangedEventArgs(property)); + } + } + + protected void RaisePropertyChanged(Expression> expression) + { + var lambda = expression as LambdaExpression; + MemberExpression memberExpression; + if (lambda.Body is UnaryExpression) + { + var unaryExpression = lambda.Body as UnaryExpression; + memberExpression = unaryExpression.Operand as MemberExpression; + } + else + { + memberExpression = lambda.Body as MemberExpression; + } + + if (memberExpression != null) + { + var propertyInfo = memberExpression.Member as PropertyInfo; + if (propertyInfo != null) + { + this.RaisePropertyChanged(propertyInfo.Name); + } + } + } + } +} \ No newline at end of file diff --git a/Source/Examples/WPF/DemoCore/ScreenCapture.cs b/Source/Examples/WPF/DemoCore/ScreenCapture.cs new file mode 100644 index 000000000..a444ac7b7 --- /dev/null +++ b/Source/Examples/WPF/DemoCore/ScreenCapture.cs @@ -0,0 +1,52 @@ +namespace DemoCore +{ + using System; + using System.Drawing; + using System.Runtime.InteropServices; + + public static class ScreenCapture + { + [DllImport("gdi32.dll")] + static extern bool BitBlt(IntPtr hdcDest, int xDest, int yDest, int wDest, int hDest, IntPtr hdcSource, int xSrc, int ySrc, CopyPixelOperation rop); + + [DllImport("user32.dll")] + static extern bool ReleaseDC(IntPtr hWnd, IntPtr hDc); + + [DllImport("gdi32.dll")] + static extern IntPtr DeleteDC(IntPtr hDc); + + [DllImport("gdi32.dll")] + static extern IntPtr DeleteObject(IntPtr hDc); + + [DllImport("gdi32.dll")] + static extern IntPtr CreateCompatibleBitmap(IntPtr hdc, int nWidth, int nHeight); + + [DllImport("gdi32.dll")] + static extern IntPtr CreateCompatibleDC(IntPtr hdc); + + [DllImport("gdi32.dll")] + static extern IntPtr SelectObject(IntPtr hdc, IntPtr bmp); + + [DllImport("user32.dll")] + public static extern IntPtr GetDesktopWindow(); + + [DllImport("user32.dll")] + static extern IntPtr GetWindowDC(IntPtr ptr); + + public static Bitmap Capture(int left, int top, int width, int height) + { + var hDesk = GetDesktopWindow(); + var hSrce = GetWindowDC(hDesk); + var hDest = CreateCompatibleDC(hSrce); + var hBmp = CreateCompatibleBitmap(hSrce, width, height); + var hOldBmp = SelectObject(hDest, hBmp); + BitBlt(hDest, 0, 0, width, height, hSrce, left, top, CopyPixelOperation.SourceCopy | CopyPixelOperation.CaptureBlt); + var bmp = Image.FromHbitmap(hBmp); + SelectObject(hDest, hOldBmp); + DeleteObject(hBmp); + DeleteDC(hDest); + ReleaseDC(hDesk, hSrce); + return bmp; + } + } +} \ No newline at end of file diff --git a/Source/Examples/WPF/DrawingBrowser/App.config b/Source/Examples/WPF/DrawingBrowser/App.config new file mode 100644 index 000000000..8e1564635 --- /dev/null +++ b/Source/Examples/WPF/DrawingBrowser/App.config @@ -0,0 +1,6 @@ + + + + + + \ No newline at end of file diff --git a/Source/Examples/WPF/DrawingBrowser/App.xaml b/Source/Examples/WPF/DrawingBrowser/App.xaml new file mode 100644 index 000000000..76db01692 --- /dev/null +++ b/Source/Examples/WPF/DrawingBrowser/App.xaml @@ -0,0 +1,8 @@ + + + + + diff --git a/Source/Examples/WPF/DrawingBrowser/App.xaml.cs b/Source/Examples/WPF/DrawingBrowser/App.xaml.cs new file mode 100644 index 000000000..b2d4badec --- /dev/null +++ b/Source/Examples/WPF/DrawingBrowser/App.xaml.cs @@ -0,0 +1,17 @@ +using System; +using System.Collections.Generic; +using System.Configuration; +using System.Data; +using System.Linq; +using System.Threading.Tasks; +using System.Windows; + +namespace DrawingDemo +{ + /// + /// Interaction logic for App.xaml + /// + public partial class App : Application + { + } +} \ No newline at end of file diff --git a/Source/Examples/WPF/DrawingBrowser/DelegateCommand.cs b/Source/Examples/WPF/DrawingBrowser/DelegateCommand.cs new file mode 100644 index 000000000..c8e6f5e94 --- /dev/null +++ b/Source/Examples/WPF/DrawingBrowser/DelegateCommand.cs @@ -0,0 +1,30 @@ +namespace DrawingDemo +{ + using System; + using System.Windows.Input; + + public class DelegateCommand : ICommand + { + private readonly Action execute; + + private readonly Func canExecute; + + public DelegateCommand(Action execute, Func canExecute = null) + { + this.execute = execute; + this.canExecute = canExecute; + } + + public bool CanExecute(object parameter) + { + return this.canExecute == null || this.canExecute(); + } + + public void Execute(object parameter) + { + this.execute(); + } + + public event EventHandler CanExecuteChanged; + } +} \ No newline at end of file diff --git a/Source/Examples/WPF/DrawingBrowser/DrawingBrowser.csproj b/Source/Examples/WPF/DrawingBrowser/DrawingBrowser.csproj new file mode 100644 index 000000000..f064a2e91 --- /dev/null +++ b/Source/Examples/WPF/DrawingBrowser/DrawingBrowser.csproj @@ -0,0 +1,43 @@ + + + $(MSBuildExtensionsPath)\$(VisualStudioVersion)\Bin\Microsoft.CSharp.targets + net47 + Exe + + + + + + + Designer + MSBuild:UpdateDesignTimeXaml + + + + + Designer + MSBuild:UpdateDesignTimeXaml + + + + + + + + + + + + + + + + + + + + + + + + \ No newline at end of file diff --git a/Source/Examples/WPF/DrawingBrowser/MainWindow.xaml b/Source/Examples/WPF/DrawingBrowser/MainWindow.xaml new file mode 100644 index 000000000..e48af53cd --- /dev/null +++ b/Source/Examples/WPF/DrawingBrowser/MainWindow.xaml @@ -0,0 +1,28 @@ + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/Source/Examples/WPF/DrawingBrowser/MainWindow.xaml.cs b/Source/Examples/WPF/DrawingBrowser/MainWindow.xaml.cs new file mode 100644 index 000000000..a330ed4d0 --- /dev/null +++ b/Source/Examples/WPF/DrawingBrowser/MainWindow.xaml.cs @@ -0,0 +1,144 @@ +namespace DrawingDemo +{ + using System.Collections.Generic; + using System.Collections.ObjectModel; + using System.ComponentModel; + using System.IO; + using System.Runtime.CompilerServices; + using System.Windows; + using System.Windows.Input; + + using DrawingDemo.Annotations; + + using OxyPlot.Drawing; + + using SvgLibrary; + + /// + /// Interaction logic for MainWindow.xaml + /// + public partial class MainWindow : Window + { + public MainWindow() + { + this.InitializeComponent(); + this.DataContext = new MainViewModel(); + } + } + + public class MainViewModel : INotifyPropertyChanged + { + private ExampleInfo selectedExample; + + public ICommand SavePngCommand { get; private set; } + public ICommand SavePdfCommand { get; private set; } + public ICommand SaveSvgCommand { get; private set; } + public DrawingModel Drawing { get; private set; } + + public IList Examples { get; private set; } + + public ExampleInfo SelectedExample + { + get + { + return this.selectedExample; + } + + set + { + this.selectedExample = value; + this.OnPropertyChanged(); + } + } + + public MainViewModel() + { + var svg = new Svg() { ViewBox = "0 0 900 900" }; + var g = new SvgGroup() { Id = "g1" }; + g.Elements.Add(new SvgPath() { Id = "p1" }); + g.Elements.Add(new SvgPath() { Id = "p2" }); + svg.Elements.Add(g); + using (var s = File.Create(@"D:\test.svg")) + svg.Save(s); + this.SavePngCommand = new DelegateCommand(this.SavePng); + this.SavePdfCommand = new DelegateCommand(this.SavePdf); + this.SaveSvgCommand = new DelegateCommand(this.SaveSvg); + + this.Examples = new ObservableCollection(DrawingDemo.Examples.Get()); + this.Drawing = new DrawingModel(); + + /* Drawing.Background = OxyColors.Orange; + this.Drawing.Add(new Rectangle(-40, -30, 40, 30) { Thickness = 0.5 }); + this.Drawing.Add(new Text(-39, 29, "Drawing example") { FontSize = 2 }); + this.Drawing.Add(new Text(-39, 25, "Fixed font size") { FontSize = -11 }); + + this.Drawing.Add(new Ellipse(0, 0, 30, 20)); + this.Drawing.Add(new Ellipse(0, 0, 20, 15) { Thickness = 1, Fill = OxyColors.LightGreen }); + this.Drawing.Add(new Rectangle(-30, -20, 30, 20)); + + var polyline = new Polyline(); + for (double r = 0; r < 360; r += 15) + this.Drawing.Add(new Text(0, 0, "Drawing") { Rotate = r, FontSize = 3, Color = OxyColors.White }); + + var lines = new Lines() { Thickness = -4, Color = OxyColors.IndianRed }; + lines.Add(0, -10, 0, 10); + lines.Add(-15, 0, 15, 0); + this.Drawing.Add(lines); + + var imageSource = new OxyImage(File.ReadAllBytes("test.png")); + for (double r = 0; r < 360; r += 90) + { + this.Drawing.Add( + new Image + { + X = 0, + Y = 0, + Width = -32, + Height = -32, + // Rotation = r, + Source = imageSource, + HorizontalAlignment = HorizontalAlignment.Left, + VerticalAlignment = VerticalAlignment.Top + }); + } + + this.Drawing.Add(new Image + { + X = 20, + Y = 10, + Width = 4, + Height = 4, + SourceX = 6, + SourceY = 6, + SourceWidth = 20, + SourceHeight = 20, + Source = imageSource + });*/ + } + + private void SavePng() + { + // PngExporter.Export(this.Drawing, "test.png", 100, 100); + } + + private void SavePdf() + { + } + + private void SaveSvg() + { + } + + public event PropertyChangedEventHandler PropertyChanged; + + [NotifyPropertyChangedInvocator] + protected virtual void OnPropertyChanged([CallerMemberName] string propertyName = null) + { + var handler = this.PropertyChanged; + if (handler != null) + { + handler(this, new PropertyChangedEventArgs(propertyName)); + } + } + } +} \ No newline at end of file diff --git a/Source/Examples/WPF/DrawingBrowser/OxyPlot.ico b/Source/Examples/WPF/DrawingBrowser/OxyPlot.ico new file mode 100644 index 000000000..bc94ef85c Binary files /dev/null and b/Source/Examples/WPF/DrawingBrowser/OxyPlot.ico differ diff --git a/Source/Examples/WPF/DrawingBrowser/Properties/Annotations.cs b/Source/Examples/WPF/DrawingBrowser/Properties/Annotations.cs new file mode 100644 index 000000000..e9ac71477 --- /dev/null +++ b/Source/Examples/WPF/DrawingBrowser/Properties/Annotations.cs @@ -0,0 +1,614 @@ +using System; + +#pragma warning disable 1591 +// ReSharper disable UnusedMember.Global +// ReSharper disable UnusedParameter.Local +// ReSharper disable MemberCanBePrivate.Global +// ReSharper disable UnusedAutoPropertyAccessor.Global +// ReSharper disable IntroduceOptionalParameters.Global +// ReSharper disable MemberCanBeProtected.Global +// ReSharper disable InconsistentNaming + +namespace DrawingDemo.Annotations +{ + /// + /// Indicates that the value of the marked element could be null sometimes, + /// so the check for null is necessary before its usage + /// + /// + /// [CanBeNull] public object Test() { return null; } + /// public void UseTest() { + /// var p = Test(); + /// var s = p.ToString(); // Warning: Possible 'System.NullReferenceException' + /// } + /// + [AttributeUsage( + AttributeTargets.Method | AttributeTargets.Parameter | + AttributeTargets.Property | AttributeTargets.Delegate | + AttributeTargets.Field, AllowMultiple = false, Inherited = true)] + public sealed class CanBeNullAttribute : Attribute { } + + /// + /// Indicates that the value of the marked element could never be null + /// + /// + /// [NotNull] public object Foo() { + /// return null; // Warning: Possible 'null' assignment + /// } + /// + [AttributeUsage( + AttributeTargets.Method | AttributeTargets.Parameter | + AttributeTargets.Property | AttributeTargets.Delegate | + AttributeTargets.Field, AllowMultiple = false, Inherited = true)] + public sealed class NotNullAttribute : Attribute { } + + /// + /// Indicates that the marked method builds string by format pattern and (optional) arguments. + /// Parameter, which contains format string, should be given in constructor. The format string + /// should be in -like form + /// + /// + /// [StringFormatMethod("message")] + /// public void ShowError(string message, params object[] args) { /* do something */ } + /// public void Foo() { + /// ShowError("Failed: {0}"); // Warning: Non-existing argument in format string + /// } + /// + [AttributeUsage( + AttributeTargets.Constructor | AttributeTargets.Method, + AllowMultiple = false, Inherited = true)] + public sealed class StringFormatMethodAttribute : Attribute + { + /// + /// Specifies which parameter of an annotated method should be treated as format-string + /// + public StringFormatMethodAttribute(string formatParameterName) + { + FormatParameterName = formatParameterName; + } + + public string FormatParameterName { get; private set; } + } + + /// + /// Indicates that the function argument should be string literal and match one + /// of the parameters of the caller function. For example, ReSharper annotates + /// the parameter of + /// + /// + /// public void Foo(string param) { + /// if (param == null) + /// throw new ArgumentNullException("par"); // Warning: Cannot resolve symbol + /// } + /// + [AttributeUsage(AttributeTargets.Parameter, AllowMultiple = false, Inherited = true)] + public sealed class InvokerParameterNameAttribute : Attribute { } + + /// + /// Indicates that the method is contained in a type that implements + /// interface + /// and this method is used to notify that some property value changed + /// + /// + /// The method should be non-static and conform to one of the supported signatures: + /// + /// NotifyChanged(string) + /// NotifyChanged(params string[]) + /// NotifyChanged{T}(Expression{Func{T}}) + /// NotifyChanged{T,U}(Expression{Func{T,U}}) + /// SetProperty{T}(ref T, T, string) + /// + /// + /// + /// public class Foo : INotifyPropertyChanged { + /// public event PropertyChangedEventHandler PropertyChanged; + /// [NotifyPropertyChangedInvocator] + /// protected virtual void NotifyChanged(string propertyName) { ... } + /// + /// private string _name; + /// public string Name { + /// get { return _name; } + /// set { _name = value; NotifyChanged("LastName"); /* Warning */ } + /// } + /// } + /// + /// Examples of generated notifications: + /// + /// NotifyChanged("Property") + /// NotifyChanged(() => Property) + /// NotifyChanged((VM x) => x.Property) + /// SetProperty(ref myField, value, "Property") + /// + /// + [AttributeUsage(AttributeTargets.Method, AllowMultiple = false, Inherited = true)] + public sealed class NotifyPropertyChangedInvocatorAttribute : Attribute + { + public NotifyPropertyChangedInvocatorAttribute() { } + public NotifyPropertyChangedInvocatorAttribute(string parameterName) + { + ParameterName = parameterName; + } + + public string ParameterName { get; private set; } + } + + /// + /// Describes dependency between method input and output + /// + /// + ///

Function Definition Table syntax:

+ /// + /// FDT ::= FDTRow [;FDTRow]* + /// FDTRow ::= Input => Output | Output <= Input + /// Input ::= ParameterName: Value [, Input]* + /// Output ::= [ParameterName: Value]* {halt|stop|void|nothing|Value} + /// Value ::= true | false | null | notnull | canbenull + /// + /// If method has single input parameter, it's name could be omitted.
+ /// Using halt (or void/nothing, which is the same) + /// for method output means that the methos doesn't return normally.
+ /// canbenull annotation is only applicable for output parameters.
+ /// You can use multiple [ContractAnnotation] for each FDT row, + /// or use single attribute with rows separated by semicolon.
+ ///
+ /// + /// + /// [ContractAnnotation("=> halt")] + /// public void TerminationMethod() + /// + /// + /// [ContractAnnotation("halt <= condition: false")] + /// public void Assert(bool condition, string text) // regular assertion method + /// + /// + /// [ContractAnnotation("s:null => true")] + /// public bool IsNullOrEmpty(string s) // string.IsNullOrEmpty() + /// + /// + /// // A method that returns null if the parameter is null, and not null if the parameter is not null + /// [ContractAnnotation("null => null; notnull => notnull")] + /// public object Transform(object data) + /// + /// + /// [ContractAnnotation("s:null=>false; =>true,result:notnull; =>false, result:null")] + /// public bool TryParse(string s, out Person result) + /// + /// + [AttributeUsage(AttributeTargets.Method, AllowMultiple = true, Inherited = true)] + public sealed class ContractAnnotationAttribute : Attribute + { + public ContractAnnotationAttribute([NotNull] string contract) + : this(contract, false) { } + + public ContractAnnotationAttribute([NotNull] string contract, bool forceFullStates) + { + Contract = contract; + ForceFullStates = forceFullStates; + } + + public string Contract { get; private set; } + public bool ForceFullStates { get; private set; } + } + + /// + /// Indicates that marked element should be localized or not + /// + /// + /// [LocalizationRequiredAttribute(true)] + /// public class Foo { + /// private string str = "my string"; // Warning: Localizable string + /// } + /// + [AttributeUsage(AttributeTargets.All, AllowMultiple = false, Inherited = true)] + public sealed class LocalizationRequiredAttribute : Attribute + { + public LocalizationRequiredAttribute() : this(true) { } + public LocalizationRequiredAttribute(bool required) + { + Required = required; + } + + public bool Required { get; private set; } + } + + /// + /// Indicates that the value of the marked type (or its derivatives) + /// cannot be compared using '==' or '!=' operators and Equals() + /// should be used instead. However, using '==' or '!=' for comparison + /// with null is always permitted. + /// + /// + /// [CannotApplyEqualityOperator] + /// class NoEquality { } + /// class UsesNoEquality { + /// public void Test() { + /// var ca1 = new NoEquality(); + /// var ca2 = new NoEquality(); + /// if (ca1 != null) { // OK + /// bool condition = ca1 == ca2; // Warning + /// } + /// } + /// } + /// + [AttributeUsage( + AttributeTargets.Interface | AttributeTargets.Class | + AttributeTargets.Struct, AllowMultiple = false, Inherited = true)] + public sealed class CannotApplyEqualityOperatorAttribute : Attribute { } + + /// + /// When applied to a target attribute, specifies a requirement for any type marked + /// with the target attribute to implement or inherit specific type or types. + /// + /// + /// [BaseTypeRequired(typeof(IComponent)] // Specify requirement + /// public class ComponentAttribute : Attribute { } + /// [Component] // ComponentAttribute requires implementing IComponent interface + /// public class MyComponent : IComponent { } + /// + [AttributeUsage(AttributeTargets.Class, AllowMultiple = true, Inherited = true)] + [BaseTypeRequired(typeof(Attribute))] + public sealed class BaseTypeRequiredAttribute : Attribute + { + public BaseTypeRequiredAttribute([NotNull] Type baseType) + { + BaseType = baseType; + } + + [NotNull] public Type BaseType { get; private set; } + } + + /// + /// Indicates that the marked symbol is used implicitly + /// (e.g. via reflection, in external library), so this symbol + /// will not be marked as unused (as well as by other usage inspections) + /// + [AttributeUsage(AttributeTargets.All, AllowMultiple = false, Inherited = true)] + public sealed class UsedImplicitlyAttribute : Attribute + { + public UsedImplicitlyAttribute() + : this(ImplicitUseKindFlags.Default, ImplicitUseTargetFlags.Default) { } + + public UsedImplicitlyAttribute(ImplicitUseKindFlags useKindFlags) + : this(useKindFlags, ImplicitUseTargetFlags.Default) { } + + public UsedImplicitlyAttribute(ImplicitUseTargetFlags targetFlags) + : this(ImplicitUseKindFlags.Default, targetFlags) { } + + public UsedImplicitlyAttribute( + ImplicitUseKindFlags useKindFlags, ImplicitUseTargetFlags targetFlags) + { + UseKindFlags = useKindFlags; + TargetFlags = targetFlags; + } + + public ImplicitUseKindFlags UseKindFlags { get; private set; } + public ImplicitUseTargetFlags TargetFlags { get; private set; } + } + + /// + /// Should be used on attributes and causes ReSharper + /// to not mark symbols marked with such attributes as unused + /// (as well as by other usage inspections) + /// + [AttributeUsage(AttributeTargets.Class, AllowMultiple = false, Inherited = true)] + public sealed class MeansImplicitUseAttribute : Attribute + { + public MeansImplicitUseAttribute() + : this(ImplicitUseKindFlags.Default, ImplicitUseTargetFlags.Default) { } + + public MeansImplicitUseAttribute(ImplicitUseKindFlags useKindFlags) + : this(useKindFlags, ImplicitUseTargetFlags.Default) { } + + public MeansImplicitUseAttribute(ImplicitUseTargetFlags targetFlags) + : this(ImplicitUseKindFlags.Default, targetFlags) { } + + public MeansImplicitUseAttribute( + ImplicitUseKindFlags useKindFlags, ImplicitUseTargetFlags targetFlags) + { + UseKindFlags = useKindFlags; + TargetFlags = targetFlags; + } + + [UsedImplicitly] public ImplicitUseKindFlags UseKindFlags { get; private set; } + [UsedImplicitly] public ImplicitUseTargetFlags TargetFlags { get; private set; } + } + + [Flags] + public enum ImplicitUseKindFlags + { + Default = Access | Assign | InstantiatedWithFixedConstructorSignature, + /// Only entity marked with attribute considered used + Access = 1, + /// Indicates implicit assignment to a member + Assign = 2, + /// + /// Indicates implicit instantiation of a type with fixed constructor signature. + /// That means any unused constructor parameters won't be reported as such. + /// + InstantiatedWithFixedConstructorSignature = 4, + /// Indicates implicit instantiation of a type + InstantiatedNoFixedConstructorSignature = 8, + } + + /// + /// Specify what is considered used implicitly + /// when marked with + /// or + /// + [Flags] + public enum ImplicitUseTargetFlags + { + Default = Itself, + Itself = 1, + /// Members of entity marked with attribute are considered used + Members = 2, + /// Entity marked with attribute and all its members considered used + WithMembers = Itself | Members + } + + /// + /// This attribute is intended to mark publicly available API + /// which should not be removed and so is treated as used + /// + [MeansImplicitUse] + public sealed class PublicAPIAttribute : Attribute + { + public PublicAPIAttribute() { } + public PublicAPIAttribute([NotNull] string comment) + { + Comment = comment; + } + + [NotNull] public string Comment { get; private set; } + } + + /// + /// Tells code analysis engine if the parameter is completely handled + /// when the invoked method is on stack. If the parameter is a delegate, + /// indicates that delegate is executed while the method is executed. + /// If the parameter is an enumerable, indicates that it is enumerated + /// while the method is executed + /// + [AttributeUsage(AttributeTargets.Parameter, Inherited = true)] + public sealed class InstantHandleAttribute : Attribute { } + + /// + /// Indicates that a method does not make any observable state changes. + /// The same as System.Diagnostics.Contracts.PureAttribute + /// + /// + /// [Pure] private int Multiply(int x, int y) { return x * y; } + /// public void Foo() { + /// const int a = 2, b = 2; + /// Multiply(a, b); // Waring: Return value of pure method is not used + /// } + /// + [AttributeUsage(AttributeTargets.Method, Inherited = true)] + public sealed class PureAttribute : Attribute { } + + /// + /// Indicates that a parameter is a path to a file or a folder + /// within a web project. Path can be relative or absolute, + /// starting from web root (~) + /// + [AttributeUsage(AttributeTargets.Parameter)] + public class PathReferenceAttribute : Attribute + { + public PathReferenceAttribute() { } + public PathReferenceAttribute([PathReference] string basePath) + { + BasePath = basePath; + } + + [NotNull] public string BasePath { get; private set; } + } + + // ASP.NET MVC attributes + + [AttributeUsage(AttributeTargets.Assembly, AllowMultiple = true)] + public sealed class AspMvcAreaMasterLocationFormatAttribute : Attribute + { + public AspMvcAreaMasterLocationFormatAttribute(string format) { } + } + + [AttributeUsage(AttributeTargets.Assembly, AllowMultiple = true)] + public sealed class AspMvcAreaPartialViewLocationFormatAttribute : Attribute + { + public AspMvcAreaPartialViewLocationFormatAttribute(string format) { } + } + + [AttributeUsage(AttributeTargets.Assembly, AllowMultiple = true)] + public sealed class AspMvcAreaViewLocationFormatAttribute : Attribute + { + public AspMvcAreaViewLocationFormatAttribute(string format) { } + } + + [AttributeUsage(AttributeTargets.Assembly, AllowMultiple = true)] + public sealed class AspMvcMasterLocationFormatAttribute : Attribute + { + public AspMvcMasterLocationFormatAttribute(string format) { } + } + + [AttributeUsage(AttributeTargets.Assembly, AllowMultiple = true)] + public sealed class AspMvcPartialViewLocationFormatAttribute : Attribute + { + public AspMvcPartialViewLocationFormatAttribute(string format) { } + } + + [AttributeUsage(AttributeTargets.Assembly, AllowMultiple = true)] + public sealed class AspMvcViewLocationFormatAttribute : Attribute + { + public AspMvcViewLocationFormatAttribute(string format) { } + } + + /// + /// ASP.NET MVC attribute. If applied to a parameter, indicates that the parameter + /// is an MVC action. If applied to a method, the MVC action name is calculated + /// implicitly from the context. Use this attribute for custom wrappers similar to + /// System.Web.Mvc.Html.ChildActionExtensions.RenderAction(HtmlHelper, String) + /// + [AttributeUsage(AttributeTargets.Parameter | AttributeTargets.Method)] + public sealed class AspMvcActionAttribute : Attribute + { + public AspMvcActionAttribute() { } + public AspMvcActionAttribute([NotNull] string anonymousProperty) + { + AnonymousProperty = anonymousProperty; + } + + [NotNull] public string AnonymousProperty { get; private set; } + } + + /// + /// ASP.NET MVC attribute. Indicates that a parameter is an MVC area. + /// Use this attribute for custom wrappers similar to + /// System.Web.Mvc.Html.ChildActionExtensions.RenderAction(HtmlHelper, String) + /// + [AttributeUsage(AttributeTargets.Parameter)] + public sealed class AspMvcAreaAttribute : PathReferenceAttribute + { + public AspMvcAreaAttribute() { } + public AspMvcAreaAttribute([NotNull] string anonymousProperty) + { + AnonymousProperty = anonymousProperty; + } + + [NotNull] public string AnonymousProperty { get; private set; } + } + + /// + /// ASP.NET MVC attribute. If applied to a parameter, indicates that + /// the parameter is an MVC controller. If applied to a method, + /// the MVC controller name is calculated implicitly from the context. + /// Use this attribute for custom wrappers similar to + /// System.Web.Mvc.Html.ChildActionExtensions.RenderAction(HtmlHelper, String, String) + /// + [AttributeUsage(AttributeTargets.Parameter | AttributeTargets.Method)] + public sealed class AspMvcControllerAttribute : Attribute + { + public AspMvcControllerAttribute() { } + public AspMvcControllerAttribute([NotNull] string anonymousProperty) + { + AnonymousProperty = anonymousProperty; + } + + [NotNull] public string AnonymousProperty { get; private set; } + } + + /// + /// ASP.NET MVC attribute. Indicates that a parameter is an MVC Master. + /// Use this attribute for custom wrappers similar to + /// System.Web.Mvc.Controller.View(String, String) + /// + [AttributeUsage(AttributeTargets.Parameter)] + public sealed class AspMvcMasterAttribute : Attribute { } + + /// + /// ASP.NET MVC attribute. Indicates that a parameter is an MVC model type. + /// Use this attribute for custom wrappers similar to + /// System.Web.Mvc.Controller.View(String, Object) + /// + [AttributeUsage(AttributeTargets.Parameter)] + public sealed class AspMvcModelTypeAttribute : Attribute { } + + /// + /// ASP.NET MVC attribute. If applied to a parameter, indicates that + /// the parameter is an MVC partial view. If applied to a method, + /// the MVC partial view name is calculated implicitly from the context. + /// Use this attribute for custom wrappers similar to + /// System.Web.Mvc.Html.RenderPartialExtensions.RenderPartial(HtmlHelper, String) + /// + [AttributeUsage(AttributeTargets.Parameter | AttributeTargets.Method)] + public sealed class AspMvcPartialViewAttribute : PathReferenceAttribute { } + + /// + /// ASP.NET MVC attribute. Allows disabling all inspections + /// for MVC views within a class or a method. + /// + [AttributeUsage(AttributeTargets.Class | AttributeTargets.Method)] + public sealed class AspMvcSupressViewErrorAttribute : Attribute { } + + /// + /// ASP.NET MVC attribute. Indicates that a parameter is an MVC display template. + /// Use this attribute for custom wrappers similar to + /// System.Web.Mvc.Html.DisplayExtensions.DisplayForModel(HtmlHelper, String) + /// + [AttributeUsage(AttributeTargets.Parameter)] + public sealed class AspMvcDisplayTemplateAttribute : Attribute { } + + /// + /// ASP.NET MVC attribute. Indicates that a parameter is an MVC editor template. + /// Use this attribute for custom wrappers similar to + /// System.Web.Mvc.Html.EditorExtensions.EditorForModel(HtmlHelper, String) + /// + [AttributeUsage(AttributeTargets.Parameter)] + public sealed class AspMvcEditorTemplateAttribute : Attribute { } + + /// + /// ASP.NET MVC attribute. Indicates that a parameter is an MVC template. + /// Use this attribute for custom wrappers similar to + /// System.ComponentModel.DataAnnotations.UIHintAttribute(System.String) + /// + [AttributeUsage(AttributeTargets.Parameter)] + public sealed class AspMvcTemplateAttribute : Attribute { } + + /// + /// ASP.NET MVC attribute. If applied to a parameter, indicates that the parameter + /// is an MVC view. If applied to a method, the MVC view name is calculated implicitly + /// from the context. Use this attribute for custom wrappers similar to + /// System.Web.Mvc.Controller.View(Object) + /// + [AttributeUsage(AttributeTargets.Parameter | AttributeTargets.Method)] + public sealed class AspMvcViewAttribute : PathReferenceAttribute { } + + /// + /// ASP.NET MVC attribute. When applied to a parameter of an attribute, + /// indicates that this parameter is an MVC action name + /// + /// + /// [ActionName("Foo")] + /// public ActionResult Login(string returnUrl) { + /// ViewBag.ReturnUrl = Url.Action("Foo"); // OK + /// return RedirectToAction("Bar"); // Error: Cannot resolve action + /// } + /// + [AttributeUsage(AttributeTargets.Parameter | AttributeTargets.Property)] + public sealed class AspMvcActionSelectorAttribute : Attribute { } + + [AttributeUsage( + AttributeTargets.Parameter | AttributeTargets.Property | + AttributeTargets.Field, Inherited = true)] + public sealed class HtmlElementAttributesAttribute : Attribute + { + public HtmlElementAttributesAttribute() { } + public HtmlElementAttributesAttribute([NotNull] string name) + { + Name = name; + } + + [NotNull] public string Name { get; private set; } + } + + [AttributeUsage( + AttributeTargets.Parameter | AttributeTargets.Field | + AttributeTargets.Property, Inherited = true)] + public sealed class HtmlAttributeValueAttribute : Attribute + { + public HtmlAttributeValueAttribute([NotNull] string name) + { + Name = name; + } + + [NotNull] public string Name { get; private set; } + } + + // Razor attributes + + /// + /// Razor attribute. Indicates that a parameter or a method is a Razor section. + /// Use this attribute for custom wrappers similar to + /// System.Web.WebPages.WebPageBase.RenderSection(String) + /// + [AttributeUsage(AttributeTargets.Parameter | AttributeTargets.Method, Inherited = true)] + public sealed class RazorSectionAttribute : Attribute { } +} \ No newline at end of file diff --git a/Source/Examples/WPF/DrawingBrowser/Properties/AssemblyInfo.cs b/Source/Examples/WPF/DrawingBrowser/Properties/AssemblyInfo.cs new file mode 100644 index 000000000..7e934f63b --- /dev/null +++ b/Source/Examples/WPF/DrawingBrowser/Properties/AssemblyInfo.cs @@ -0,0 +1,24 @@ +using System.Reflection; +using System.Resources; +using System.Runtime.CompilerServices; +using System.Runtime.InteropServices; +using System.Windows; + +//In order to begin building localizable applications, set +//CultureYouAreCodingWith in your .csproj file +//inside a . For example, if you are using US english +//in your source files, set the to en-US. Then uncomment +//the NeutralResourceLanguage attribute below. Update the "en-US" in +//the line below to match the UICulture setting in the project file. + +//[assembly: NeutralResourcesLanguage("en-US", UltimateResourceFallbackLocation.Satellite)] + + +[assembly: ThemeInfo( + ResourceDictionaryLocation.None, //where theme specific resource dictionaries are located + //(used if a resource is not found in the page, + // or application resource dictionaries) + ResourceDictionaryLocation.SourceAssembly //where the generic resource dictionary is located + //(used if a resource is not found in the page, + // app, or any theme specific resource dictionaries) +)] diff --git a/Source/Examples/WPF/DrawingBrowser/Properties/Resources.Designer.cs b/Source/Examples/WPF/DrawingBrowser/Properties/Resources.Designer.cs new file mode 100644 index 000000000..d5252afe3 --- /dev/null +++ b/Source/Examples/WPF/DrawingBrowser/Properties/Resources.Designer.cs @@ -0,0 +1,63 @@ +//------------------------------------------------------------------------------ +// +// This code was generated by a tool. +// Runtime Version:4.0.30319.34014 +// +// Changes to this file may cause incorrect behavior and will be lost if +// the code is regenerated. +// +//------------------------------------------------------------------------------ + +namespace DrawingBrowser.Properties { + using System; + + + /// + /// A strongly-typed resource class, for looking up localized strings, etc. + /// + // This class was auto-generated by the StronglyTypedResourceBuilder + // class via a tool like ResGen or Visual Studio. + // To add or remove a member, edit your .ResX file then rerun ResGen + // with the /str option, or rebuild your VS project. + [global::System.CodeDom.Compiler.GeneratedCodeAttribute("System.Resources.Tools.StronglyTypedResourceBuilder", "4.0.0.0")] + [global::System.Diagnostics.DebuggerNonUserCodeAttribute()] + [global::System.Runtime.CompilerServices.CompilerGeneratedAttribute()] + internal class Resources { + + private static global::System.Resources.ResourceManager resourceMan; + + private static global::System.Globalization.CultureInfo resourceCulture; + + [global::System.Diagnostics.CodeAnalysis.SuppressMessageAttribute("Microsoft.Performance", "CA1811:AvoidUncalledPrivateCode")] + internal Resources() { + } + + /// + /// Returns the cached ResourceManager instance used by this class. + /// + [global::System.ComponentModel.EditorBrowsableAttribute(global::System.ComponentModel.EditorBrowsableState.Advanced)] + internal static global::System.Resources.ResourceManager ResourceManager { + get { + if (object.ReferenceEquals(resourceMan, null)) { + global::System.Resources.ResourceManager temp = new global::System.Resources.ResourceManager("DrawingBrowser.Properties.Resources", typeof(Resources).Assembly); + resourceMan = temp; + } + return resourceMan; + } + } + + /// + /// Overrides the current thread's CurrentUICulture property for all + /// resource lookups using this strongly typed resource class. + /// + [global::System.ComponentModel.EditorBrowsableAttribute(global::System.ComponentModel.EditorBrowsableState.Advanced)] + internal static global::System.Globalization.CultureInfo Culture { + get { + return resourceCulture; + } + set { + resourceCulture = value; + } + } + } +} diff --git a/Source/Examples/WPF/DrawingBrowser/Properties/Resources.resx b/Source/Examples/WPF/DrawingBrowser/Properties/Resources.resx new file mode 100644 index 000000000..af7dbebba --- /dev/null +++ b/Source/Examples/WPF/DrawingBrowser/Properties/Resources.resx @@ -0,0 +1,117 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + text/microsoft-resx + + + 2.0 + + + System.Resources.ResXResourceReader, System.Windows.Forms, Version=2.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089 + + + System.Resources.ResXResourceWriter, System.Windows.Forms, Version=2.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089 + + \ No newline at end of file diff --git a/Source/Examples/WPF/DrawingBrowser/Properties/Settings.Designer.cs b/Source/Examples/WPF/DrawingBrowser/Properties/Settings.Designer.cs new file mode 100644 index 000000000..7108544c4 --- /dev/null +++ b/Source/Examples/WPF/DrawingBrowser/Properties/Settings.Designer.cs @@ -0,0 +1,26 @@ +//------------------------------------------------------------------------------ +// +// This code was generated by a tool. +// Runtime Version:4.0.30319.34014 +// +// Changes to this file may cause incorrect behavior and will be lost if +// the code is regenerated. +// +//------------------------------------------------------------------------------ + +namespace DrawingBrowser.Properties { + + + [global::System.Runtime.CompilerServices.CompilerGeneratedAttribute()] + [global::System.CodeDom.Compiler.GeneratedCodeAttribute("Microsoft.VisualStudio.Editors.SettingsDesigner.SettingsSingleFileGenerator", "12.0.0.0")] + internal sealed partial class Settings : global::System.Configuration.ApplicationSettingsBase { + + private static Settings defaultInstance = ((Settings)(global::System.Configuration.ApplicationSettingsBase.Synchronized(new Settings()))); + + public static Settings Default { + get { + return defaultInstance; + } + } + } +} diff --git a/Source/Examples/WPF/DrawingBrowser/Properties/Settings.settings b/Source/Examples/WPF/DrawingBrowser/Properties/Settings.settings new file mode 100644 index 000000000..033d7a5e9 --- /dev/null +++ b/Source/Examples/WPF/DrawingBrowser/Properties/Settings.settings @@ -0,0 +1,7 @@ + + + + + + + \ No newline at end of file diff --git a/Source/Examples/WPF/DrawingBrowser/Test.png b/Source/Examples/WPF/DrawingBrowser/Test.png new file mode 100644 index 000000000..387b9fd1a Binary files /dev/null and b/Source/Examples/WPF/DrawingBrowser/Test.png differ diff --git a/Source/Examples/WPF/DrawingDemos/App.xaml b/Source/Examples/WPF/DrawingDemos/App.xaml new file mode 100644 index 000000000..e0627ab33 --- /dev/null +++ b/Source/Examples/WPF/DrawingDemos/App.xaml @@ -0,0 +1,8 @@ + + + + + diff --git a/Source/Examples/WPF/DrawingDemos/App.xaml.cs b/Source/Examples/WPF/DrawingDemos/App.xaml.cs new file mode 100644 index 000000000..17c8ed785 --- /dev/null +++ b/Source/Examples/WPF/DrawingDemos/App.xaml.cs @@ -0,0 +1,16 @@ +using System; +using System.Collections.Generic; +using System.Configuration; +using System.Data; +using System.Linq; +using System.Windows; + +namespace DrawingDemos +{ + /// + /// Interaction logic for App.xaml + /// + public partial class App : Application + { + } +} diff --git a/Source/Examples/WPF/DrawingDemos/Demos/TwoDrawingViews/Window1.xaml b/Source/Examples/WPF/DrawingDemos/Demos/TwoDrawingViews/Window1.xaml new file mode 100644 index 000000000..09a60d85b --- /dev/null +++ b/Source/Examples/WPF/DrawingDemos/Demos/TwoDrawingViews/Window1.xaml @@ -0,0 +1,37 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/Source/Examples/WPF/DrawingDemos/Demos/TwoDrawingViews/Window1.xaml.cs b/Source/Examples/WPF/DrawingDemos/Demos/TwoDrawingViews/Window1.xaml.cs new file mode 100644 index 000000000..9ad0d8d5e --- /dev/null +++ b/Source/Examples/WPF/DrawingDemos/Demos/TwoDrawingViews/Window1.xaml.cs @@ -0,0 +1,54 @@ +// -------------------------------------------------------------------------------------------------------------------- +// +// The MIT License (MIT) +// +// Copyright (c) 2014 OxyPlot contributors +// +// Permission is hereby granted, free of charge, to any person obtaining a +// copy of this software and associated documentation files (the +// "Software"), to deal in the Software without restriction, including +// without limitation the rights to use, copy, modify, merge, publish, +// distribute, sublicense, and/or sell copies of the Software, and to +// permit persons to whom the Software is furnished to do so, subject to +// the following conditions: +// +// The above copyright notice and this permission notice shall be included +// in all copies or substantial portions of the Software. +// +// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS +// OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF +// MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. +// IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY +// CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, +// TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE +// SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. +// +// +// Interaction logic for Window1.xaml +// +// -------------------------------------------------------------------------------------------------------------------- + +namespace TwoDrawingViews +{ + using System.Windows; + + using DemoCore; + + using OxyPlot.Drawing; + + /// + /// Interaction logic for Window1.xaml + /// + [Demo("Two DrawingViews showing the same Drawing.")] + public partial class Window1 : Window + { + public Window1() + { + this.InitializeComponent(); + this.Drawing = DrawingLibrary.Examples.SvgExamples.Tiger().Model; + this.DataContext = this; + } + + public DrawingModel Drawing { get; set; } + } +} diff --git a/Source/Examples/WPF/DrawingDemos/DrawingDemos.csproj b/Source/Examples/WPF/DrawingDemos/DrawingDemos.csproj new file mode 100644 index 000000000..f064a2e91 --- /dev/null +++ b/Source/Examples/WPF/DrawingDemos/DrawingDemos.csproj @@ -0,0 +1,43 @@ + + + $(MSBuildExtensionsPath)\$(VisualStudioVersion)\Bin\Microsoft.CSharp.targets + net47 + Exe + + + + + + + Designer + MSBuild:UpdateDesignTimeXaml + + + + + Designer + MSBuild:UpdateDesignTimeXaml + + + + + + + + + + + + + + + + + + + + + + + + \ No newline at end of file diff --git a/Source/Examples/WPF/DrawingDemos/Images/DoubleView.png b/Source/Examples/WPF/DrawingDemos/Images/DoubleView.png new file mode 100644 index 000000000..90943b86c Binary files /dev/null and b/Source/Examples/WPF/DrawingDemos/Images/DoubleView.png differ diff --git a/Source/Examples/WPF/DrawingDemos/Images/TwoDrawingViews.png b/Source/Examples/WPF/DrawingDemos/Images/TwoDrawingViews.png new file mode 100644 index 000000000..e7ba15542 Binary files /dev/null and b/Source/Examples/WPF/DrawingDemos/Images/TwoDrawingViews.png differ diff --git a/Source/Examples/WPF/DrawingDemos/MainWindow.xaml b/Source/Examples/WPF/DrawingDemos/MainWindow.xaml new file mode 100644 index 000000000..bad03dae1 --- /dev/null +++ b/Source/Examples/WPF/DrawingDemos/MainWindow.xaml @@ -0,0 +1,28 @@ + + + + + + + + + + + + + + + + + + + diff --git a/Source/Examples/WPF/DrawingDemos/MainWindow.xaml.cs b/Source/Examples/WPF/DrawingDemos/MainWindow.xaml.cs new file mode 100644 index 000000000..790eda23c --- /dev/null +++ b/Source/Examples/WPF/DrawingDemos/MainWindow.xaml.cs @@ -0,0 +1,99 @@ +namespace DrawingDemos +{ + using System.Collections.Generic; + using System.Linq; + using System.Reflection; + using System.Windows; + using System.Windows.Controls; + using System.Windows.Input; + + using DemoCore; + + /// + /// Interaction logic for MainWindow.xaml + /// + public partial class MainWindow + { + /// + /// Initializes a new instance of the class. + /// + public MainWindow() + { + this.InitializeComponent(); + this.DataContext = this; + this.Demos = this.GetDemos(this.GetType().Assembly).OrderBy(e => e.Title).ToArray(); + } + + /// + /// Gets the demos. + /// + /// The demos. + public IList Demos { get; private set; } + + /// + /// Creates a thumbnail of the specified window. + /// + /// The window. + /// The width of the thumbnail. + /// The output path. + private static void CreateThumbnail(Window window, int width, string path) + { + var bitmap = ScreenCapture.Capture( + (int)window.Left, + (int)window.Top, + (int)window.ActualWidth, + (int)window.ActualHeight); + var newHeight = width * bitmap.Height / bitmap.Width; + var resizedBitmap = BitmapTools.Resize(bitmap, width, newHeight); + resizedBitmap.Save(path); + } + + /// + /// Handles the MouseDoubleClick event of the ListBox control. + /// + /// The source of the event. + /// The instance containing the event data. + private void ListBoxMouseDoubleClick(object sender, System.Windows.Input.MouseButtonEventArgs args) + { + var lb = (ListBox)sender; + var example = lb.SelectedItem as Demo; + if (example != null) + { + var window = example.Create(); + window.Icon = this.Icon; + window.Show(); + + if (example.Thumbnail == null) + { + } + + window.KeyDown += (s, e) => + { + if (e.Key == Key.F12) + { + CreateThumbnail(window, 120, System.IO.Path.Combine(@"..\..\Images\", example.ThumbnailFileName)); + MessageBox.Show(window, "Demo image updated."); + e.Handled = true; + } + }; + } + } + + /// + /// Gets the examples in the specified assembly. + /// + /// The assembly to search. + /// A sequence of demos. + private IEnumerable GetDemos(Assembly assembly) + { + foreach (var type in assembly.GetTypes()) + { + var ea = type.GetCustomAttributes(typeof(DemoAttribute), false).FirstOrDefault() as DemoAttribute; + if (ea != null) + { + yield return new Demo(type, ea.Title, ea.Description); + } + } + } + } +} diff --git a/Source/Examples/WPF/DrawingDemos/Properties/AssemblyInfo.cs b/Source/Examples/WPF/DrawingDemos/Properties/AssemblyInfo.cs new file mode 100644 index 000000000..7e934f63b --- /dev/null +++ b/Source/Examples/WPF/DrawingDemos/Properties/AssemblyInfo.cs @@ -0,0 +1,24 @@ +using System.Reflection; +using System.Resources; +using System.Runtime.CompilerServices; +using System.Runtime.InteropServices; +using System.Windows; + +//In order to begin building localizable applications, set +//CultureYouAreCodingWith in your .csproj file +//inside a . For example, if you are using US english +//in your source files, set the to en-US. Then uncomment +//the NeutralResourceLanguage attribute below. Update the "en-US" in +//the line below to match the UICulture setting in the project file. + +//[assembly: NeutralResourcesLanguage("en-US", UltimateResourceFallbackLocation.Satellite)] + + +[assembly: ThemeInfo( + ResourceDictionaryLocation.None, //where theme specific resource dictionaries are located + //(used if a resource is not found in the page, + // or application resource dictionaries) + ResourceDictionaryLocation.SourceAssembly //where the generic resource dictionary is located + //(used if a resource is not found in the page, + // app, or any theme specific resource dictionaries) +)] diff --git a/Source/Examples/WPF/DrawingDemos/Properties/Resources.Designer.cs b/Source/Examples/WPF/DrawingDemos/Properties/Resources.Designer.cs new file mode 100644 index 000000000..9d7063a85 --- /dev/null +++ b/Source/Examples/WPF/DrawingDemos/Properties/Resources.Designer.cs @@ -0,0 +1,63 @@ +//------------------------------------------------------------------------------ +// +// This code was generated by a tool. +// Runtime Version:4.0.30319.34014 +// +// Changes to this file may cause incorrect behavior and will be lost if +// the code is regenerated. +// +//------------------------------------------------------------------------------ + +namespace DrawingDemos.Properties { + using System; + + + /// + /// A strongly-typed resource class, for looking up localized strings, etc. + /// + // This class was auto-generated by the StronglyTypedResourceBuilder + // class via a tool like ResGen or Visual Studio. + // To add or remove a member, edit your .ResX file then rerun ResGen + // with the /str option, or rebuild your VS project. + [global::System.CodeDom.Compiler.GeneratedCodeAttribute("System.Resources.Tools.StronglyTypedResourceBuilder", "4.0.0.0")] + [global::System.Diagnostics.DebuggerNonUserCodeAttribute()] + [global::System.Runtime.CompilerServices.CompilerGeneratedAttribute()] + internal class Resources { + + private static global::System.Resources.ResourceManager resourceMan; + + private static global::System.Globalization.CultureInfo resourceCulture; + + [global::System.Diagnostics.CodeAnalysis.SuppressMessageAttribute("Microsoft.Performance", "CA1811:AvoidUncalledPrivateCode")] + internal Resources() { + } + + /// + /// Returns the cached ResourceManager instance used by this class. + /// + [global::System.ComponentModel.EditorBrowsableAttribute(global::System.ComponentModel.EditorBrowsableState.Advanced)] + internal static global::System.Resources.ResourceManager ResourceManager { + get { + if (object.ReferenceEquals(resourceMan, null)) { + global::System.Resources.ResourceManager temp = new global::System.Resources.ResourceManager("DrawingDemos.Properties.Resources", typeof(Resources).Assembly); + resourceMan = temp; + } + return resourceMan; + } + } + + /// + /// Overrides the current thread's CurrentUICulture property for all + /// resource lookups using this strongly typed resource class. + /// + [global::System.ComponentModel.EditorBrowsableAttribute(global::System.ComponentModel.EditorBrowsableState.Advanced)] + internal static global::System.Globalization.CultureInfo Culture { + get { + return resourceCulture; + } + set { + resourceCulture = value; + } + } + } +} diff --git a/Source/Examples/WPF/DrawingDemos/Properties/Resources.resx b/Source/Examples/WPF/DrawingDemos/Properties/Resources.resx new file mode 100644 index 000000000..af7dbebba --- /dev/null +++ b/Source/Examples/WPF/DrawingDemos/Properties/Resources.resx @@ -0,0 +1,117 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + text/microsoft-resx + + + 2.0 + + + System.Resources.ResXResourceReader, System.Windows.Forms, Version=2.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089 + + + System.Resources.ResXResourceWriter, System.Windows.Forms, Version=2.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089 + + \ No newline at end of file diff --git a/Source/Examples/WPF/DrawingDemos/Properties/Settings.Designer.cs b/Source/Examples/WPF/DrawingDemos/Properties/Settings.Designer.cs new file mode 100644 index 000000000..9042e3a86 --- /dev/null +++ b/Source/Examples/WPF/DrawingDemos/Properties/Settings.Designer.cs @@ -0,0 +1,26 @@ +//------------------------------------------------------------------------------ +// +// This code was generated by a tool. +// Runtime Version:4.0.30319.34014 +// +// Changes to this file may cause incorrect behavior and will be lost if +// the code is regenerated. +// +//------------------------------------------------------------------------------ + +namespace DrawingDemos.Properties { + + + [global::System.Runtime.CompilerServices.CompilerGeneratedAttribute()] + [global::System.CodeDom.Compiler.GeneratedCodeAttribute("Microsoft.VisualStudio.Editors.SettingsDesigner.SettingsSingleFileGenerator", "12.0.0.0")] + internal sealed partial class Settings : global::System.Configuration.ApplicationSettingsBase { + + private static Settings defaultInstance = ((Settings)(global::System.Configuration.ApplicationSettingsBase.Synchronized(new Settings()))); + + public static Settings Default { + get { + return defaultInstance; + } + } + } +} diff --git a/Source/Examples/WPF/DrawingDemos/Properties/Settings.settings b/Source/Examples/WPF/DrawingDemos/Properties/Settings.settings new file mode 100644 index 000000000..033d7a5e9 --- /dev/null +++ b/Source/Examples/WPF/DrawingDemos/Properties/Settings.settings @@ -0,0 +1,7 @@ + + + + + + + \ No newline at end of file diff --git a/Source/Examples/WPF/DrawingDemos/ReadMe.txt b/Source/Examples/WPF/DrawingDemos/ReadMe.txt new file mode 100644 index 000000000..014ddb33e --- /dev/null +++ b/Source/Examples/WPF/DrawingDemos/ReadMe.txt @@ -0,0 +1,9 @@ +To create new demos: +1. Copy a folder under Demos/ or Workitems/ +2. Rename and modify +3. Run the demo in Debug mode +4. Press F12 when running the demo to generate a new demo image in the Images/ folder +5. Add the image to the project in the Images/ folder as a resource + +The demos are found by reflection, see the MainWindow.GetDemos method. +Note that the window class must be decorated by an `DemoAttribute`. \ No newline at end of file diff --git a/Source/Examples/WPF/DrawingDemos/app.config b/Source/Examples/WPF/DrawingDemos/app.config new file mode 100644 index 000000000..884f9844f --- /dev/null +++ b/Source/Examples/WPF/DrawingDemos/app.config @@ -0,0 +1,3 @@ + + + diff --git a/Source/OxyPlot.Core.Drawing/OxyPlot.Core.Drawing.csproj b/Source/OxyPlot.Core.Drawing/OxyPlot.Core.Drawing.csproj index 0ab8bedc3..d10e13cab 100644 --- a/Source/OxyPlot.Core.Drawing/OxyPlot.Core.Drawing.csproj +++ b/Source/OxyPlot.Core.Drawing/OxyPlot.Core.Drawing.csproj @@ -5,7 +5,7 @@ - + diff --git a/Source/OxyPlot.WPF.sln b/Source/OxyPlot.WPF.sln index bb1415f5e..5993b6107 100644 --- a/Source/OxyPlot.WPF.sln +++ b/Source/OxyPlot.WPF.sln @@ -44,6 +44,14 @@ Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = "Documentation", "Documentat ..\README.md = ..\README.md EndProjectSection EndProject +Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "DrawingLibrary", "Examples\DrawingLibrary\DrawingLibrary.csproj", "{CE562D06-3069-43F4-8173-840DF9DD8916}" +EndProject +Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "DrawingDemos", "Examples\WPF\DrawingDemos\DrawingDemos.csproj", "{329DFB74-D3FF-4449-BCB5-63DA0819A17A}" +EndProject +Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "DrawingBrowser", "Examples\WPF\DrawingBrowser\DrawingBrowser.csproj", "{CE85749C-5A4D-48D3-9714-DC955FC821FB}" +EndProject +Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "DemoCore", "Examples\WPF\DemoCore\DemoCore.csproj", "{01B36A2D-8977-4FAA-8790-A6614165E98D}" +EndProject Global GlobalSection(SolutionConfigurationPlatforms) = preSolution Debug|Any CPU = Debug|Any CPU @@ -98,6 +106,22 @@ Global {EDD52464-AD60-4EA1-B774-87AAFD930B6B}.Debug|Any CPU.Build.0 = Debug|Any CPU {EDD52464-AD60-4EA1-B774-87AAFD930B6B}.Release|Any CPU.ActiveCfg = Release|Any CPU {EDD52464-AD60-4EA1-B774-87AAFD930B6B}.Release|Any CPU.Build.0 = Release|Any CPU + {CE562D06-3069-43F4-8173-840DF9DD8916}.Debug|Any CPU.ActiveCfg = Debug|Any CPU + {CE562D06-3069-43F4-8173-840DF9DD8916}.Debug|Any CPU.Build.0 = Debug|Any CPU + {CE562D06-3069-43F4-8173-840DF9DD8916}.Release|Any CPU.ActiveCfg = Release|Any CPU + {CE562D06-3069-43F4-8173-840DF9DD8916}.Release|Any CPU.Build.0 = Release|Any CPU + {329DFB74-D3FF-4449-BCB5-63DA0819A17A}.Debug|Any CPU.ActiveCfg = Debug|Any CPU + {329DFB74-D3FF-4449-BCB5-63DA0819A17A}.Debug|Any CPU.Build.0 = Debug|Any CPU + {329DFB74-D3FF-4449-BCB5-63DA0819A17A}.Release|Any CPU.ActiveCfg = Release|Any CPU + {329DFB74-D3FF-4449-BCB5-63DA0819A17A}.Release|Any CPU.Build.0 = Release|Any CPU + {CE85749C-5A4D-48D3-9714-DC955FC821FB}.Debug|Any CPU.ActiveCfg = Debug|Any CPU + {CE85749C-5A4D-48D3-9714-DC955FC821FB}.Debug|Any CPU.Build.0 = Debug|Any CPU + {CE85749C-5A4D-48D3-9714-DC955FC821FB}.Release|Any CPU.ActiveCfg = Release|Any CPU + {CE85749C-5A4D-48D3-9714-DC955FC821FB}.Release|Any CPU.Build.0 = Release|Any CPU + {01B36A2D-8977-4FAA-8790-A6614165E98D}.Debug|Any CPU.ActiveCfg = Debug|Any CPU + {01B36A2D-8977-4FAA-8790-A6614165E98D}.Debug|Any CPU.Build.0 = Debug|Any CPU + {01B36A2D-8977-4FAA-8790-A6614165E98D}.Release|Any CPU.ActiveCfg = Release|Any CPU + {01B36A2D-8977-4FAA-8790-A6614165E98D}.Release|Any CPU.Build.0 = Release|Any CPU EndGlobalSection GlobalSection(SolutionProperties) = preSolution HideSolutionNode = FALSE @@ -109,6 +133,13 @@ Global {831970F4-9390-4214-848B-70E6250443DC} = {B630CA82-A785-49CA-8FA0-3D3AF4D6626A} {B86739B8-5DE9-406F-9418-0751BF7C166F} = {831970F4-9390-4214-848B-70E6250443DC} {EDD52464-AD60-4EA1-B774-87AAFD930B6B} = {B630CA82-A785-49CA-8FA0-3D3AF4D6626A} + {CE562D06-3069-43F4-8173-840DF9DD8916} = {B630CA82-A785-49CA-8FA0-3D3AF4D6626A} + {329DFB74-D3FF-4449-BCB5-63DA0819A17A} = {831970F4-9390-4214-848B-70E6250443DC} + {CE85749C-5A4D-48D3-9714-DC955FC821FB} = {B630CA82-A785-49CA-8FA0-3D3AF4D6626A} + {01B36A2D-8977-4FAA-8790-A6614165E98D} = {B630CA82-A785-49CA-8FA0-3D3AF4D6626A} + EndGlobalSection + GlobalSection(ExtensibilityGlobals) = postSolution + SolutionGuid = {1707D5CE-236F-4333-8B04-2F711F8F2CF8} EndGlobalSection GlobalSection(ExtensibilityGlobals) = postSolution SolutionGuid = {C96D2723-A182-4A28-ABEE-51CEC95FC6E2} diff --git a/Source/OxyPlot.WPF.sln.DotSettings b/Source/OxyPlot.WPF.sln.DotSettings index 30b380a8d..0ae45bf36 100644 --- a/Source/OxyPlot.WPF.sln.DotSettings +++ b/Source/OxyPlot.WPF.sln.DotSettings @@ -26,11 +26,16 @@ NEXT_LINE_SHIFTED_2 1 1 + False + False False public protected internal private static new abstract virtual override sealed readonly extern unsafe volatile async + NEVER False False + NEVER False + ALWAYS False True ON_SINGLE_LINE @@ -524,9 +529,14 @@ <Policy Inspect="True" Prefix="" Suffix="" Style="AaBb" /> <Policy Inspect="True" Prefix="T" Suffix="" Style="AaBb" /> <Policy Inspect="True" Prefix="" Suffix="" Style="AaBb" /> + True True + True + True + True True True + True True True <data /> diff --git a/Source/OxyPlot.Wpf.Tests/PlotViewTests.cs b/Source/OxyPlot.Wpf.Tests/PlotViewTests.cs index 7ea3803da..1bd736760 100644 --- a/Source/OxyPlot.Wpf.Tests/PlotViewTests.cs +++ b/Source/OxyPlot.Wpf.Tests/PlotViewTests.cs @@ -57,7 +57,7 @@ public void GetFromOtherThread() { var model = new PlotModel(); var plotView = new PlotView { Model = model }; - PlotModel actualModel = null; + Model actualModel = null; Task.Factory.StartNew(() => actualModel = plotView.ActualModel).Wait(); Assert.AreEqual(model, actualModel); } diff --git a/Source/OxyPlot.Wpf/Drawing/DrawingView.cs b/Source/OxyPlot.Wpf/Drawing/DrawingView.cs new file mode 100644 index 000000000..6179f3cb8 --- /dev/null +++ b/Source/OxyPlot.Wpf/Drawing/DrawingView.cs @@ -0,0 +1,341 @@ +// -------------------------------------------------------------------------------------------------------------------- +// +// Copyright (c) 2014 OxyPlot contributors +// +// +// Represents a control that displays a DrawingModel. +// +// -------------------------------------------------------------------------------------------------------------------- + +namespace OxyPlot.Wpf +{ + using System; + using System.Diagnostics; + using System.Windows; + using System.Windows.Controls; + using System.Windows.Documents; + using System.Windows.Input; + using System.Windows.Media; + using System.Windows.Threading; + + using OxyPlot.Drawing; + + /// + /// Represents a control that displays a . + /// + public class DrawingView : GraphicsView, IDrawingView + { + /// + /// Identifies the dependency property. + /// + public static readonly DependencyProperty DrawingPaddingProperty = DependencyProperty.Register( + "DrawingPadding", typeof(double), typeof(DrawingView), new PropertyMetadata(10.0)); + + /// + /// Identifies the dependency property. + /// + public static readonly DependencyProperty DrawingProperty = DependencyProperty.Register( + "Drawing", typeof(DrawingModel), typeof(DrawingView), new PropertyMetadata(null, (s, e) => ((DrawingView)s).DrawingChanged())); + + /// + /// The default controller. + /// + private IController defaultController; + + /// + /// The canvas + /// + private Canvas canvas; + + /// + /// The zoom adorner + /// + private RectangleAdorner zoomAdorner; + + /// + /// The render context + /// + private IRenderContext rc; + + /// + /// Initializes static members of the class. + /// + static DrawingView() + { + DefaultStyleKeyProperty.OverrideMetadata(typeof(DrawingView), new FrameworkPropertyMetadata(typeof(DrawingView))); + } + + /// + /// Initializes a new instance of the class. + /// + public DrawingView() + { + this.Loaded += this.ViewLoaded; + this.CommandBindings.Add(new CommandBinding(ApplicationCommands.Copy, (s, e) => this.Copy(), (s, e) => e.CanExecute = this.CanCopy())); + this.CommandBindings.Add(new CommandBinding(DrawingViewCommands.ZoomExtents, (s, e) => this.ZoomExtents(), (s, e) => e.CanExecute = this.CanZoomExtents())); + } + + /// + /// Gets the actual plot controller. + /// + /// The actual plot controller. + public override IController ActualController + { + get + { + return this.Controller ?? (this.defaultController ?? (this.defaultController = this.CreateDefaultController())); + } + } + + /// + /// Gets or sets the drawing. + /// + /// + /// The drawing. + /// + public DrawingModel Drawing + { + get + { + return (DrawingModel)this.GetValue(DrawingProperty); + } + + set + { + this.SetValue(DrawingProperty, value); + } + } + + /// + /// Gets or sets the padding around the drawing. + /// + /// + /// The padding. + /// + public double DrawingPadding + { + get + { + return (double)this.GetValue(DrawingPaddingProperty); + } + + set + { + this.SetValue(DrawingPaddingProperty, value); + } + } + + /// + /// Gets the actual model in the view. + /// + /// + /// The actual . + /// + public override Model ActualModel + { + get + { + return this.Drawing; + } + } + + /// + /// Gets the actual view model. + /// + /// + /// The actual view model. + /// + public DrawingViewModel ActualViewModel + { + get + { + return this.ViewModel as DrawingViewModel; + } + } + + /// + /// Hides the zoom rectangle. + /// + public override void HideZoomRectangle() + { + if (this.zoomAdorner != null) + { + var parentAdorner = AdornerLayer.GetAdornerLayer(this.canvas); + parentAdorner.Remove(this.zoomAdorner); + this.zoomAdorner = null; + } + } + + /// + /// Zooms the extents. + /// + public void ZoomExtents() + { + this.ActualViewModel.ZoomExtents(this.rc); + } + + /// + /// Invalidates the view. + /// + void IDrawingView.Invalidate() + { + this.BeginInvoke(this.InvalidateArrange); + } + + /// + /// Gets the bounding box of the current drawing. + /// + /// The bounding box. + public BoundingBox GetBounds() + { + return this.ActualViewModel.GetBounds(this.rc); + } + + /// + /// When overridden in a derived class, is invoked whenever application code or internal processes call . + /// + public override void OnApplyTemplate() + { + base.OnApplyTemplate(); + this.canvas = (Canvas)this.GetTemplateChild("PART_Canvas"); + this.rc = new CanvasRenderContext(this.canvas); + } + + /// + /// Shows the zoom rectangle. + /// + /// The rectangle. + public override void ShowZoomRectangle(OxyRect rect) + { + if (this.zoomAdorner == null) + { + var parentAdorner = AdornerLayer.GetAdornerLayer(this.canvas); + this.zoomAdorner = new RectangleAdorner(this.canvas); + parentAdorner.Add(this.zoomAdorner); + } + + this.zoomAdorner.Rect = new Rect(rect.Left, rect.Top, rect.Width, rect.Height); // .ToPixelAlignedRect(); + this.zoomAdorner.InvalidateVisual(); + } + + /// + /// Gets the element that the mouse position is relative to. + /// + /// + /// The element. + /// + protected override IInputElement GetRelativeTo() + { + return this.canvas; + } + + /// + /// Called to arrange and size the content of a object. + /// + /// The computed size that is used to arrange the content. + /// + /// The size of the control. + /// + protected override Size ArrangeOverride(Size arrangeBounds) + { + this.Render(); + return base.ArrangeOverride(arrangeBounds); + } + + /// + /// Creates the default controller. + /// + /// + /// The default controller. + /// + protected override IController CreateDefaultController() + { + return new DrawingController(); + } + + /// + /// Invokes the specified action on the UI Thread (without blocking the calling thread). + /// + /// The action. + private void BeginInvoke(Action action) + { + if (!this.Dispatcher.CheckAccess()) + { + this.Dispatcher.BeginInvoke(DispatcherPriority.Background, action); + } + else + { + action(); + } + } + + /// + /// Determines whether this instance can zoom to extents. + /// + /// true if zoom to extents is available; otherwise false. + private bool CanZoomExtents() + { + return this.Drawing != null && this.ActualWidth > 0 && this.ActualHeight > 0 && !this.ActualViewModel.GetBounds(this.rc).IsEmpty(); + } + + /// + /// Copies the current content of the view to the clipboard. + /// + private void Copy() + { + // Clipboard.SetImage(Drawing); + } + + /// + /// Determines whether the content of the view can be copied. + /// + /// true if copy is available; otherwise false. + private bool CanCopy() + { + return this.ActualViewModel != null; + } + + /// + /// Handles changes to the . + /// + private void DrawingChanged() + { + if (this.Drawing == null) + { + this.ViewModel = null; + return; + } + + this.ViewModel = new DrawingViewModel(this, this.Drawing); + this.ActualViewModel.ZoomExtents(this.rc); + } + + /// + /// Handles the loaded event. + /// + /// The sender. + /// The instance containing the event data. + private void ViewLoaded(object sender, RoutedEventArgs e) + { + this.Render(); + } + + /// + /// Renders the content of the view. + /// + private void Render() + { + this.canvas.Children.Clear(); + this.canvas.Background = this.Drawing == null || this.Drawing.Background.IsInvisible() + ? Brushes.Transparent + : this.Drawing.Background.ToBrush(); + + var vm = this.ActualViewModel; + if (vm != null) + { + vm.Update(this.rc); + vm.Render(this.rc); + } + } + } +} diff --git a/Source/OxyPlot.Wpf/Drawing/DrawingViewCommands.cs b/Source/OxyPlot.Wpf/Drawing/DrawingViewCommands.cs new file mode 100644 index 000000000..d868105da --- /dev/null +++ b/Source/OxyPlot.Wpf/Drawing/DrawingViewCommands.cs @@ -0,0 +1,54 @@ +// -------------------------------------------------------------------------------------------------------------------- +// +// Copyright (c) 2014 OxyPlot contributors +// +// +// Provides a standard set of commands for the control. +// +// -------------------------------------------------------------------------------------------------------------------- + +namespace OxyPlot.Wpf +{ + using System.Windows.Input; + + /// + /// Provides a standard set of commands for the control. + /// + public static class DrawingViewCommands + { + /// + /// Initializes static members of the class. + /// + static DrawingViewCommands() + { + ZoomExtents = new RoutedCommand("ZoomExtents", typeof(DrawingViewCommands)); + ZoomExtents.InputGestures.Add(new KeyGesture(Key.A, ModifierKeys.Alt)); + SelectAll = new RoutedCommand("SelectAll", typeof(DrawingViewCommands)); + SelectAll.InputGestures.Add(new KeyGesture(Key.A, ModifierKeys.Control)); + SelectNone = new RoutedCommand("SelectNone", typeof(DrawingViewCommands)); + SelectNone.InputGestures.Add(new KeyGesture(Key.N, ModifierKeys.Control)); + SelectInverse = new RoutedCommand("SelectInverse", typeof(DrawingViewCommands)); + SelectInverse.InputGestures.Add(new KeyGesture(Key.I, ModifierKeys.Control)); + } + + /// + /// Gets the zoom extents command. + /// + public static RoutedCommand ZoomExtents { get; private set; } + + /// + /// Gets the select all command. + /// + public static RoutedCommand SelectAll { get; private set; } + + /// + /// Gets the select none command. + /// + public static RoutedCommand SelectNone { get; private set; } + + /// + /// Gets the select inverse command. + /// + public static RoutedCommand SelectInverse { get; private set; } + } +} \ No newline at end of file diff --git a/Source/OxyPlot.Wpf/Drawing/RectangleAdorner.cs b/Source/OxyPlot.Wpf/Drawing/RectangleAdorner.cs new file mode 100644 index 000000000..044ecad4f --- /dev/null +++ b/Source/OxyPlot.Wpf/Drawing/RectangleAdorner.cs @@ -0,0 +1,59 @@ +// -------------------------------------------------------------------------------------------------------------------- +// +// Copyright (c) 2014 OxyPlot contributors +// +// +// Provides a rectangle adorner. +// +// -------------------------------------------------------------------------------------------------------------------- + +namespace OxyPlot.Wpf +{ + using System.Windows; + using System.Windows.Documents; + using System.Windows.Media; + + /// + /// Provides a rectangle adorner. + /// + public class RectangleAdorner : Adorner + { + /// + /// The brush + /// + private Brush brush; + + /// + /// The pen + /// + private Pen pen; + + /// + /// Initializes a new instance of the class. + /// + /// The element to bind the adorner to. + public RectangleAdorner(UIElement adornedElement) + : base(adornedElement) + { + this.brush = new SolidColorBrush(Color.FromArgb(40, 255, 255, 0)); + this.pen = new Pen(Brushes.Black, 1); + } + + /// + /// Gets or sets the rectangle. + /// + /// + /// The rectangle. + /// + public Rect Rect { get; set; } + + /// + /// Renders the adorner. + /// + /// The drawing context. + protected override void OnRender(DrawingContext dc) + { + dc.DrawRectangle(this.brush, this.pen, this.Rect); + } + } +} \ No newline at end of file diff --git a/Source/OxyPlot.Wpf/Graphics/GraphicsView.cs b/Source/OxyPlot.Wpf/Graphics/GraphicsView.cs new file mode 100644 index 000000000..fd05196b4 --- /dev/null +++ b/Source/OxyPlot.Wpf/Graphics/GraphicsView.cs @@ -0,0 +1,287 @@ +// -------------------------------------------------------------------------------------------------------------------- +// +// Copyright (c) 2014 OxyPlot contributors +// +// +// Provides an abstract base class for graphics controls. +// +// -------------------------------------------------------------------------------------------------------------------- + +namespace OxyPlot.Wpf +{ + using System; + using System.Windows; + using System.Windows.Controls; + using System.Windows.Input; + + /// + /// Provides an abstract base class for graphics controls. + /// + public abstract class GraphicsView : Control, IView + { + /// + /// Identifies the dependency property. + /// + public static readonly DependencyProperty ControllerProperty = + DependencyProperty.Register("Controller", typeof(IController), typeof(GraphicsView), new PropertyMetadata(null)); + + /// + /// The mouse down point + /// + private ScreenPoint mouseDownPoint; + + /// + /// Gets the actual model in the view. + /// + /// + /// The actual . + /// + public abstract Model ActualModel { get; } + + /// + /// Gets or sets the view model. + /// + /// + /// The view model. + /// + public IViewModel ViewModel { get; protected set; } + + /// + /// Gets the coordinates of the client area of the view. + /// + /// + /// The client area rectangle. + /// + OxyRect IView.ClientArea + { + get { return new OxyRect(0, 0, this.ActualWidth, this.ActualHeight); } + } + + /// + /// Gets or sets the plot controller. + /// + /// The plot controller. + public IController Controller + { + get { return (IController)this.GetValue(ControllerProperty); } + set { this.SetValue(ControllerProperty, value); } + } + + /// + /// Gets the actual plot controller. + /// + /// The actual plot controller. + public abstract IController ActualController { get; } + + ///// + ///// Gets the actual plot controller. + ///// + ///// The actual plot controller. + //public IController ActualController + //{ + // get + // { + // return this.Controller ?? (this.defaultController ?? (this.defaultController = this.CreateDefaultController())); + // } + //} + + /// + /// Sets the cursor type. + /// + /// The cursor type. + public void SetCursorType(OxyPlot.CursorType cursorType) + { + switch (cursorType) + { + case OxyPlot.CursorType.Pan: + this.Cursor = Cursors.Hand; + break; + case OxyPlot.CursorType.ZoomRectangle: + this.Cursor = Cursors.SizeNWSE; + break; + case OxyPlot.CursorType.ZoomHorizontal: + this.Cursor = Cursors.SizeWE; + break; + case OxyPlot.CursorType.ZoomVertical: + this.Cursor = Cursors.SizeNS; + break; + default: + this.Cursor = Cursors.Arrow; + break; + } + } + + /// + /// Hides the zoom rectangle. + /// + public virtual void HideZoomRectangle() + { + } + + /// + /// Shows the zoom rectangle. + /// + /// The zoom rectangle. + public virtual void ShowZoomRectangle(OxyRect zoomRectangle) + { + } + + /// + /// Invoked when an unhandled KeyDown attached event reaches an element in its route that is derived from this class. Implement this method to add class handling for this event. + /// + /// The that contains the event data. + protected override void OnKeyDown(KeyEventArgs e) + { + base.OnKeyDown(e); + if (e.Handled) + { + return; + } + + var args = new OxyKeyEventArgs { ModifierKeys = Keyboard.GetModifierKeys(), Key = e.Key.Convert() }; + e.Handled = this.ActualController.HandleKeyDown(this, args); + } + + /// + /// Creates the default controller. + /// + /// The default controller. + protected abstract IController CreateDefaultController(); + + /// + /// Invoked when an unhandled MouseDown attached event reaches an element in its route that is derived from this class. Implement this method to add class handling for this event. + /// + /// The that contains the event data. This event data reports details about the mouse button that was pressed and the handled state. + protected override void OnMouseDown(MouseButtonEventArgs e) + { + base.OnMouseDown(e); + + if (e.Handled) + { + return; + } + + this.Focus(); + this.CaptureMouse(); + + // store the mouse down point, check it when mouse button is released to determine if the context menu should be shown + this.mouseDownPoint = e.GetPosition(this).ToScreenPoint(); + + e.Handled = this.ActualController.HandleMouseDown(this, e.ToMouseDownEventArgs(this, this.GetRelativeTo())); + } + + /// + /// Gets the element that the mouse position is relative to. + /// + /// The element. + protected virtual IInputElement GetRelativeTo() + { + return this; + } + + /// + /// Invoked when an unhandled MouseMove attached event reaches an element in its route that is derived from this class. Implement this method to add class handling for this event. + /// + /// The that contains the event data. + protected override void OnMouseMove(MouseEventArgs e) + { + base.OnMouseMove(e); + + if (e.Handled) + { + return; + } + + e.Handled = this.ActualController.HandleMouseMove(this, e.ToMouseEventArgs(this, this.GetRelativeTo())); + } + + /// + /// Invoked when an unhandled MouseUp routed event reaches an element in its route that is derived from this class. Implement this method to add class handling for this event. + /// + /// The that contains the event data. The event data reports that the mouse button was released. + protected override void OnMouseUp(MouseButtonEventArgs e) + { + base.OnMouseUp(e); + + if (e.Handled) + { + return; + } + + this.ReleaseMouseCapture(); + + if (this.ActualController.HandleMouseUp(this, e.ToMouseReleasedEventArgs(this, this.GetRelativeTo()))) + { + e.Handled = true; + return; + } + + // Open the context menu + var p = e.GetPosition(this).ToScreenPoint(); + double d = p.DistanceTo(this.mouseDownPoint); + + if (this.ContextMenu != null) + { + if (Math.Abs(d) < 1e-8 && e.ChangedButton == MouseButton.Right) + { + // TODO: why is the data context not passed to the context menu?? + this.ContextMenu.DataContext = this.DataContext; + + this.ContextMenu.Visibility = Visibility.Visible; + this.ContextMenu.IsOpen = true; + } + else + { + this.ContextMenu.Visibility = Visibility.Collapsed; + this.ContextMenu.IsOpen = false; + } + } + } + + /// + /// Invoked when an unhandled  attached event is raised on this element. Implement this method to add class handling for this event. + /// + /// The that contains the event data. + protected override void OnMouseEnter(MouseEventArgs e) + { + base.OnMouseEnter(e); + if (e.Handled) + { + return; + } + + e.Handled = this.ActualController.HandleMouseEnter(this, e.ToMouseEventArgs(this, this.GetRelativeTo())); + } + + /// + /// Invoked when an unhandled  attached event is raised on this element. Implement this method to add class handling for this event. + /// + /// The that contains the event data. + protected override void OnMouseLeave(MouseEventArgs e) + { + base.OnMouseEnter(e); + if (e.Handled) + { + return; + } + + e.Handled = this.ActualController.HandleMouseLeave(this, e.ToMouseEventArgs(this, this.GetRelativeTo())); + } + + /// + /// Invoked when an unhandled MouseWheel attached event reaches an element in its route that is derived from this class. Implement this method to add class handling for this event. + /// + /// The that contains the event data. + protected override void OnPreviewMouseWheel(MouseWheelEventArgs e) + { + base.OnPreviewMouseWheel(e); + + if (e.Handled) + { + return; + } + + e.Handled = this.ActualController.HandleMouseWheel(this, e.ToMouseWheelEventArgs(this.GetRelativeTo())); + } + } +} diff --git a/Source/OxyPlot.Wpf/OxyPlot.Wpf.csproj b/Source/OxyPlot.Wpf/OxyPlot.Wpf.csproj index f262dec78..76dc64abe 100644 --- a/Source/OxyPlot.Wpf/OxyPlot.Wpf.csproj +++ b/Source/OxyPlot.Wpf/OxyPlot.Wpf.csproj @@ -86,6 +86,10 @@ + + + + diff --git a/Source/OxyPlot.Wpf/Plot.cs b/Source/OxyPlot.Wpf/Plot.cs index efc869c27..170f7bbdd 100644 --- a/Source/OxyPlot.Wpf/Plot.cs +++ b/Source/OxyPlot.Wpf/Plot.cs @@ -76,7 +76,7 @@ public ObservableCollection Annotations /// Gets the actual model. /// /// The actual model. - public override PlotModel ActualModel + public override Model ActualModel { get { @@ -88,7 +88,7 @@ public override PlotModel ActualModel /// Gets the actual Plot controller. /// /// The actual Plot controller. - public override IPlotController ActualController + public override IController ActualController { get { diff --git a/Source/OxyPlot.Wpf/PlotBase.Events.cs b/Source/OxyPlot.Wpf/PlotBase.Events.cs index 9f126b6b2..7e61099c7 100644 --- a/Source/OxyPlot.Wpf/PlotBase.Events.cs +++ b/Source/OxyPlot.Wpf/PlotBase.Events.cs @@ -111,7 +111,7 @@ protected override void OnMouseDown(MouseButtonEventArgs e) // store the mouse down point, check it when mouse button is released to determine if the context menu should be shown this.mouseDownPoint = e.GetPosition(this).ToScreenPoint(); - e.Handled = this.ActualController.HandleMouseDown(this, e.ToMouseDownEventArgs(this)); + e.Handled = this.ActualController.HandleMouseDown(this, e.ToMouseDownEventArgs(this, this.GetRelativeTo())); } /// @@ -126,7 +126,7 @@ protected override void OnMouseMove(MouseEventArgs e) return; } - e.Handled = this.ActualController.HandleMouseMove(this, e.ToMouseEventArgs(this)); + e.Handled = this.ActualController.HandleMouseMove(this, e.ToMouseEventArgs(this, this.GetRelativeTo())); } /// @@ -143,7 +143,7 @@ protected override void OnMouseUp(MouseButtonEventArgs e) this.ReleaseMouseCapture(); - e.Handled = this.ActualController.HandleMouseUp(this, e.ToMouseReleasedEventArgs(this)); + e.Handled = this.ActualController.HandleMouseUp(this, e.ToMouseReleasedEventArgs(this, this.GetRelativeTo())); // Open the context menu var p = e.GetPosition(this).ToScreenPoint(); @@ -179,7 +179,7 @@ protected override void OnMouseEnter(MouseEventArgs e) return; } - e.Handled = this.ActualController.HandleMouseEnter(this, e.ToMouseEventArgs(this)); + e.Handled = this.ActualController.HandleMouseEnter(this, e.ToMouseEventArgs(this, this.GetRelativeTo())); } /// @@ -194,7 +194,7 @@ protected override void OnMouseLeave(MouseEventArgs e) return; } - e.Handled = this.ActualController.HandleMouseLeave(this, e.ToMouseEventArgs(this)); + e.Handled = this.ActualController.HandleMouseLeave(this, e.ToMouseEventArgs(this, this.GetRelativeTo())); } } } diff --git a/Source/OxyPlot.Wpf/PlotBase.Export.cs b/Source/OxyPlot.Wpf/PlotBase.Export.cs index eb9e2b615..e4aca40b6 100644 --- a/Source/OxyPlot.Wpf/PlotBase.Export.cs +++ b/Source/OxyPlot.Wpf/PlotBase.Export.cs @@ -22,7 +22,7 @@ public partial class PlotBase /// Name of the file. public void SaveBitmap(string fileName) { - this.SaveBitmap(fileName, -1, -1, this.ActualModel.Background); + this.SaveBitmap(fileName, -1, -1, ((IPlotView)this).ActualModel.Background); } /// @@ -49,7 +49,7 @@ public void SaveBitmap(string fileName, int width, int height, OxyColor backgrou background = this.Background.ToOxyColor(); } - PngExporter.Export(this.ActualModel, fileName, width, height, background); + PngExporter.Export(((IPlotView)this).ActualModel, fileName, width, height, background); } /// @@ -58,8 +58,8 @@ public void SaveBitmap(string fileName, int width, int height, OxyColor backgrou /// Name of the file. public void SaveXaml(string fileName) { - var background = this.ActualModel.Background.IsVisible() ? this.ActualModel.Background : this.Background.ToOxyColor(); - XamlExporter.Export(this.ActualModel, fileName, this.ActualWidth, this.ActualHeight, background); + var background = ((IPlotView)this).ActualModel.Background.IsVisible() ? ((IPlotView)this).ActualModel.Background : this.Background.ToOxyColor(); + XamlExporter.Export(((IPlotView)this).ActualModel, fileName, this.ActualWidth, this.ActualHeight, background); } /// @@ -68,8 +68,8 @@ public void SaveXaml(string fileName) /// The xaml. public string ToXaml() { - var background = this.ActualModel.Background.IsVisible() ? this.ActualModel.Background : this.Background.ToOxyColor(); - return XamlExporter.ExportToString(this.ActualModel, this.ActualWidth, this.ActualHeight, background); + var background = ((IPlotView)this).ActualModel.Background.IsVisible() ? ((IPlotView)this).ActualModel.Background : this.Background.ToOxyColor(); + return XamlExporter.ExportToString(((IPlotView)this).ActualModel, this.ActualWidth, this.ActualHeight, background); } /// @@ -78,8 +78,8 @@ public string ToXaml() /// A bitmap. public BitmapSource ToBitmap() { - var background = this.ActualModel.Background.IsVisible() ? this.ActualModel.Background : this.Background.ToOxyColor(); - return PngExporter.ExportToBitmap(this.ActualModel, (int)this.ActualWidth, (int)this.ActualHeight, background); + var background = ((IPlotView)this).ActualModel.Background.IsVisible() ? ((IPlotView)this).ActualModel.Background : this.Background.ToOxyColor(); + return PngExporter.ExportToBitmap(((IPlotView)this).ActualModel, (int)this.ActualWidth, (int)this.ActualHeight, background); } } } diff --git a/Source/OxyPlot.Wpf/PlotBase.cs b/Source/OxyPlot.Wpf/PlotBase.cs index 0e4d4daa6..d7b796cfa 100644 --- a/Source/OxyPlot.Wpf/PlotBase.cs +++ b/Source/OxyPlot.Wpf/PlotBase.cs @@ -24,7 +24,7 @@ namespace OxyPlot.Wpf /// /// Represents a control that displays a . /// - public abstract partial class PlotBase : Control, IPlotView + public abstract partial class PlotBase : GraphicsView, IPlotView { /// /// The Grid PART constant. @@ -69,7 +69,7 @@ public abstract partial class PlotBase : Control, IPlotView /// /// The mouse down point. /// - private ScreenPoint mouseDownPoint; + protected ScreenPoint mouseDownPoint; /// /// The overlays. @@ -129,10 +129,18 @@ Model IView.ActualModel } /// - /// Gets the actual model. + /// Gets the actual model in the view. /// - /// The actual model. - public abstract PlotModel ActualModel { get; } + /// + /// The actual model. + /// + PlotModel IPlotView.ActualModel + { + get + { + return (PlotModel)this.ActualModel; + } + } /// /// Gets the actual controller. @@ -148,12 +156,6 @@ IController IView.ActualController } } - /// - /// Gets the actual PlotView controller. - /// - /// The actual PlotView controller. - public abstract IPlotController ActualController { get; } - /// /// Gets the coordinates of the client area of the view. /// @@ -193,7 +195,7 @@ public void HideTracker() /// /// Hides the zoom rectangle. /// - public void HideZoomRectangle() + public override void HideZoomRectangle() { this.zoomControl.Visibility = Visibility.Collapsed; } @@ -206,7 +208,7 @@ public void PanAllAxes(Vector delta) { if (this.ActualModel != null) { - this.ActualModel.PanAllAxes(delta.X, delta.Y); + ((IPlotView)this).ActualModel.PanAllAxes(delta.X, delta.Y); } this.InvalidatePlot(false); @@ -220,7 +222,7 @@ public void ZoomAllAxes(double factor) { if (this.ActualModel != null) { - this.ActualModel.ZoomAllAxes(factor); + ((IPlotView)this).ActualModel.ZoomAllAxes(factor); } this.InvalidatePlot(false); @@ -233,7 +235,7 @@ public void ResetAllAxes() { if (this.ActualModel != null) { - this.ActualModel.ResetAllAxes(); + ((IPlotView)this).ActualModel.ResetAllAxes(); } this.InvalidatePlot(false); @@ -292,33 +294,7 @@ public override void OnApplyTemplate() mouseGrid.Background = Brushes.Transparent; // background must be set for hit test to work this.grid.Children.Add(mouseGrid); } - - /// - /// Sets the cursor type. - /// - /// The cursor type. - public void SetCursorType(CursorType cursorType) - { - switch (cursorType) - { - case CursorType.Pan: - this.Cursor = this.PanCursor; - break; - case CursorType.ZoomRectangle: - this.Cursor = this.ZoomRectangleCursor; - break; - case CursorType.ZoomHorizontal: - this.Cursor = this.ZoomHorizontalCursor; - break; - case CursorType.ZoomVertical: - this.Cursor = this.ZoomVerticalCursor; - break; - default: - this.Cursor = Cursors.Arrow; - break; - } - } - + /// /// Shows the tracker. /// @@ -368,7 +344,7 @@ public void ShowTracker(TrackerHitResult trackerHitResult) /// Shows the zoom rectangle. /// /// The rectangle. - public void ShowZoomRectangle(OxyRect r) + public override void ShowZoomRectangle(OxyRect r) { this.zoomControl.Width = r.Width; this.zoomControl.Height = r.Height; @@ -387,6 +363,17 @@ public void SetClipboardText(string text) Clipboard.SetText(text); } + /// + /// Creates the default controller. + /// + /// + /// The default controller. + /// + protected override IController CreateDefaultController() + { + return new PlotController(); + } + /// /// Provides the behavior for the Arrange pass of Silverlight layout. Classes can override this method to define their own Arrange pass behavior. /// @@ -470,14 +457,14 @@ private bool IsUserVisible(FrameworkElement element, FrameworkElement container) /// The instance containing the event data. private void DoCopy(object sender, ExecutedRoutedEventArgs e) { - var background = this.ActualModel.Background.IsVisible() ? this.ActualModel.Background : this.Background.ToOxyColor(); + var background = ((IPlotView)this).ActualModel.Background.IsVisible() ? ((IPlotView)this).ActualModel.Background : this.Background.ToOxyColor(); if (background.IsInvisible()) { background = OxyColors.White; } var bitmap = PngExporter.ExportToBitmap( - this.ActualModel, (int)this.ActualWidth, (int)this.ActualHeight, background); + ((IPlotView)this).ActualModel, (int)this.ActualWidth, (int)this.ActualHeight, background); Clipboard.SetImage(bitmap); } @@ -573,9 +560,9 @@ private void UpdateVisuals() // Clear the canvas this.canvas.Children.Clear(); - if (this.ActualModel != null && this.ActualModel.Background.IsVisible()) + if (this.ActualModel != null && ((IPlotView)this).ActualModel.Background.IsVisible()) { - this.canvas.Background = this.ActualModel.Background.ToBrush(); + this.canvas.Background = ((IPlotView)this).ActualModel.Background.ToBrush(); } else { diff --git a/Source/OxyPlot.Wpf/PlotView.cs b/Source/OxyPlot.Wpf/PlotView.cs index 3905ce027..9fe5cb0d6 100644 --- a/Source/OxyPlot.Wpf/PlotView.cs +++ b/Source/OxyPlot.Wpf/PlotView.cs @@ -9,8 +9,12 @@ namespace OxyPlot.Wpf { + using System; + using System.Threading; using System.Windows; using System.Windows.Controls; + using System.Windows.Input; + using System.Windows.Media; /// /// Represents a control that displays a . @@ -18,12 +22,6 @@ namespace OxyPlot.Wpf [TemplatePart(Name = PartGrid, Type = typeof(Grid))] public class PlotView : PlotBase { - /// - /// Identifies the dependency property. - /// - public static readonly DependencyProperty ControllerProperty = - DependencyProperty.Register("Controller", typeof(IPlotController), typeof(PlotView)); - /// /// Identifies the dependency property. /// @@ -71,28 +69,11 @@ public PlotModel Model } } - /// - /// Gets or sets the Plot controller. - /// - /// The Plot controller. - public IPlotController Controller - { - get - { - return (IPlotController)this.GetValue(ControllerProperty); - } - - set - { - this.SetValue(ControllerProperty, value); - } - } - /// /// Gets the actual model. /// /// The actual model. - public override PlotModel ActualModel + public override Model ActualModel { get { @@ -104,7 +85,7 @@ public override PlotModel ActualModel /// Gets the actual PlotView controller. /// /// The actual PlotView controller. - public override IPlotController ActualController + public override IController ActualController { get { @@ -120,6 +101,156 @@ protected void OnAppearanceChanged() this.InvalidatePlot(false); } + /// + /// Invoked when an unhandled KeyDown attached event reaches an element in its route that is derived from this class. Implement this method to add class handling for this event. + /// + /// The that contains the event data. + protected override void OnKeyDown(KeyEventArgs e) + { + base.OnKeyDown(e); + if (e.Handled) + { + return; + } + + var args = new OxyKeyEventArgs { ModifierKeys = Keyboard.GetModifierKeys(), Key = e.Key.Convert() }; + e.Handled = this.ActualController.HandleKeyDown(this, args); + } + + /// + /// Invoked when an unhandled MouseDown attached event reaches an element in its route that is derived from this class. Implement this method to add class handling for this event. + /// + /// The that contains the event data. This event data reports details about the mouse button that was pressed and the handled state. + protected override void OnMouseDown(MouseButtonEventArgs e) + { + base.OnMouseDown(e); + + if (e.Handled) + { + return; + } + + this.Focus(); + this.CaptureMouse(); + + // store the mouse down point, check it when mouse button is released to determine if the context menu should be shown + this.mouseDownPoint = e.GetPosition(this).ToScreenPoint(); + + e.Handled = this.ActualController.HandleMouseDown(this, e.ToMouseDownEventArgs(null, this)); + } + + /// + /// Invoked when an unhandled MouseMove attached event reaches an element in its route that is derived from this class. Implement this method to add class handling for this event. + /// + /// The that contains the event data. + protected override void OnMouseMove(MouseEventArgs e) + { + base.OnMouseMove(e); + + if (e.Handled) + { + return; + } + + e.Handled = this.ActualController.HandleMouseMove(this, e.ToMouseEventArgs(null, this)); + } + + /// + /// Invoked when an unhandled MouseUp routed event reaches an element in its route that is derived from this class. Implement this method to add class handling for this event. + /// + /// The that contains the event data. The event data reports that the mouse button was released. + protected override void OnMouseUp(MouseButtonEventArgs e) + { + base.OnMouseUp(e); + + if (e.Handled) + { + return; + } + + this.ReleaseMouseCapture(); + + e.Handled = this.ActualController.HandleMouseUp(this, e.ToMouseReleasedEventArgs(null, this)); + + // Open the context menu + var p = e.GetPosition(this).ToScreenPoint(); + double d = p.DistanceTo(this.mouseDownPoint); + + if (this.ContextMenu != null) + { + if (Math.Abs(d) < 1e-8 && e.ChangedButton == MouseButton.Right) + { + // TODO: why is the data context not passed to the context menu?? + this.ContextMenu.DataContext = this.DataContext; + + this.ContextMenu.Visibility = Visibility.Visible; + this.ContextMenu.IsOpen = true; + } + else + { + this.ContextMenu.Visibility = Visibility.Collapsed; + this.ContextMenu.IsOpen = false; + } + } + } + + /// + /// Invoked when an unhandled  attached event is raised on this element. Implement this method to add class handling for this event. + /// + /// The that contains the event data. + protected override void OnMouseEnter(MouseEventArgs e) + { + base.OnMouseEnter(e); + if (e.Handled) + { + return; + } + + e.Handled = this.ActualController.HandleMouseEnter(this, e.ToMouseEventArgs(null, this)); + } + + /// + /// Invoked when an unhandled  attached event is raised on this element. Implement this method to add class handling for this event. + /// + /// The that contains the event data. + protected override void OnMouseLeave(MouseEventArgs e) + { + base.OnMouseEnter(e); + if (e.Handled) + { + return; + } + + e.Handled = this.ActualController.HandleMouseLeave(this, e.ToMouseEventArgs(null, this)); + } + + /// + /// Invoked when an unhandled MouseWheel attached event reaches an element in its route that is derived from this class. Implement this method to add class handling for this event. + /// + /// The that contains the event data. + protected override void OnMouseWheel(MouseWheelEventArgs e) + { + base.OnMouseWheel(e); + + if (e.Handled || !this.IsMouseWheelEnabled) + { + return; + } + + e.Handled = this.ActualController.HandleMouseWheel(this, e.ToMouseWheelEventArgs(this)); + } + + /// + /// Called when the parent of visual object is changed. + /// + /// A value of type that represents the previous parent of the object. If the object did not have a previous parent, the value of the parameter is null. + protected override void OnVisualParentChanged(DependencyObject oldParent) + { + base.OnVisualParentChanged(oldParent); + var parent = VisualTreeHelper.GetParent(this); + // this.IsRendering = parent != null && this.IsLoaded; + } + /// /// Called when the visual appearance is changed. /// diff --git a/Source/OxyPlot.Wpf/Themes/Generic.xaml b/Source/OxyPlot.Wpf/Themes/Generic.xaml index 6941192b0..bff3235d9 100644 --- a/Source/OxyPlot.Wpf/Themes/Generic.xaml +++ b/Source/OxyPlot.Wpf/Themes/Generic.xaml @@ -105,4 +105,17 @@ - \ No newline at end of file + + diff --git a/Source/OxyPlot.Wpf/Utilities/ConverterExtensions.cs b/Source/OxyPlot.Wpf/Utilities/ConverterExtensions.cs index f8242cc7d..25738fe3a 100644 --- a/Source/OxyPlot.Wpf/Utilities/ConverterExtensions.cs +++ b/Source/OxyPlot.Wpf/Utilities/ConverterExtensions.cs @@ -397,12 +397,16 @@ public static OxyMouseWheelEventArgs ToMouseWheelEventArgs(this MouseWheelEventA /// Converts to for a mouse down event. /// /// The instance containing the event data. + /// The view. /// The that the event is relative to. - /// A containing the converted event arguments. - public static OxyMouseDownEventArgs ToMouseDownEventArgs(this MouseButtonEventArgs e, IInputElement relativeTo) + /// + /// A containing the converted event arguments. + /// + public static OxyMouseDownEventArgs ToMouseDownEventArgs(this MouseButtonEventArgs e, IView view, IInputElement relativeTo) { return new OxyMouseDownEventArgs { + View = view, ChangedButton = e.ChangedButton.Convert(), ClickCount = e.ClickCount, Position = e.GetPosition(relativeTo).ToScreenPoint(), @@ -414,12 +418,16 @@ public static OxyMouseDownEventArgs ToMouseDownEventArgs(this MouseButtonEventAr /// Converts to for a mouse up event. /// /// The instance containing the event data. + /// The view. /// The that the event is relative to. - /// A containing the converted event arguments. - public static OxyMouseEventArgs ToMouseReleasedEventArgs(this MouseButtonEventArgs e, IInputElement relativeTo) + /// + /// A containing the converted event arguments. + /// + public static OxyMouseEventArgs ToMouseReleasedEventArgs(this MouseButtonEventArgs e, IView view, IInputElement relativeTo) { return new OxyMouseEventArgs { + View = view, Position = e.GetPosition(relativeTo).ToScreenPoint(), ModifierKeys = Keyboard.GetModifierKeys() }; @@ -429,12 +437,16 @@ public static OxyMouseEventArgs ToMouseReleasedEventArgs(this MouseButtonEventAr /// Converts to for a mouse event. /// /// The instance containing the event data. + /// The view. /// The that the event is relative to. - /// A containing the converted event arguments. - public static OxyMouseEventArgs ToMouseEventArgs(this MouseEventArgs e, IInputElement relativeTo) + /// + /// A containing the converted event arguments. + /// + public static OxyMouseEventArgs ToMouseEventArgs(this MouseEventArgs e, IView view, IInputElement relativeTo) { return new OxyMouseEventArgs { + View = view, Position = e.GetPosition(relativeTo).ToScreenPoint(), ModifierKeys = Keyboard.GetModifierKeys() }; diff --git a/Source/OxyPlot.XamarinForms/OxyPlot.XamarinForms.csproj.bak b/Source/OxyPlot.XamarinForms/OxyPlot.XamarinForms.csproj.bak new file mode 100644 index 000000000..72bd60759 --- /dev/null +++ b/Source/OxyPlot.XamarinForms/OxyPlot.XamarinForms.csproj.bak @@ -0,0 +1,70 @@ + + + + Debug + AnyCPU + {786C830F-07A1-408B-BD7F-6EE04809D6DB};{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC} + 8.0.30703 + 2.0 + {B63C5F8C-61C8-4E69-93D6-F49F816D3746} + Library + OxyPlot.XamarinForms + OxyPlot.XamarinForms + Profile78 + v4.5 + ..\ + ..\ + true + + + true + full + false + bin\Debug + DEBUG; + prompt + 4 + false + + + full + true + bin\Release + prompt + 4 + false + + + + + Properties\GlobalAssemblyInfo.cs + + + + + + + + ..\packages\Xamarin.Forms.1.0.6186\lib\portable-win+net45+wp80+MonoAndroid10+MonoTouch10\Xamarin.Forms.Core.dll + + + ..\packages\Xamarin.Forms.1.0.6186\lib\portable-win+net45+wp80+MonoAndroid10+MonoTouch10\Xamarin.Forms.Xaml.dll + + + + + + + + {7A0B35C0-DD17-4964-8E9A-44D6CECDC692} + OxyPlot + + + + + + This project references NuGet package(s) that are missing on this computer. Enable NuGet Package Restore to download them. For more information, see http://go.microsoft.com/fwlink/?LinkID=322105. The missing file is {0}. + + + + \ No newline at end of file diff --git a/Source/OxyPlot/ClassDiagrams/Drawing.cd b/Source/OxyPlot/ClassDiagrams/Drawing.cd new file mode 100644 index 000000000..c4e22d235 --- /dev/null +++ b/Source/OxyPlot/ClassDiagrams/Drawing.cd @@ -0,0 +1,224 @@ + + + + + + AEQAAAAEAAhABgAAEIQAQAQCAAAgAAAAgVAAgAAAEAg= + Drawing\DrawingView\DrawingViewModel.cs + + + + + + + AAIAAAAEAQAAABAABAAQBAAAAAABAAAAAAAgAABAAAA= + Drawing\DrawingModel\DrawingModel.cs + + + + + + AAAAABAAgAAAAAAAIAAAAgAAAgAAAAAAAAAAAAAAEAE= + Drawing\DrawingModel\DrawingElement.cs + + + + + + + AAAAAAAAAAAAgAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA= + Drawing\DrawingModel\PointsElement.cs + + + + + + AAAAAAAAAAABAAAIAAAAAAAAAAgACAAAAAAACAAAAAA= + Drawing\DrawingModel\ShapeElement.cs + + + + + + AAAAAAAAAAABACAAABAAIAAAAAAAAAAAACAAgAAAAAA= + Drawing\DrawingModel\StrokedElement.cs + + + + + + AAAAAAAAAAAAQAAAYAAAAAAAABAAAAAAgAAAgAAAAAg= + Drawing\DrawingModel\Elements\Arrow.cs + + + + + + AAAAAAAAAAAAAAAAIAAAGAAAAAAAAAAAAAAAAAAIAAA= + Drawing\DrawingModel\Elements\Ellipse.cs + + + + + + AAAQAAAAABAAAIACIAAAgAAAAAAAAAAAAAAAAAAAAAA= + Drawing\DrawingModel\Elements\Grid.cs + + + + + + AAAAEAAABgAAAIIAIAAAgEQGAAAAAAAAAAAAAAAAYAA= + Drawing\DrawingModel\Elements\Image.cs + + + + + + AAAAAAAAAAAAAAAAAAAAAAAAAAAAAIAAAAAAAAAAAAA= + Drawing\DrawingModel\Elements\Interpolation.cs + + + + + + AAIAAAAAAAAAAAAAIAAAAAAAAAAAAAAAAAAAAAAAAAA= + Drawing\DrawingModel\Elements\Lines.cs + + + + + + AAAAAAAAAAAAgAAAIBAAAAAAAAAAAAAAACAAAAAAAAA= + Drawing\DrawingModel\Elements\Polygon.cs + + + + + + AAIAAAAAAAAAAAAAIAAAAAAAAAAAAAAAAAAAAAAAAAA= + Drawing\DrawingModel\Elements\Polyline.cs + + + + + + AAAAEAAAAAAQAIAAIAAAgAAAAAAAAAAAAAAAAAAAAAA= + Drawing\DrawingModel\Elements\Rectangle.cs + + + + + + AAAAAAAAAAAAAAAAIAAAAAAAAAAAAAAAAAAABAAAAAA= + Drawing\DrawingModel\Elements\RoundedRectangle.cs + + + + + + AAAAAAAgAgAAgAAAoAAAAAAAEAAAAAAAAAAAgAAAAAA= + Drawing\DrawingModel\Elements\Text.cs + + + + + + BEAgEAEAAgAAAAMAICBAAgQSkASAAAAIAAEAAAAAAAA= + Drawing\DrawingModel\Elements\TileLayer.cs + + + + + + AAAAAAAAAAAAAEAgIAAAAAAAAAAAAAAAAAAAAAACAEA= + Drawing\DrawingModel\Elements\UmlClassBox.cs + + + + + + AAAAAAAAAABAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA= + Drawing\DrawingController\DrawingController.cs + + + + + + AABApQACAFBAECCQAAIAAIAIAQQAAACAAEBEgAJAAgo= + Graphics\ControllerBase.cs + + + + + + + AAAgBAAIABBCgGCQAgJAEIBAARIBEAFEIEgAAhDCEgI= + Graphics\Model.cs + + + + + + AAAAAAAAAABAgEAAAAAAAAAAARIAEAFEIAAAAhCCAAA= + Graphics\UIElement.cs + + + + + + AAAAABAAABQAEAAAAAAAAgIAAAAAACAAAARBQAEKEgA= + Graphics\SelectableElement.cs + + + + + + AAAAAAAAAAAAAAAAAAAAQAAAAAAAAAAAAAAAAAAAAAA= + Graphics\Element.cs + + + + + + AAAAQAAAAEAAAACAAAAIAAAACAAAAAAAAAAAAAAAAAA= + Drawing\DrawingModel\Elements\LatLon.cs + + + + + + AAQAAAAEAAhAAAAAAIAAQAQAAAAAAAAAABAAAAAAEAA= + Drawing\DrawingView\IDrawingViewModel.cs + + + + + + AAAEAAAEAAgAAAAAAIAAAAAAAAAAAAAAEAAAAAAAAAA= + Drawing\DrawingView\IDrawingView.cs + + + + + + AAAABAAAAAAAAAAAAQAEAEAAAAAAAAAAAAAAAAAgEAA= + Graphics\IView.cs + + + + + + AAAAAAAAAAAABgAAEAAAAAAAAAAAAAAAAAAAAAAAAAA= + Graphics\IViewModel.cs + + + + + + AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAQAAAAAAAAAAAA= + Drawing\DrawingModel\IDrawingElement.cs + + + + \ No newline at end of file diff --git a/Source/OxyPlot/Drawing/DrawingController/DelegateDrawingCommand.cs b/Source/OxyPlot/Drawing/DrawingController/DelegateDrawingCommand.cs new file mode 100644 index 000000000..fa5e9413d --- /dev/null +++ b/Source/OxyPlot/Drawing/DrawingController/DelegateDrawingCommand.cs @@ -0,0 +1,30 @@ +// -------------------------------------------------------------------------------------------------------------------- +// +// Copyright (c) 2014 OxyPlot contributors +// +// +// Provides a controller command for the IDrawingView implemented by a delegate. +// +// -------------------------------------------------------------------------------------------------------------------- + +namespace OxyPlot.Drawing +{ + using System; + + /// + /// Provides a controller command for the implemented by a delegate. + /// + /// The type of the event arguments. + public class DelegateDrawingCommand : DelegateViewCommand + where T : OxyInputEventArgs + { + /// + /// Initializes a new instance of the class. + /// + /// The handler. + public DelegateDrawingCommand(Action handler) + : base((v, c, e) => handler((IDrawingView)v, c, e)) + { + } + } +} \ No newline at end of file diff --git a/Source/OxyPlot/Drawing/DrawingController/DrawingCommands.cs b/Source/OxyPlot/Drawing/DrawingController/DrawingCommands.cs new file mode 100644 index 000000000..c3e0fbfbe --- /dev/null +++ b/Source/OxyPlot/Drawing/DrawingController/DrawingCommands.cs @@ -0,0 +1,213 @@ +// -------------------------------------------------------------------------------------------------------------------- +// +// Copyright (c) 2014 OxyPlot contributors +// +// +// Defines commands for the DrawingController. +// +// -------------------------------------------------------------------------------------------------------------------- + +namespace OxyPlot.Drawing +{ + /// + /// Defines commands for the DrawingController. + /// + public static class DrawingCommands + { + /// + /// Initializes static members of the class. + /// + static DrawingCommands() + { + // commands that can be triggered from key events + Reset = new DelegateDrawingCommand((view, controller, args) => HandleReset(view)); + + // commands that can be triggered from mouse down events + ResetAt = new DelegateDrawingCommand((view, controller, args) => HandleReset(view)); + PanAt = new DelegateDrawingCommand((view, controller, args) => controller.AddMouseManipulator(view, new PanManipulator(view), args)); + ZoomRectangle = new DelegateDrawingCommand((view, controller, args) => controller.AddMouseManipulator(view, new ZoomRectangleManipulator(view), args)); + ZoomWheel = new DelegateDrawingCommand((view, controller, args) => HandleZoomByWheel(view, args)); + ZoomWheelFine = new DelegateDrawingCommand((view, controller, args) => HandleZoomByWheel(view, args, 0.1)); + ZoomInAt = new DelegateDrawingCommand((view, controller, args) => HandleZoomAt(view, args, 0.05)); + ZoomOutAt = new DelegateDrawingCommand((view, controller, args) => HandleZoomAt(view, args, -0.05)); + + PanZoomByTouch = new DelegateDrawingCommand((view, controller, args) => controller.AddTouchManipulator(view, new TouchManipulator(view), args)); + + // commands that can be triggered from key events + PanLeft = new DelegateDrawingCommand((view, controller, args) => HandlePan(view, -0.1, 0)); + PanRight = new DelegateDrawingCommand((view, controller, args) => HandlePan(view, 0.1, 0)); + PanUp = new DelegateDrawingCommand((view, controller, args) => HandlePan(view, 0, -0.1)); + PanDown = new DelegateDrawingCommand((view, controller, args) => HandlePan(view, 0, 0.1)); + PanLeftFine = new DelegateDrawingCommand((view, controller, args) => HandlePan(view, -0.01, 0)); + PanRightFine = new DelegateDrawingCommand((view, controller, args) => HandlePan(view, 0.01, 0)); + PanUpFine = new DelegateDrawingCommand((view, controller, args) => HandlePan(view, 0, -0.01)); + PanDownFine = new DelegateDrawingCommand((view, controller, args) => HandlePan(view, 0, 0.01)); + + ZoomIn = new DelegateDrawingCommand((view, controller, args) => HandleZoomCenter(view, 1)); + ZoomOut = new DelegateDrawingCommand((view, controller, args) => HandleZoomCenter(view, -1)); + ZoomInFine = new DelegateDrawingCommand((view, controller, args) => HandleZoomCenter(view, 0.1)); + ZoomOutFine = new DelegateDrawingCommand((view, controller, args) => HandleZoomCenter(view, -0.1)); + } + + /// + /// Gets the reset axes command. + /// + public static IViewCommand Reset { get; private set; } + + /// + /// Gets the reset axes command (for mouse events). + /// + public static IViewCommand ResetAt { get; private set; } + + /// + /// Gets the pan/zoom touch command. + /// + public static IViewCommand PanZoomByTouch { get; private set; } + + /// + /// Gets the pan command. + /// + public static IViewCommand PanAt { get; private set; } + + /// + /// Gets the zoom rectangle command. + /// + public static IViewCommand ZoomRectangle { get; private set; } + + /// + /// Gets the zoom by mouse wheel command. + /// + public static IViewCommand ZoomWheel { get; private set; } + + /// + /// Gets the fine-control zoom by mouse wheel command. + /// + public static IViewCommand ZoomWheelFine { get; private set; } + + /// + /// Gets the pan left command. + /// + public static IViewCommand PanLeft { get; private set; } + + /// + /// Gets the pan right command. + /// + public static IViewCommand PanRight { get; private set; } + + /// + /// Gets the pan up command. + /// + public static IViewCommand PanUp { get; private set; } + + /// + /// Gets the pan down command. + /// + public static IViewCommand PanDown { get; private set; } + + /// + /// Gets the fine control pan left command. + /// + public static IViewCommand PanLeftFine { get; private set; } + + /// + /// Gets the fine control pan right command. + /// + public static IViewCommand PanRightFine { get; private set; } + + /// + /// Gets the fine control pan up command. + /// + public static IViewCommand PanUpFine { get; private set; } + + /// + /// Gets the fine control pan down command. + /// + public static IViewCommand PanDownFine { get; private set; } + + /// + /// Gets the zoom in command. + /// + public static IViewCommand ZoomInAt { get; private set; } + + /// + /// Gets the zoom out command. + /// + public static IViewCommand ZoomOutAt { get; private set; } + + /// + /// Gets the zoom in command. + /// + public static IViewCommand ZoomIn { get; private set; } + + /// + /// Gets the zoom out command. + /// + public static IViewCommand ZoomOut { get; private set; } + + /// + /// Gets the fine control zoom in command. + /// + public static IViewCommand ZoomInFine { get; private set; } + + /// + /// Gets the fine control zoom out command. + /// + public static IViewCommand ZoomOutFine { get; private set; } + + /// + /// Handles the reset events. + /// + /// The view to reset. + private static void HandleReset(IDrawingView view) + { + view.ActualViewModel.Reset(); + } + + /// + /// Zooms the view by the specified factor at the position specified in the . + /// + /// The view. + /// The instance containing the event data. + /// The zoom factor. + private static void HandleZoomAt(IDrawingView view, OxyMouseEventArgs args, double delta) + { + var m = new ZoomStepManipulator(view) { Step = delta, FineControl = args.IsControlDown }; + m.Started(args); + } + + /// + /// Zooms the view by the mouse wheel delta in the specified . + /// + /// The view. + /// The instance containing the event data. + /// The zoom speed factor. Default value is 1. + private static void HandleZoomByWheel(IDrawingView view, OxyMouseWheelEventArgs args, double factor = 1) + { + var m = new ZoomStepManipulator(view) { Step = args.Delta * 0.001 * factor, FineControl = args.IsControlDown }; + m.Started(args); + } + + /// + /// Zooms the view by the key in the specified factor. + /// + /// The view. + /// The zoom factor (positive zoom in, negative zoom out). + private static void HandleZoomCenter(IDrawingView view, double delta) + { + view.ActualViewModel.Zoom(1 + (delta * 0.12)); + } + + /// + /// Pans the view by the key in the specified vector. + /// + /// The view. + /// The horizontal delta (percentage of Graphics area width). + /// The vertical delta (percentage of Graphics area height). + private static void HandlePan(IDrawingView view, double dx, double dy) + { + dx *= view.ClientArea.Width; + dy *= view.ClientArea.Height; + view.ActualViewModel.Pan(new ScreenVector(dx, dy)); + } + } +} \ No newline at end of file diff --git a/Source/OxyPlot/Drawing/DrawingController/DrawingController.cs b/Source/OxyPlot/Drawing/DrawingController/DrawingController.cs new file mode 100644 index 000000000..f1999e49e --- /dev/null +++ b/Source/OxyPlot/Drawing/DrawingController/DrawingController.cs @@ -0,0 +1,80 @@ +// -------------------------------------------------------------------------------------------------------------------- +// +// Copyright (c) 2014 OxyPlot contributors +// +// +// Provides a Graphics controller where the input command bindings can be modified. +// +// -------------------------------------------------------------------------------------------------------------------- + +namespace OxyPlot.Drawing +{ + using System.Collections.Generic; + + /// + /// Provides a Graphics controller where the input command bindings can be modified. + /// + public class DrawingController : ControllerBase + { + /// + /// Initializes a new instance of the class. + /// + public DrawingController() + { + // Zoom rectangle bindings: MMB / control RMB / control+alt LMB + this.BindMouseDown(OxyMouseButton.Middle, DrawingCommands.ZoomRectangle); + this.BindMouseDown(OxyMouseButton.Right, OxyModifierKeys.Control, DrawingCommands.ZoomRectangle); + this.BindMouseDown(OxyMouseButton.Left, OxyModifierKeys.Control | OxyModifierKeys.Alt, DrawingCommands.ZoomRectangle); + + // Reset bindings: Same as zoom rectangle, but double click / A key + this.BindMouseDown(OxyMouseButton.Middle, OxyModifierKeys.None, 2, DrawingCommands.ResetAt); + this.BindMouseDown(OxyMouseButton.Right, OxyModifierKeys.Control, 2, DrawingCommands.ResetAt); + this.BindMouseDown(OxyMouseButton.Left, OxyModifierKeys.Control | OxyModifierKeys.Alt, 2, DrawingCommands.ResetAt); + this.BindKeyDown(OxyKey.A, DrawingCommands.Reset); + this.BindKeyDown(OxyKey.Home, DrawingCommands.Reset); + this.BindCore(new OxyShakeGesture(), DrawingCommands.Reset); + + // Pan bindings: RMB / alt LMB / Up/down/left/right keys (panning direction on axis is opposite of key as it is more intuitive) + this.BindMouseDown(OxyMouseButton.Right, DrawingCommands.PanAt); + this.BindMouseDown(OxyMouseButton.Left, OxyModifierKeys.Alt, DrawingCommands.PanAt); + this.BindKeyDown(OxyKey.Left, DrawingCommands.PanLeft); + this.BindKeyDown(OxyKey.Right, DrawingCommands.PanRight); + this.BindKeyDown(OxyKey.Up, DrawingCommands.PanUp); + this.BindKeyDown(OxyKey.Down, DrawingCommands.PanDown); + this.BindKeyDown(OxyKey.Left, OxyModifierKeys.Control, DrawingCommands.PanLeftFine); + this.BindKeyDown(OxyKey.Right, OxyModifierKeys.Control, DrawingCommands.PanRightFine); + this.BindKeyDown(OxyKey.Up, OxyModifierKeys.Control, DrawingCommands.PanUpFine); + this.BindKeyDown(OxyKey.Down, OxyModifierKeys.Control, DrawingCommands.PanDownFine); + + this.BindTouchDown(DrawingCommands.PanZoomByTouch); + + // Zoom in/out binding: XB1 / XB2 / mouse wheels / +/- keys + this.BindMouseDown(OxyMouseButton.XButton1, DrawingCommands.ZoomInAt); + this.BindMouseDown(OxyMouseButton.XButton2, DrawingCommands.ZoomOutAt); + this.BindMouseWheel(DrawingCommands.ZoomWheel); + this.BindMouseWheel(OxyModifierKeys.Control, DrawingCommands.ZoomWheelFine); + this.BindKeyDown(OxyKey.Add, DrawingCommands.ZoomIn); + this.BindKeyDown(OxyKey.Subtract, DrawingCommands.ZoomOut); + this.BindKeyDown(OxyKey.PageUp, DrawingCommands.ZoomIn); + this.BindKeyDown(OxyKey.PageDown, DrawingCommands.ZoomOut); + this.BindKeyDown(OxyKey.Add, OxyModifierKeys.Control, DrawingCommands.ZoomInFine); + this.BindKeyDown(OxyKey.Subtract, OxyModifierKeys.Control, DrawingCommands.ZoomOutFine); + this.BindKeyDown(OxyKey.PageUp, OxyModifierKeys.Control, DrawingCommands.ZoomInFine); + this.BindKeyDown(OxyKey.PageDown, OxyModifierKeys.Control, DrawingCommands.ZoomOutFine); + } + + /// + /// Returns the elements that are hit at the specified position. + /// + /// The view. + /// The hit test arguments. + /// + /// A sequence of hit results. + /// + public override IEnumerable HitTest(IView view, HitTestArguments args) + { + var drawingView = (IDrawingView)view; + return drawingView.ActualViewModel.HitTest(args); + } + } +} \ No newline at end of file diff --git a/Source/OxyPlot/Drawing/DrawingController/Manipulators/MouseManipulator.cs b/Source/OxyPlot/Drawing/DrawingController/Manipulators/MouseManipulator.cs new file mode 100644 index 000000000..35dff54ba --- /dev/null +++ b/Source/OxyPlot/Drawing/DrawingController/Manipulators/MouseManipulator.cs @@ -0,0 +1,40 @@ +// -------------------------------------------------------------------------------------------------------------------- +// +// Copyright (c) 2014 OxyPlot contributors +// +// +// Provides an abstract base class for mouse event manipulators. +// +// -------------------------------------------------------------------------------------------------------------------- + +namespace OxyPlot.Drawing +{ + /// + /// Provides an abstract base class for mouse event manipulators. + /// + public abstract class MouseManipulator : ManipulatorBase + { + /// + /// Initializes a new instance of the class. + /// + /// The view. + protected MouseManipulator(IDrawingView view) + : base(view) + { + } + + /// + /// Gets the drawing view. + /// + /// + /// The view. + /// + public new IDrawingView View + { + get + { + return (IDrawingView)base.View; + } + } + } +} \ No newline at end of file diff --git a/Source/OxyPlot/Drawing/DrawingController/Manipulators/PanManipulator.cs b/Source/OxyPlot/Drawing/DrawingController/Manipulators/PanManipulator.cs new file mode 100644 index 000000000..e7b079eb7 --- /dev/null +++ b/Source/OxyPlot/Drawing/DrawingController/Manipulators/PanManipulator.cs @@ -0,0 +1,71 @@ +// -------------------------------------------------------------------------------------------------------------------- +// +// Copyright (c) 2014 OxyPlot contributors +// +// +// Provides a plot control manipulator for panning functionality. +// +// -------------------------------------------------------------------------------------------------------------------- + +namespace OxyPlot.Drawing +{ + /// + /// Provides a plot control manipulator for panning functionality. + /// + public class PanManipulator : MouseManipulator + { + /// + /// Initializes a new instance of the class. + /// + /// The view. + public PanManipulator(IDrawingView view) + : base(view) + { + } + + /// + /// Gets or sets the previous position. + /// + private ScreenPoint PreviousPosition { get; set; } + + /// + /// Occurs when the input device changes position during a manipulation. + /// + /// The instance containing the event data. + public override void Delta(OxyMouseEventArgs e) + { + base.Delta(e); + this.View.ActualViewModel.Pan(e.Position - this.PreviousPosition, e.Position); + this.PreviousPosition = e.Position; + } + + /// + /// Occurs when a manipulation is complete. + /// + /// The instance containing the event data. + public override void Completed(OxyMouseEventArgs e) + { + base.Completed(e); + this.View.SetCursorType(CursorType.Default); + } + + /// Gets the cursor for the manipulation. + /// + /// The cursor. + public CursorType GetCursorType() + { + return CursorType.Pan; + } + + /// + /// Occurs when an input device begins a manipulation on the plot. + /// + /// The instance containing the event data. + public override void Started(OxyMouseEventArgs e) + { + base.Started(e); + this.PreviousPosition = e.Position; + this.View.SetCursorType(CursorType.Pan); + } + } +} diff --git a/Source/OxyPlot/Drawing/DrawingController/Manipulators/TouchManipulator.cs b/Source/OxyPlot/Drawing/DrawingController/Manipulators/TouchManipulator.cs new file mode 100644 index 000000000..64ce0a86d --- /dev/null +++ b/Source/OxyPlot/Drawing/DrawingController/Manipulators/TouchManipulator.cs @@ -0,0 +1,72 @@ +// -------------------------------------------------------------------------------------------------------------------- +// +// Copyright (c) 2014 OxyPlot contributors +// +// +// Provides a plot control manipulator for touch functionality. +// +// -------------------------------------------------------------------------------------------------------------------- + +namespace OxyPlot.Drawing +{ + /// + /// Provides a plot control manipulator for touch functionality. + /// + public class TouchManipulator : ManipulatorBase + { + /// + /// The previous position + /// + private ScreenPoint previousPosition; + + /// + /// Initializes a new instance of the class. + /// + /// The plot control. + public TouchManipulator(IDrawingView view) + : base(view) + { + } + + /// + /// Gets the drawing view. + /// + /// + /// The view. + /// + public new IDrawingView View + { + get + { + return (IDrawingView)base.View; + } + } + + /// + /// Occurs when a touch delta event is handled. + /// + /// The instance containing the event data. + public override void Delta(OxyTouchEventArgs e) + { + base.Delta(e); + + var newPosition = this.previousPosition + e.DeltaTranslation; + + this.View.ActualViewModel.Pan(this.previousPosition - newPosition, newPosition); + + this.View.ActualViewModel.ZoomAt(e.DeltaScale, newPosition); + + this.previousPosition = newPosition; + } + + /// + /// Occurs when an input device begins a manipulation on the plot. + /// + /// The instance containing the event data. + public override void Started(OxyTouchEventArgs e) + { + base.Started(e); + this.previousPosition = e.Position; + } + } +} \ No newline at end of file diff --git a/Source/OxyPlot/Drawing/DrawingController/Manipulators/ZoomRectangleManipulator.cs b/Source/OxyPlot/Drawing/DrawingController/Manipulators/ZoomRectangleManipulator.cs new file mode 100644 index 000000000..4d1d9bde0 --- /dev/null +++ b/Source/OxyPlot/Drawing/DrawingController/Manipulators/ZoomRectangleManipulator.cs @@ -0,0 +1,86 @@ +// -------------------------------------------------------------------------------------------------------------------- +// +// Copyright (c) 2014 OxyPlot contributors +// +// +// The zoom manipulator. +// +// -------------------------------------------------------------------------------------------------------------------- + +namespace OxyPlot.Drawing +{ + /// + /// Provides a plot control manipulator for zoom by rectangle functionality. + /// + public class ZoomRectangleManipulator : MouseManipulator + { + /// + /// The zoom rectangle. + /// + private OxyRect zoomRectangle; + + /// + /// The first position of the manipulation. + /// + private ScreenPoint startPosition; + + /// + /// Initializes a new instance of the class. + /// + /// The view. + public ZoomRectangleManipulator(IDrawingView view) + : base(view) + { + } + + /// + /// Occurs when a manipulation is complete. + /// + /// The instance containing the event data. + public override void Completed(OxyMouseEventArgs e) + { + base.Completed(e); + + this.View.HideZoomRectangle(); + this.View.SetCursorType(CursorType.Default); + + if (this.zoomRectangle.Width > 10 && this.zoomRectangle.Height > 10) + { + this.View.ActualViewModel.Zoom(this.zoomRectangle); + } + } + + /// + /// Occurs when the input device changes position during a manipulation. + /// + /// The instance containing the event data. + public override void Delta(OxyMouseEventArgs e) + { + base.Delta(e); + this.zoomRectangle = new OxyRect(this.startPosition, e.Position); + this.View.ShowZoomRectangle(this.zoomRectangle); + } + + /// + /// Gets the cursor for the manipulation. + /// + /// The cursor. + public CursorType GetCursorType() + { + return CursorType.ZoomRectangle; + } + + /// + /// Occurs when an input device begins a manipulation on the plot. + /// + /// The instance containing the event data. + public override void Started(OxyMouseEventArgs e) + { + base.Started(e); + this.startPosition = e.Position; + this.zoomRectangle = new OxyRect(this.startPosition, this.startPosition); + this.View.ShowZoomRectangle(this.zoomRectangle); + this.View.SetCursorType(CursorType.ZoomRectangle); + } + } +} diff --git a/Source/OxyPlot/Drawing/DrawingController/Manipulators/ZoomStepManipulator.cs b/Source/OxyPlot/Drawing/DrawingController/Manipulators/ZoomStepManipulator.cs new file mode 100644 index 000000000..262683bf9 --- /dev/null +++ b/Source/OxyPlot/Drawing/DrawingController/Manipulators/ZoomStepManipulator.cs @@ -0,0 +1,61 @@ +// -------------------------------------------------------------------------------------------------------------------- +// +// Copyright (c) 2014 OxyPlot contributors +// +// +// The step manipulator. +// +// -------------------------------------------------------------------------------------------------------------------- + +namespace OxyPlot.Drawing +{ + /// + /// Provides a plot control manipulator for stepwise zoom functionality. + /// + public class ZoomStepManipulator : MouseManipulator + { + /// + /// Initializes a new instance of the class. + /// + /// The view. + public ZoomStepManipulator(IDrawingView view) + : base(view) + { + } + + /// + /// Gets or sets a value indicating whether FineControl. + /// + public bool FineControl { get; set; } + + /// + /// Gets or sets Step. + /// + public double Step { get; set; } + + /// + /// Occurs when an input device begins a manipulation on the plot. + /// + /// The instance containing the event data. + public override void Started(OxyMouseEventArgs e) + { + base.Started(e); + + 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; + } + + this.View.ActualViewModel.ZoomAt(new ScreenVector(scale, scale), e.Position); + } + } +} \ No newline at end of file diff --git a/Source/OxyPlot/Drawing/DrawingModel/ChangedEventArgs.cs b/Source/OxyPlot/Drawing/DrawingModel/ChangedEventArgs.cs new file mode 100644 index 000000000..8a9f507f1 --- /dev/null +++ b/Source/OxyPlot/Drawing/DrawingModel/ChangedEventArgs.cs @@ -0,0 +1,20 @@ +// -------------------------------------------------------------------------------------------------------------------- +// +// Copyright (c) 2014 OxyPlot contributors +// +// +// Provides data for the event. +// +// -------------------------------------------------------------------------------------------------------------------- + +namespace OxyPlot.Drawing +{ + using System; + + /// + /// Provides data for the event. + /// + public class ChangedEventArgs : EventArgs + { + } +} \ No newline at end of file diff --git a/Source/OxyPlot/Drawing/DrawingModel/DrawingElement.cs b/Source/OxyPlot/Drawing/DrawingModel/DrawingElement.cs new file mode 100644 index 000000000..0617e5bbd --- /dev/null +++ b/Source/OxyPlot/Drawing/DrawingModel/DrawingElement.cs @@ -0,0 +1,224 @@ +// -------------------------------------------------------------------------------------------------------------------- +// +// Copyright (c) 2014 OxyPlot contributors +// +// +// Represents an element of a DrawingModel. +// +// -------------------------------------------------------------------------------------------------------------------- + +namespace OxyPlot.Drawing +{ + using System; + + /// + /// Represents an element of a . + /// + public abstract class DrawingElement : UIElement, IDrawingElement + { + /// + /// Occurs when the touch gesture is completed. + /// + public event EventHandler Frame; + + /// + /// Gets or sets the font weight. + /// + /// + /// The font weight. + /// + public double FontWeight { get; set; } + + /// + /// Gets or sets the size of the font. + /// + /// + /// The size of the font. + /// + public double FontSize { get; set; } + + /// + /// Gets or sets the font family. + /// + /// + /// The font family. + /// + public string FontFamily { get; set; } + + /// + /// Creates the presentation model for the element. + /// + /// The parent presentation model. + /// The presentation model. + Presenter IDrawingElement.CreatePresentationModel(DrawingViewModel v) + { + return this.CreatePresenter(v); + } + + /// + /// Raises the event. + /// + /// The instance containing the event data. + protected internal virtual void OnFrame(FrameEventArgs e) + { + var handler = this.Frame; + if (handler != null) + { + handler(this, e); + } + } + + /// + /// Creates the presentation model for the element. + /// + /// The parent presentation model. + /// The presentation model. + protected abstract Presenter CreatePresenter(DrawingViewModel v); + + /// + /// Provides a generic base class for element presentation models. + /// + /// The type of the model. + public abstract class Presenter : Presenter + where T : DrawingElement + { + /// + /// Initializes a new instance of the class. + /// + /// The model. + /// The parent . + protected Presenter(T model, DrawingViewModel v) + : base(v) + { + this.Model = model; + } + + /// + /// Gets the model. + /// + /// + /// The model. + /// + protected T Model { get; private set; } + } + + /// + /// Provides an abstract base class for element presentation models. + /// + public abstract class Presenter + { + /// + /// Initializes a new instance of the class. + /// + /// The drawing presentation model. + protected Presenter(DrawingViewModel drawingViewModel) + { + this.DrawingViewModel = drawingViewModel; + } + + /// + /// Gets the presentation model of the parent . + /// + /// + /// The presentation model. + /// + protected DrawingViewModel DrawingViewModel { get; private set; } + + /// + /// Gets the bounding box of the element. + /// + /// The render context. + /// The bounding box. + public abstract BoundingBox GetBounds(IRenderContext rc); + + /// + /// Updates the element. + /// + /// The render context. + public abstract void Update(IRenderContext rc); + + /// + /// Renders the element. + /// + /// The render context. + public abstract void Render(IRenderContext rc); + + /// + /// Tests if the element is hit by the specified point. + /// + /// The hit test arguments. + /// + /// A hit test result. + /// + public HitTestResult HitTest(HitTestArguments args) + { + return this.HitTestOverride(args); + } + + /// + /// When overridden in a derived class, tests if the element is hit by the specified point. + /// + /// The hit test arguments. + /// + /// The result of the hit test. + /// + protected virtual HitTestResult HitTestOverride(HitTestArguments args) + { + return null; + } + + /// + /// Transforms the specified point. + /// + /// The point to transform. + /// The transformed point. + protected ScreenPoint Transform(DataPoint p) + { + return this.DrawingViewModel.Transform(p); + } + + /// + /// Transforms the specified point. + /// + /// The x coordinate of the point. + /// The y coordinate of the point. + /// + /// The transformed point. + /// + protected ScreenPoint Transform(double x, double y) + { + return this.DrawingViewModel.Transform(x, y); + } + + /// + /// Transforms the specified length. + /// + /// The length to transform. + /// The transformed length. + protected double Transform(double p) + { + return this.DrawingViewModel.Transform(p); + } + + /// + /// Inverse-transforms the specified point. + /// + /// The point. + /// The inverse-transformed point. + protected DataPoint InverseTransform(ScreenPoint p) + { + return this.DrawingViewModel.InverseTransform(p); + } + + /// + /// Inverse-transforms the specified length. + /// + /// The length. + /// The inverse-transformed length. + protected double InverseTransform(double length) + { + return this.DrawingViewModel.InverseTransform(length); + } + } + } +} \ No newline at end of file diff --git a/Source/OxyPlot/Drawing/DrawingModel/DrawingModel.cs b/Source/OxyPlot/Drawing/DrawingModel/DrawingModel.cs new file mode 100644 index 000000000..5cadda60a --- /dev/null +++ b/Source/OxyPlot/Drawing/DrawingModel/DrawingModel.cs @@ -0,0 +1,118 @@ +// -------------------------------------------------------------------------------------------------------------------- +// +// Copyright (c) 2014 OxyPlot contributors +// +// +// Represents a drawing. +// +// -------------------------------------------------------------------------------------------------------------------- + +namespace OxyPlot.Drawing +{ + using System; + using System.Collections.Generic; + + /// + /// Represents a drawing. + /// + public class DrawingModel : Model + { + /// + /// The elements + /// + private readonly IList elements; + + /// + /// Initializes a new instance of the class. + /// + public DrawingModel() + { + this.elements = new ElementCollection(this); + } + + /// + /// Occurs when the model is changed. + /// + public event EventHandler Changed; + + /// + /// Gets or sets the background color of the drawing. + /// + /// + /// The background color. + /// + public OxyColor Background { get; set; } + + /// + /// Gets the elements of the drawing. + /// + /// + /// The elements. + /// + public IList Elements + { + get + { + return this.elements; + } + } + + /// + /// Adds the specified element. + /// + /// The element. + public void Add(DrawingElement e) + { + this.elements.Add(e); + } + + /// + /// Clears the drawing. + /// + public void Clear() + { + this.elements.Clear(); + } + + /// + /// Removes the specified element. + /// + /// The element. + public void Remove(DrawingElement e) + { + this.elements.Remove(e); + } + + /// + /// Invalidates the model. + /// + public void Invalidate() + { + this.OnChanged(new ChangedEventArgs()); + } + + /// + /// Gets all elements of the model, sorted by rendering priority. + /// + /// + /// An enumerator of the elements. + /// + public override IEnumerable GetElements() + { + return this.elements; + } + + /// + /// Raises the event. + /// + /// The instance containing the event data. + protected virtual void OnChanged(ChangedEventArgs args) + { + var handler = this.Changed; + if (handler != null) + { + handler(this, args); + } + } + } +} diff --git a/Source/OxyPlot/Drawing/DrawingModel/Elements/Arrow.cs b/Source/OxyPlot/Drawing/DrawingModel/Elements/Arrow.cs new file mode 100644 index 000000000..ca3ef4d82 --- /dev/null +++ b/Source/OxyPlot/Drawing/DrawingModel/Elements/Arrow.cs @@ -0,0 +1,161 @@ +// -------------------------------------------------------------------------------------------------------------------- +// +// Copyright (c) 2014 OxyPlot contributors +// +// +// Represents an arrow. +// +// -------------------------------------------------------------------------------------------------------------------- + +namespace OxyPlot.Drawing +{ + /// + /// Represents an arrow. + /// + public class Arrow : ShapeElement + { + /// + /// Initializes a new instance of the class. + /// + public Arrow() + { + this.Thickness = 1; + this.HeadLength = 6; + this.HeadWidth = 3; + this.Veeness = 1; + this.Color = OxyColors.Black; + } + + /// + /// Gets or sets the start point. + /// + /// + /// The start point. + /// + public DataPoint StartPoint { get; set; } + + /// + /// Gets or sets the end point. + /// + /// + /// The end point. + /// + public DataPoint EndPoint { get; set; } + + /// + /// Gets or sets the length of the head relative to the . + /// + /// + /// The length of the head. + /// + public double HeadLength { get; set; } + + /// + /// Gets or sets the width of the head relative to the . + /// + /// + /// The width of the head. + /// + public double HeadWidth { get; set; } + + /// + /// Gets or sets the veeness relative to the . + /// + /// + /// The veeness. + /// + public double Veeness { get; set; } + + /// + /// Gets or sets the color of the arrow. + /// + /// + /// The color. + /// + public OxyColor Color { get; set; } + + /// + /// Creates the presentation model for the element. + /// + /// The parent presentation model. + /// + /// The presentation model. + /// + protected override Presenter CreatePresenter(DrawingViewModel v) + { + return new ArrowPresenter(this, v); + } + + /// + /// Represents the presentation model for the class. + /// + private class ArrowPresenter : Presenter + { + /// + /// The points + /// + private readonly ScreenPoint[] points = new ScreenPoint[7]; + + /// + /// Initializes a new instance of the class. + /// + /// The model. + /// The presentation model of the parent . + public ArrowPresenter(Arrow model, DrawingViewModel v) + : base(model, v) + { + } + + /// + /// Gets the bounding box of the element. + /// + /// The render context. + /// + /// The bounding box. + /// + public override BoundingBox GetBounds(IRenderContext rc) + { + var bb = new BoundingBox(); + bb.Union(this.Model.StartPoint); + bb.Union(this.Model.EndPoint); + return bb; + } + + /// + /// Updates the element. + /// + /// The render context. + public override void Update(IRenderContext rc) + { + var startPoint = this.Transform(this.Model.StartPoint); + var endPoint = this.Transform(this.Model.EndPoint); + var direction = endPoint - startPoint; + direction.Normalize(); + var normal = new ScreenVector(-direction.Y, direction.X); + var thickness = this.Transform(this.Model.Thickness); + + var p1 = endPoint - (direction * this.Model.HeadLength * thickness); + var p2 = p1 + (direction * this.Model.Veeness * thickness); + var n1 = normal * this.Model.HeadWidth * 0.5 * thickness; + var n2 = normal * 0.5 * thickness; + + this.points[0] = endPoint; + this.points[1] = p1 + n1; + this.points[2] = p2 + n2; + this.points[3] = startPoint + n2; + this.points[4] = startPoint - n2; + this.points[5] = p2 - n2; + this.points[6] = p1 - n1; + } + + /// + /// Renders the element. + /// + /// The render context. + public override void Render(IRenderContext rc) + { + rc.DrawPolygon(this.points, this.Model.Color, OxyColors.Undefined); + } + } + } +} \ No newline at end of file diff --git a/Source/OxyPlot/Drawing/DrawingModel/Elements/Ellipse.cs b/Source/OxyPlot/Drawing/DrawingModel/Elements/Ellipse.cs new file mode 100644 index 000000000..3ccfc7a75 --- /dev/null +++ b/Source/OxyPlot/Drawing/DrawingModel/Elements/Ellipse.cs @@ -0,0 +1,136 @@ +// -------------------------------------------------------------------------------------------------------------------- +// +// Copyright (c) 2014 OxyPlot contributors +// +// +// Represents an ellipse. +// +// -------------------------------------------------------------------------------------------------------------------- + +namespace OxyPlot.Drawing +{ + /// + /// Represents an ellipse. + /// + public class Ellipse : ShapeElement + { + /// + /// Gets or sets the center of the ellipse. + /// + /// + /// The center. + /// + public DataPoint Center { get; set; } + + /// + /// Gets or sets the x-axis radius of the ellipse. + /// + /// + /// The radius. + /// + public double RadiusX { get; set; } + + /// + /// Gets or sets the y-axis radius of the ellipse. + /// + /// + /// The radius. + /// + public double RadiusY { get; set; } + + /// + /// Creates the presentation model for the element. + /// + /// The presentation model of the parent . + /// + /// The presentation model. + /// + protected override Presenter CreatePresenter(DrawingViewModel v) + { + return new EllipsePresenter(this, v); + } + + /// + /// Represents the presentation model for the . + /// + private class EllipsePresenter : Presenter + { + /// + /// The rectangle defining the ellipse. + /// + private OxyRect rect; + + /// + /// Initializes a new instance of the class. + /// + /// The model. + /// The v. + public EllipsePresenter(Ellipse model, DrawingViewModel v) + : base(model, v) + { + } + + /// + /// Gets the bounding box of the element. + /// + /// The render context. + /// + /// The bounding box. + /// + public override BoundingBox GetBounds(IRenderContext rc) + { + var c = this.Model.Center; + var dx = this.Model.RadiusX > 0 ? this.Model.RadiusX : 0; + var dy = this.Model.RadiusY > 0 ? this.Model.RadiusY : 0; + return new BoundingBox(c.X - dx, c.Y - dy, c.X + dx, c.Y + dy); + } + + /// + /// Updates the element. + /// + /// The render context. + public override void Update(IRenderContext rc) + { + var c = this.Transform(this.Model.Center); + var dx = this.Model.RadiusX > 0 ? this.Transform(this.Model.RadiusX) : -this.Model.RadiusX; + var dy = this.Model.RadiusY > 0 ? this.Transform(this.Model.RadiusY) : -this.Model.RadiusY; + this.rect = new OxyRect(c.X - dx, c.Y - dy, dx * 2, dy * 2); + } + + /// + /// Renders the element. + /// + /// The render context. + public override void Render(IRenderContext rc) + { + rc.DrawEllipse(this.rect, this.Model.Fill, this.Model.Stroke, this.Transform(this.Model.Thickness)); + if (this.Model.Text != null) + { + rc.DrawText(this.rect.Center, this.Model.Text, this.Model.TextColor, this.Model.FontFamily, this.Model.FontSize, this.Model.FontWeight, 0, HorizontalAlignment.Center, VerticalAlignment.Middle); + } + } + + /// + /// When overridden in a derived class, tests if the element is hit by the specified point. + /// + /// The hit test arguments. + /// + /// The result of the hit test. + /// + protected override HitTestResult HitTestOverride(HitTestArguments args) + { + var dx = this.rect.Center.X - args.Point.X; + var dy = this.rect.Center.Y - args.Point.Y; + var rx = this.rect.Width / 2; + var ry = this.rect.Height / 2; + var q = (dx * dx / (rx * rx)) + (dy * dy / (ry * ry)); + if (q <= 1) + { + return new HitTestResult(this.Model, args.Point); + } + + return base.HitTestOverride(args); + } + } + } +} \ No newline at end of file diff --git a/Source/OxyPlot/Drawing/DrawingModel/Elements/Grid.cs b/Source/OxyPlot/Drawing/DrawingModel/Elements/Grid.cs new file mode 100644 index 000000000..72826d2e3 --- /dev/null +++ b/Source/OxyPlot/Drawing/DrawingModel/Elements/Grid.cs @@ -0,0 +1,186 @@ +// -------------------------------------------------------------------------------------------------------------------- +// +// Copyright (c) 2014 OxyPlot contributors +// +// +// Represents an infinite grid element. +// +// -------------------------------------------------------------------------------------------------------------------- + +namespace OxyPlot.Drawing +{ + using System; + using System.Collections.Generic; + + /// + /// Represents an infinite grid element. + /// + public class Grid : ShapeElement + { + /// + /// Initializes a new instance of the class. + /// + public Grid() + { + this.MajorThickness = -1; + this.MinorThickness = -1; + this.MajorDistance = 10; + this.MinorDistance = 1; + this.MajorColor = OxyColor.FromAColor(60, OxyColors.Blue); + this.MinorColor = OxyColor.FromAColor(20, OxyColors.Blue); + } + + /// + /// Gets or sets the major thickness. + /// + /// + /// The major thickness. + /// + public double MajorThickness { get; set; } + + /// + /// Gets or sets the minor thickness. + /// + /// + /// The minor thickness. + /// + public double MinorThickness { get; set; } + + /// + /// Gets or sets the major distance. + /// + /// + /// The major distance. + /// + public double MajorDistance { get; set; } + + /// + /// Gets or sets the minor distance. + /// + /// + /// The minor distance. + /// + public double MinorDistance { get; set; } + + /// + /// Gets or sets the color of the major. + /// + /// + /// The color of the major. + /// + public OxyColor MajorColor { get; set; } + + /// + /// Gets or sets the color of the minor. + /// + /// + /// The color of the minor. + /// + public OxyColor MinorColor { get; set; } + + /// + /// Creates the presentation model for the element. + /// + /// The parent presentation model. + /// + /// The presentation model. + /// + protected override Presenter CreatePresenter(DrawingViewModel v) + { + return new GridPresenter(this, v); + } + + /// + /// Represents the presentation model for the . + /// + private class GridPresenter : Presenter + { + /// + /// Initializes a new instance of the class. + /// + /// The model. + /// The presentation model of the parent . + public GridPresenter(Grid model, DrawingViewModel v) + : base(model, v) + { + } + + /// + /// Gets the bounding box of the element. + /// + /// The render context. + /// + /// The bounding box. + /// + public override BoundingBox GetBounds(IRenderContext rc) + { + return new BoundingBox(); + } + + /// + /// Updates the element. + /// + /// The render context. + public override void Update(IRenderContext rc) + { + } + + /// + /// Renders the element. + /// + /// The render context. + public override void Render(IRenderContext rc) + { + var majorLineSegments = new List(); + var minorLineSegments = new List(); + + var clientRect = this.DrawingViewModel.ClientArea; + var p0 = this.InverseTransform(new ScreenPoint(clientRect.Left, clientRect.Bottom)); + var p1 = this.InverseTransform(new ScreenPoint(clientRect.Right, clientRect.Top)); + + double x = (int)(p0.X / this.Model.MinorDistance) * this.Model.MinorDistance; + while (x <= p1.X) + { + var majorLine = Math.Abs((Math.Round(x / this.Model.MajorDistance) * this.Model.MajorDistance) - x) < 1e-6; + var q0 = this.Transform(x, p0.Y); + var q1 = this.Transform(x, p1.Y); + if (majorLine) + { + majorLineSegments.Add(q0); + majorLineSegments.Add(q1); + } + else + { + minorLineSegments.Add(q0); + minorLineSegments.Add(q1); + } + + x += this.Model.MinorDistance; + } + + double y = (int)(p0.Y / this.Model.MinorDistance) * this.Model.MinorDistance; + while (y <= p1.Y) + { + var majorLine = Math.Abs((Math.Round(y / this.Model.MajorDistance) * this.Model.MajorDistance) - y) < 1e-6; + var q0 = this.Transform(p0.X, y); + var q1 = this.Transform(p1.X, y); + if (majorLine) + { + majorLineSegments.Add(q0); + majorLineSegments.Add(q1); + } + else + { + minorLineSegments.Add(q0); + minorLineSegments.Add(q1); + } + + y += this.Model.MinorDistance; + } + + rc.DrawLineSegments(majorLineSegments, this.Model.MajorColor, this.Transform(this.Model.MajorThickness), aliased: true); + rc.DrawLineSegments(minorLineSegments, this.Model.MinorColor, this.Transform(this.Model.MinorThickness), aliased: true); + } + } + } +} \ No newline at end of file diff --git a/Source/OxyPlot/Drawing/DrawingModel/Elements/Image.cs b/Source/OxyPlot/Drawing/DrawingModel/Elements/Image.cs new file mode 100644 index 000000000..c4baabe86 --- /dev/null +++ b/Source/OxyPlot/Drawing/DrawingModel/Elements/Image.cs @@ -0,0 +1,209 @@ +// -------------------------------------------------------------------------------------------------------------------- +// +// Copyright (c) 2014 OxyPlot contributors +// +// +// Represents an image element. +// +// -------------------------------------------------------------------------------------------------------------------- + +namespace OxyPlot.Drawing +{ + /// + /// Represents an image element. + /// + public class Image : DrawingElement + { + /// + /// Initializes a new instance of the class. + /// + public Image() + { + this.Opacity = 1.0; + this.Interpolate = true; + } + + /// + /// Gets or sets the x. + /// + /// + /// The x. + /// + public double X { get; set; } + + /// + /// Gets or sets the y. + /// + /// + /// The y. + /// + public double Y { get; set; } + + /// + /// Gets or sets the width. + /// + /// + /// The width. + /// + public double Width { get; set; } + + /// + /// Gets or sets the height. + /// + /// + /// The height. + /// + public double Height { get; set; } + + /// + /// Gets or sets the source x. + /// + /// + /// The source x. + /// + public int SourceX { get; set; } + + /// + /// Gets or sets the source y. + /// + /// + /// The source y. + /// + public int SourceY { get; set; } + + /// + /// Gets or sets the width of the source. + /// + /// + /// The width of the source. + /// + public int SourceWidth { get; set; } + + /// + /// Gets or sets the height of the source. + /// + /// + /// The height of the source. + /// + public int SourceHeight { get; set; } + + /// + /// Gets or sets the source. + /// + /// + /// The source. + /// + public OxyImage Source { get; set; } + + /// + /// Gets or sets the rotation. + /// + /// + /// The rotation. + /// + public double Rotation { get; set; } + + /// + /// Gets or sets the opacity. + /// + /// + /// The opacity. + /// + public double Opacity { get; set; } + + /// + /// Gets or sets a value indicating whether this is interpolate. + /// + /// + /// true if interpolate; otherwise, false. + /// + public bool Interpolate { get; set; } + + /// + /// Creates the presentation model for the element. + /// + /// The parent presentation model. + /// + /// The presentation model. + /// + protected override Presenter CreatePresenter(DrawingViewModel v) + { + return new ImagePresentationmodel(this, v); + } + + /// + /// Represents the presentation model for the . + /// + private class ImagePresentationmodel : Presenter + { + /// + /// The rectangle + /// + private OxyRect rect; + + /// + /// Initializes a new instance of the class. + /// + /// The model. + /// The presentation model of the parent . + public ImagePresentationmodel(Image model, DrawingViewModel v) + : base(model, v) + { + } + + /// + /// Updates the element. + /// + /// The render context. + public override void Update(IRenderContext rc) + { + var p1 = this.Transform(this.Model.X, this.Model.Y); + var w = this.Transform(this.Model.Width); + var h = this.Transform(this.Model.Height); + this.rect = new OxyRect(p1.X, p1.Y, w, h); + } + + /// + /// Gets the bounding box of the element. + /// + /// The render context. + /// + /// The bounding box. + /// + public override BoundingBox GetBounds(IRenderContext rc) + { + var actualWidth = this.Model.Width; + var actualHeight = this.Model.Height; + if (double.IsNaN(this.Model.Width) || double.IsNaN(this.Model.Height)) + { + actualWidth = this.Model.Source.Width; + actualHeight = this.Model.Source.Height; + } + + return new BoundingBox(this.Model.X, this.Model.Y - actualHeight, this.Model.X + actualWidth, this.Model.Y); + } + + /// + /// Renders the element. + /// + /// The render context. + public override void Render(IRenderContext rc) + { + var sourceWidth = this.Model.SourceWidth > 0 ? this.Model.SourceWidth : this.Model.Source.Width; + var sourceHeight = this.Model.SourceHeight > 0 ? this.Model.SourceHeight : this.Model.Source.Height; + rc.DrawImage( + this.Model.Source, + (uint)this.Model.SourceX, + (uint)this.Model.SourceY, + (uint)sourceWidth, + (uint)sourceHeight, + this.rect.Left, + this.rect.Top, + this.rect.Width, + this.rect.Height, + this.Model.Opacity, + this.Model.Interpolate); + } + } + } +} \ No newline at end of file diff --git a/Source/OxyPlot/Drawing/DrawingModel/Elements/Interpolation.cs b/Source/OxyPlot/Drawing/DrawingModel/Elements/Interpolation.cs new file mode 100644 index 000000000..44ba5b0b1 --- /dev/null +++ b/Source/OxyPlot/Drawing/DrawingModel/Elements/Interpolation.cs @@ -0,0 +1,60 @@ +// -------------------------------------------------------------------------------------------------------------------- +// +// Copyright (c) 2014 OxyPlot contributors +// +// +// Provides interpolation methods. +// +// -------------------------------------------------------------------------------------------------------------------- + +namespace OxyPlot.Drawing +{ + using System; + using System.Collections.Generic; + + /// + /// Provides interpolation methods. + /// + public static class Interpolation + { + /// + /// Creates an arc. + /// + /// The center of the arc. + /// The x-axis radius. + /// The y-axis radius. + /// The start angle (degrees). + /// The end angle (degrees). + /// The number of point. + /// A sequence of . + public static IEnumerable Arc(DataPoint c, double rx, double ry, double t0, double t1, int n = 40) + { + for (int i = 0; i < n; i++) + { + double t = t0 + ((t1 - t0) * i / (n - 1)); + var th = Math.PI / 180 * t; + yield return new DataPoint(c.X + (Math.Cos(th) * rx), c.Y + (Math.Sin(th) * ry)); + } + } + + /// + /// Creates an arc. + /// + /// The center of the arc. + /// The x-axis radius. + /// The y-axis radius. + /// The start angle (degrees). + /// The end angle (degrees). + /// The number of point. + /// A sequence of . + public static IEnumerable Arc(ScreenPoint c, double rx, double ry, double t0, double t1, int n = 40) + { + for (int i = 0; i < n; i++) + { + double t = t0 + ((t1 - t0) * i / (n - 1)); + var th = Math.PI / 180 * t; + yield return new ScreenPoint(c.X + (Math.Cos(th) * rx), c.Y + (Math.Sin(th) * ry)); + } + } + } +} \ No newline at end of file diff --git a/Source/OxyPlot/Drawing/DrawingModel/Elements/LatLon.cs b/Source/OxyPlot/Drawing/DrawingModel/Elements/LatLon.cs new file mode 100644 index 000000000..6def4250f --- /dev/null +++ b/Source/OxyPlot/Drawing/DrawingModel/Elements/LatLon.cs @@ -0,0 +1,88 @@ +// -------------------------------------------------------------------------------------------------------------------- +// +// Copyright (c) 2014 OxyPlot contributors +// +// +// Represents a position. +// +// -------------------------------------------------------------------------------------------------------------------- + +namespace OxyPlot.Drawing +{ + using System; + + /// + /// Represents a position. + /// + public struct LatLon + { + /// + /// The latitude + /// + private readonly double latitude; + + /// + /// The longitude + /// + private readonly double longitude; + + /// + /// Initializes a new instance of the struct. + /// + /// The latitude. + /// The longitude. + public LatLon(double latitude, double longitude) + { + this.latitude = latitude; + this.longitude = longitude; + } + + /// + /// Gets the latitude. + /// + /// + /// The latitude. + /// + public double Latitude + { + get + { + return this.latitude; + } + } + + /// + /// Gets the longitude. + /// + /// + /// The longitude. + /// + public double Longitude + { + get + { + return this.longitude; + } + } + + /// + /// Calculates the distance to the specified point by the Haversine formula. + /// + /// The point to calculate the distance to. + /// + /// The distance in meter. + /// + /// + /// + public double DistanceTo(LatLon other) + { + // radius of the earth (km) + const double Deg2Rad = Math.PI / 180; + double dlat = (other.Latitude - this.Latitude) * Deg2Rad; + double dlon = (other.Longitude - this.Longitude) * Deg2Rad; + double a = (Math.Sin(dlat / 2) * Math.Sin(dlat / 2)) + (Math.Cos(this.Latitude * Deg2Rad) * Math.Cos(other.Latitude * Deg2Rad) * Math.Sin(dlon / 2) * Math.Sin(dlon / 2)); + double c = 2 * Math.Asin(Math.Min(1, Math.Sqrt(a))); + return 6371000 * c; + } + } +} \ No newline at end of file diff --git a/Source/OxyPlot/Drawing/DrawingModel/Elements/Lines.cs b/Source/OxyPlot/Drawing/DrawingModel/Elements/Lines.cs new file mode 100644 index 000000000..5f78b3461 --- /dev/null +++ b/Source/OxyPlot/Drawing/DrawingModel/Elements/Lines.cs @@ -0,0 +1,124 @@ +// -------------------------------------------------------------------------------------------------------------------- +// +// Copyright (c) 2014 OxyPlot contributors +// +// +// Represents a lines element. +// +// -------------------------------------------------------------------------------------------------------------------- + +namespace OxyPlot.Drawing +{ + using System.Collections.Generic; + + /// + /// Represents a lines element. + /// + public class Lines : PointsElement + { + /// + /// Initializes a new instance of the class. + /// + public Lines() + { + } + + /// + /// Initializes a new instance of the class. + /// + /// The points. + public Lines(IEnumerable points) + : base(points) + { + } + + /// + /// Initializes a new instance of the class. + /// + /// The p1. + /// The p2. + public Lines(DataPoint p1, DataPoint p2) + : this(new[] { p1, p2 }) + { + } + + /// + /// Initializes a new instance of the class. + /// + /// The x1. + /// The y1. + /// The x2. + /// The y2. + public Lines(double x1, double y1, double x2, double y2) + : this(new DataPoint(x1, y1), new DataPoint(x2, y2)) + { + } + + /// + /// Adds the specified p1. + /// + /// The p1. + /// The p2. + public void Add(DataPoint p1, DataPoint p2) + { + this.Points.Add(p1); + this.Points.Add(p2); + } + + /// + /// Adds the specified x1. + /// + /// The x1. + /// The y1. + /// The x2. + /// The y2. + public void Add(double x1, double y1, double x2, double y2) + { + this.Points.Add(new DataPoint(x1, y1)); + this.Points.Add(new DataPoint(x2, y2)); + } + + /// + /// Creates the presentation model for the element. + /// + /// The parent presentation model. + /// + /// The presentation model. + /// + protected override Presenter CreatePresenter(DrawingViewModel v) + { + return new LinesPresenter(this, v); + } + + /// + /// Represents the presentation model for the . + /// + protected class LinesPresenter : PointsPresenter + { + /// + /// Initializes a new instance of the class. + /// + /// The model. + /// The presentation model of the parent . + public LinesPresenter(Lines model, DrawingViewModel v) + : base(model, v) + { + } + + /// + /// Renders the element. + /// + /// The render context. + public override void Render(IRenderContext rc) + { + rc.DrawLineSegments( + this.TransformedPoints, + this.Model.Color, + this.Transform(this.Model.Thickness), + this.Model.LineStyle.GetDashArray(), + this.Model.LineJoin, + this.Model.Aliased); + } + } + } +} \ No newline at end of file diff --git a/Source/OxyPlot/Drawing/DrawingModel/Elements/Polygon.cs b/Source/OxyPlot/Drawing/DrawingModel/Elements/Polygon.cs new file mode 100644 index 000000000..604a387ab --- /dev/null +++ b/Source/OxyPlot/Drawing/DrawingModel/Elements/Polygon.cs @@ -0,0 +1,136 @@ +// -------------------------------------------------------------------------------------------------------------------- +// +// Copyright (c) 2014 OxyPlot contributors +// +// +// Represents a polygon element. +// +// -------------------------------------------------------------------------------------------------------------------- + +namespace OxyPlot.Drawing +{ + using System.Collections.Generic; + using System.Linq; + + /// + /// Represents a polygon element. + /// + public class Polygon : ShapeElement + { + /// + /// Initializes a new instance of the class. + /// + public Polygon() + { + this.Points = new List(); + } + + /// + /// Initializes a new instance of the class. + /// + /// The points. + public Polygon(IEnumerable points) + { + this.Points = new List(points); + } + + /// + /// Gets the points. + /// + /// + /// The points. + /// + public IList Points { get; private set; } + + /// + /// Gets or sets the line join. + /// + /// + /// The line join. + /// + public LineJoin LineJoin { get; set; } + + /// + /// Gets or sets the line style. + /// + /// + /// The line style. + /// + public LineStyle LineStyle { get; set; } + + /// + /// Creates the presentation model for the element. + /// + /// The parent presentation model. + /// + /// The presentation model. + /// + protected override Presenter CreatePresenter(DrawingViewModel v) + { + return new PolygonPresenter(this, v); + } + + /// + /// Represents the presentation model for the . + /// + private class PolygonPresenter : Presenter + { + /// + /// The transformed points. + /// + private ScreenPoint[] transformedPoints; + + /// + /// Initializes a new instance of the class. + /// + /// The model. + /// The presentation model of the parent . + public PolygonPresenter(Polygon model, DrawingViewModel v) + : base(model, v) + { + } + + /// + /// Updates the element. + /// + /// The render context. + public override void Update(IRenderContext rc) + { + this.transformedPoints = this.Model.Points.Select(this.Transform).ToArray(); + } + + /// + /// Gets the bounding box of the element. + /// + /// The render context. + /// + /// The bounding box. + /// + public override BoundingBox GetBounds(IRenderContext rc) + { + var bbox = new BoundingBox(); + foreach (var p in this.Model.Points) + { + bbox.Union(p); + } + + return bbox; + } + + /// + /// Renders the element. + /// + /// The render context. + public override void Render(IRenderContext rc) + { + rc.DrawPolygon( + this.transformedPoints, + this.Model.Fill, + this.Model.Stroke, + this.Transform(this.Model.Thickness), + this.Model.LineStyle.GetDashArray(), + this.Model.LineJoin); + } + } + } +} diff --git a/Source/OxyPlot/Drawing/DrawingModel/Elements/Polyline.cs b/Source/OxyPlot/Drawing/DrawingModel/Elements/Polyline.cs new file mode 100644 index 000000000..8cdc17832 --- /dev/null +++ b/Source/OxyPlot/Drawing/DrawingModel/Elements/Polyline.cs @@ -0,0 +1,91 @@ +// -------------------------------------------------------------------------------------------------------------------- +// +// Copyright (c) 2014 OxyPlot contributors +// +// +// Represents a polyline element. +// +// -------------------------------------------------------------------------------------------------------------------- + +namespace OxyPlot.Drawing +{ + using System.Collections.Generic; + + /// + /// Represents a polyline element. + /// + public class Polyline : PointsElement + { + /// + /// Initializes a new instance of the class. + /// + public Polyline() + { + } + + /// + /// Initializes a new instance of the class. + /// + /// The points. + public Polyline(IEnumerable points) + : base(points) + { + } + + /// + /// Adds the specified point. + /// + /// The x coordinate. + /// The y coordinate. + public void Add(double x, double y) + { + this.Points.Add(new DataPoint(x, y)); + } + + /// + /// Adds a range of points. + /// + /// The points. + public void Add(params DataPoint[] points) + { + this.Points.AddRange(points); + } + + /// + /// Creates the presentation model for the element. + /// + /// The parent presentation model. + /// + /// The presentation model. + /// + protected override DrawingElement.Presenter CreatePresenter(DrawingViewModel v) + { + return new PolylinePresenter(this, v); + } + + /// + /// Represents the presentation model for the . + /// + protected class PolylinePresenter : PointsPresenter + { + /// + /// Initializes a new instance of the class. + /// + /// The model. + /// The v. + public PolylinePresenter(Polyline model, DrawingViewModel v) + : base(model, v) + { + } + + /// + /// Renders the element. + /// + /// The render context. + public override void Render(IRenderContext rc) + { + rc.DrawLine(this.TransformedPoints, this.Model.Color, this.Transform(this.Model.Thickness), this.Model.LineStyle.GetDashArray(), this.Model.LineJoin, this.Model.Aliased); + } + } + } +} \ No newline at end of file diff --git a/Source/OxyPlot/Drawing/DrawingModel/Elements/Rectangle.cs b/Source/OxyPlot/Drawing/DrawingModel/Elements/Rectangle.cs new file mode 100644 index 000000000..4b5d76e0a --- /dev/null +++ b/Source/OxyPlot/Drawing/DrawingModel/Elements/Rectangle.cs @@ -0,0 +1,118 @@ +// -------------------------------------------------------------------------------------------------------------------- +// +// Copyright (c) 2014 OxyPlot contributors +// +// +// Represents a rectangle element. +// +// -------------------------------------------------------------------------------------------------------------------- + +namespace OxyPlot.Drawing +{ + /// + /// Represents a rectangle element. + /// + public class Rectangle : ShapeElement + { + /// + /// Gets or sets the minimum x coordinate. + /// + /// + /// The minimum x coordinate. + /// + public double MinimumX { get; set; } + + /// + /// Gets or sets the maximum x coordinate. + /// + /// + /// The maximum x coordinate. + /// + public double MaximumX { get; set; } + + /// + /// Gets or sets the minimum y coordinate. + /// + /// + /// The minimum y coordinate. + /// + public double MinimumY { get; set; } + + /// + /// Gets or sets the maximum y coordinate. + /// + /// + /// The maximum y coordinate. + /// + public double MaximumY { get; set; } + + /// + /// Creates the presentation model for the element. + /// + /// The parent presentation model. + /// + /// The presentation model. + /// + protected override Presenter CreatePresenter(DrawingViewModel v) + { + return new RectanglePresenter(this, v); + } + + /// + /// Represents the presentation model for the . + /// + private class RectanglePresenter : Presenter + { + /// + /// The rectangle. + /// + private OxyRect rect; + + /// + /// Initializes a new instance of the class. + /// + /// The model. + /// The presentation model of the parent . + public RectanglePresenter(Rectangle model, DrawingViewModel v) + : base(model, v) + { + } + + /// + /// Gets the bounding box of the element. + /// + /// The render context. + /// + /// The bounding box. + /// + public override BoundingBox GetBounds(IRenderContext rc) + { + return new BoundingBox( + this.Model.MinimumX, + this.Model.MinimumY, + this.Model.MaximumX, + this.Model.MaximumY); + } + + /// + /// Updates the element. + /// + /// The render context. + public override void Update(IRenderContext rc) + { + var p1 = this.Transform(this.Model.MinimumX, this.Model.MaximumY); + var p2 = this.Transform(this.Model.MaximumX, this.Model.MinimumY); + this.rect = new OxyRect(p1, p2); + } + + /// + /// Renders the element. + /// + /// The render context. + public override void Render(IRenderContext rc) + { + rc.DrawRectangle(this.rect, this.Model.Fill, this.Model.Stroke, this.Transform(this.Model.Thickness)); + } + } + } +} \ No newline at end of file diff --git a/Source/OxyPlot/Drawing/DrawingModel/Elements/RoundedRectangle.cs b/Source/OxyPlot/Drawing/DrawingModel/Elements/RoundedRectangle.cs new file mode 100644 index 000000000..c1231f938 --- /dev/null +++ b/Source/OxyPlot/Drawing/DrawingModel/Elements/RoundedRectangle.cs @@ -0,0 +1,129 @@ +// -------------------------------------------------------------------------------------------------------------------- +// +// Copyright (c) 2014 OxyPlot contributors +// +// +// Represents a rounded rectangle. +// +// -------------------------------------------------------------------------------------------------------------------- + +namespace OxyPlot.Drawing +{ + using System.Collections.Generic; + + /// + /// Represents a rounded rectangle. + /// + public class RoundedRectangle : Rectangle + { + /// + /// Gets or sets the corner radius. + /// + /// + /// The corner radius. + /// + public double CornerRadius { get; set; } + + /// + /// Creates the presentation model for the element. + /// + /// The parent presentation model. + /// + /// The presentation model. + /// + protected override Presenter CreatePresenter(DrawingViewModel v) + { + return new RoundedRectanglePresenter(this, v); + } + + /// + /// Represents the presentation model for the . + /// + private class RoundedRectanglePresenter : Presenter + { + /// + /// The rectangle + /// + private OxyRect rect; + + /// + /// The points + /// + private List points; + + /// + /// Initializes a new instance of the class. + /// + /// The model. + /// The presentation model of the parent . + public RoundedRectanglePresenter(RoundedRectangle model, DrawingViewModel v) + : base(model, v) + { + } + + /// + /// Gets the bounding box of the element. + /// + /// The render context. + /// + /// The bounding box. + /// + public override BoundingBox GetBounds(IRenderContext rc) + { + return new BoundingBox( + this.Model.MinimumX, + this.Model.MinimumY, + this.Model.MaximumX, + this.Model.MaximumY); + } + + /// + /// Updates the element. + /// + /// The render context. + public override void Update(IRenderContext rc) + { + var p1 = this.Transform(this.Model.MinimumX, this.Model.MaximumY); + var p2 = this.Transform(this.Model.MaximumX, this.Model.MinimumY); + var cr = this.Transform(this.Model.CornerRadius); + this.rect = new OxyRect(p1, p2); + if (cr > 0) + { + this.points = new List { new ScreenPoint(p1.X + cr, p1.Y) }; + this.points.AddRange(Interpolation.Arc(new ScreenPoint(p2.X - cr, p1.Y + cr), cr, cr, -90, 0)); + this.points.AddRange(Interpolation.Arc(new ScreenPoint(p2.X - cr, p2.Y - cr), cr, cr, 0, 90)); + this.points.AddRange(Interpolation.Arc(new ScreenPoint(p1.X + cr, p2.Y - cr), cr, cr, 90, 180)); + this.points.AddRange(Interpolation.Arc(new ScreenPoint(p1.X + cr, p1.Y + cr), cr, cr, 180, 270)); + } + else + { + this.points = null; + } + } + + /// + /// Renders the element. + /// + /// The render context. + public override void Render(IRenderContext rc) + { + if (this.points != null) + { + rc.DrawPolygon( + this.points, + this.Model.Fill, + this.Model.Stroke, + this.Transform(this.Model.Thickness)); + } + else + { + rc.DrawRectangleAsPolygon( + this.rect, + this.Model.Fill, + this.Model.Stroke, + this.Transform(this.Model.Thickness)); + } + } + } + } +} \ No newline at end of file diff --git a/Source/OxyPlot/Drawing/DrawingModel/Elements/Text.cs b/Source/OxyPlot/Drawing/DrawingModel/Elements/Text.cs new file mode 100644 index 000000000..1755d6eb7 --- /dev/null +++ b/Source/OxyPlot/Drawing/DrawingModel/Elements/Text.cs @@ -0,0 +1,179 @@ +// -------------------------------------------------------------------------------------------------------------------- +// +// Copyright (c) 2014 OxyPlot contributors +// +// +// Represents an element displaying text. +// +// -------------------------------------------------------------------------------------------------------------------- + +namespace OxyPlot.Drawing +{ + /// + /// Represents an element displaying text. + /// + public class Text : DrawingElement + { + /// + /// Initializes a new instance of the class. + /// + public Text() + { + this.Color = OxyColors.Black; + this.FontFamily = "Segoe UI"; + this.FontSize = -11; + this.FontWeight = FontWeights.Normal; + this.HorizontalAlignment = HorizontalAlignment.Left; + this.VerticalAlignment = VerticalAlignment.Top; + } + + /// + /// Gets or sets the color. + /// + /// + /// The color. + /// + public OxyColor Color { get; set; } + + /// + /// Gets or sets the position. + /// + /// + /// The point. + /// + public DataPoint Point { get; set; } + + /// + /// Gets or sets the content. + /// + /// + /// The content. + /// + public string Content { get; set; } + + /// + /// Gets or sets the rotation of the text. + /// + /// + /// The rotate. + /// + public double Rotate { get; set; } + + /// + /// Gets or sets the horizontal alignment. + /// + /// + /// The horizontal alignment. + /// + public HorizontalAlignment HorizontalAlignment { get; set; } + + /// + /// Gets or sets the vertical alignment. + /// + /// + /// The vertical alignment. + /// + public VerticalAlignment VerticalAlignment { get; set; } + + /// + /// Creates the presentation model for the element. + /// + /// The parent presentation model. + /// + /// The presentation model. + /// + protected override Presenter CreatePresenter(DrawingViewModel v) + { + return new TextPresenter(this, v); + } + + /// + /// Represents the presentation model for the . + /// + private class TextPresenter : Presenter + { + /// + /// Initializes a new instance of the class. + /// + /// The model. + /// The presentation model of the parent . + public TextPresenter(Text model, DrawingViewModel v) + : base(model, v) + { + } + + /// + /// Updates the element. + /// + /// The render context. + public override void Update(IRenderContext rc) + { + } + + /// + /// Renders the element. + /// + /// The render context. + public override void Render(IRenderContext rc) + { + var screenPoints = this.Transform(this.Model.Point); + rc.DrawText( + screenPoints, + this.Model.Content, + this.Model.Color, + this.Model.FontFamily, + this.Transform(this.Model.FontSize), + this.Model.FontWeight, + this.Model.Rotate, + this.Model.HorizontalAlignment, + this.Model.VerticalAlignment); + } + + /// + /// Gets the bounding box of the element. + /// + /// The render context. + /// + /// The bounding box. + /// + public override BoundingBox GetBounds(IRenderContext rc) + { + // todo: adjust for rotating and alignment + var size = rc.MeasureText( + this.Model.Content, + this.Model.FontFamily, + this.Transform(this.Model.FontSize), + this.Model.FontWeight); + var w = this.InverseTransform(size.Width); + var h = this.InverseTransform(size.Height); + var dx = 0d; + if (this.Model.HorizontalAlignment == HorizontalAlignment.Center) + { + dx = -w / 2; + } + + if (this.Model.HorizontalAlignment == HorizontalAlignment.Right) + { + dx = -w; + } + + var dy = 0d; + if (this.Model.VerticalAlignment == VerticalAlignment.Middle) + { + dy = -h / 2; + } + + if (this.Model.VerticalAlignment == VerticalAlignment.Top) + { + dy = -h; + } + + double x = this.Model.Point.X + dx; + double y = this.Model.Point.Y + dy; + + // TODO: account for rotation + return new BoundingBox(x, y, x + w, y + h); + } + } + } +} \ No newline at end of file diff --git a/Source/OxyPlot/Drawing/DrawingModel/Elements/TileLayer.cs b/Source/OxyPlot/Drawing/DrawingModel/Elements/TileLayer.cs new file mode 100644 index 000000000..4dceb5b35 --- /dev/null +++ b/Source/OxyPlot/Drawing/DrawingModel/Elements/TileLayer.cs @@ -0,0 +1,504 @@ +// -------------------------------------------------------------------------------------------------------------------- +// +// Copyright (c) 2014 OxyPlot contributors +// +// +// Represents a tile map layer. +// +// -------------------------------------------------------------------------------------------------------------------- + +namespace OxyPlot.Drawing +{ + using System; + using System.Collections.Generic; + using System.Globalization; + using System.IO; + using System.Net; + using System.Threading; + + /// + /// Represents a tile map layer. + /// + public class TileLayer : DrawingElement + { + /// + /// The image cache. + /// + private readonly Dictionary images = new Dictionary(); + + /// + /// The download queue. + /// + private readonly Queue queue = new Queue(); + + /// + /// The current number of downloads + /// + private int numberOfDownloads; + + /// + /// Initializes a new instance of the class. + /// + public TileLayer() + { + this.Source = "http://tile.openstreetmap.org/{Z}/{X}/{Y}.png"; + this.CopyrightNotice = "OpenStreetMap"; + + this.TileSize = 256; + this.MinZoomLevel = 0; + this.MaxZoomLevel = 20; + this.Opacity = 1d; + this.FontFamily = "Arial"; + this.FontSize = 12; + this.FontWeight = FontWeights.Normal; + this.MaxNumberOfDownloads = 8; + } + + /// + /// Gets or sets the max number of simultaneous downloads. + /// + /// The max number of downloads. + public int MaxNumberOfDownloads { get; set; } + + /// + /// Gets or sets the source. + /// + /// + /// The source. + /// + public string Source { get; set; } + + /// + /// Gets or sets the copyright notice. + /// + /// + /// The copyright notice. + /// + public string CopyrightNotice { get; set; } + + /// + /// Gets or sets the opacity. + /// + /// + /// The opacity. + /// + public double Opacity { get; set; } + + /// + /// Gets or sets the size of the tile. + /// + /// + /// The size of the tile. + /// + public int TileSize { get; set; } + + /// + /// Gets or sets the minimum zoom level. + /// + /// + /// The minimum zoom level. + /// + public int MinZoomLevel { get; set; } + + /// + /// Gets or sets the maximum zoom level. + /// + /// + /// The maximum zoom level. + /// + public int MaxZoomLevel { get; set; } + + /// + /// Transforms a position to a coordinate (x,y). + /// + /// The latitude and longitude. + /// + /// Tile coordinates. + /// + public static DataPoint ToPoint(LatLon latlon) + { + double x; + double y; + LatLonToTile(latlon.Latitude, latlon.Longitude, 0, out x, out y); + return new DataPoint(x, -y); + } + + /// + /// Transforms a coordinate (x,y) to a position. + /// + /// The point. + /// + /// A structure. + /// + public static LatLon ToLatLon(DataPoint point) + { + double latitude; + double longitude; + TileToLatLon(point.X, -point.Y, 0, out latitude, out longitude); + return new LatLon(latitude, longitude); + } + + /// + /// Transforms the specified latitude and longitude to a . + /// + /// The latitude and longitude. + /// The transformed point. + public DataPoint Transform(LatLon latLon) + { + return ToPoint(latLon); + } + + /// + /// Creates the presentation model for the element. + /// + /// The parent presentation model. + /// + /// The presentation model. + /// + protected override Presenter CreatePresenter(DrawingViewModel v) + { + return new TileLayerPresenter(this, v); + } + + /// + /// Transforms a position to a tile coordinate. + /// + /// The latitude. + /// The longitude. + /// The zoom. + /// The x. + /// The y. + private static void LatLonToTile(double latitude, double longitude, int zoom, out double x, out double y) + { + // http://wiki.openstreetmap.org/wiki/Slippy_map_tilenames + int n = 1 << zoom; + double lat = latitude / 180 * Math.PI; + x = (longitude + 180.0) / 360.0 * n; + y = (1.0 - (Math.Log(Math.Tan(lat) + (1.0 / Math.Cos(lat))) / Math.PI)) / 2.0 * n; + } + + /// + /// Transforms a tile coordinate (x,y) to a position. + /// + /// The x. + /// The y. + /// The zoom. + /// The latitude. + /// The longitude. + private static void TileToLatLon(double x, double y, int zoom, out double latitude, out double longitude) + { + int n = 1 << zoom; + longitude = (x / n * 360.0) - 180.0; + double lat = Math.Atan(Math.Sinh(Math.PI * (1 - (2 * y / n)))); + latitude = lat * 180.0 / Math.PI; + } + + /// + /// Gets the image from the specified uri. + /// + /// The URI. + /// Get the image asynchronously if set to true. The plot model will be invalidated when the image has been downloaded. + /// The on download completed delegate. + /// + /// The image. + /// + /// + /// This method gets the image from cache, or starts an async download. + /// + private OxyImage GetImage(string uri, bool asyncLoading, Action onDownloadCompleted) + { + OxyImage img; + if (this.images.TryGetValue(uri, out img)) + { + return img; + } + + if (!asyncLoading) + { + 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(onDownloadCompleted); + return null; + } + + /// + /// Downloads the image from the specified URI. + /// + /// The URI. + /// The image + private OxyImage Download(string uri) + { + OxyImage img = null; + var mre = new ManualResetEvent(false); +/* var request = (HttpWebRequest)WebRequest.Create(uri); + request.Method = "GET"; + request.BeginGetResponse( + r => + { + try + { + if (request.HaveResponse) + { + var response = request.EndGetResponse(r); + var stream = response.GetResponseStream(); + + var ms = new MemoryStream(); + stream.CopyTo(ms); + var buffer = ms.ToArray(); + + img = new OxyImage(buffer); + this.images[uri] = img; + } + } + catch (Exception e) + { + var ie = e; + while (ie != null) + { + System.Diagnostics.Debug.WriteLine(ie.Message); + ie = ie.InnerException; + } + } + finally + { + mre.Set(); + } + }, + request); + */ + mre.WaitOne(); + return img; + } + + /// + /// Starts the next download in the queue. + /// + /// The download completed delegate. + private void BeginDownload(Action onDownloadCompleted) + { + 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, onDownloadCompleted); + } + } + catch (Exception e) + { + var ie = e; + while (ie != null) + { + System.Diagnostics.Debug.WriteLine(ie.Message); + ie = ie.InnerException; + } + } + }, + request);*/ + } + + /// + /// The download completed, set the image. + /// + /// The URI. + /// The result. + /// The download completed delegate. + private void DownloadCompleted(string uri, Stream result, Action onDownloadCompleted) + { + 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(); + } + + onDownloadCompleted(); + if (this.queue.Count > 0) + { + this.BeginDownload(onDownloadCompleted); + } + } + + /// + /// Gets the tile URI. + /// + /// The tile x. + /// The tile y. + /// The zoom. + /// The uri. + private string GetTileUri(int x, int y, int zoom) + { + string url = this.Source.Replace("{X}", x.ToString(CultureInfo.InvariantCulture)); + url = url.Replace("{Y}", y.ToString(CultureInfo.InvariantCulture)); + return url.Replace("{Z}", zoom.ToString(CultureInfo.InvariantCulture)); + } + + /// + /// Represents the presentation model for the . + /// + private class TileLayerPresenter : Presenter + { + /// + /// Initializes a new instance of the class. + /// + /// The model. + /// The presentation model of the parent . + public TileLayerPresenter(TileLayer model, DrawingViewModel v) + : base(model, v) + { + } + + /// + /// Gets the bounding box of the element. + /// + /// The render context. + /// + /// The bounding box. + /// + public override BoundingBox GetBounds(IRenderContext rc) + { + return new BoundingBox(); + } + + /// + /// Updates the element. + /// + /// The render context. + public override void Update(IRenderContext rc) + { + } + + /// + /// Renders the element. + /// + /// The render context. + public override void Render(IRenderContext rc) + { + var clientRect = this.DrawingViewModel.ClientArea; + var topLeft = this.InverseTransform(new ScreenPoint(clientRect.Left, clientRect.Top)); + DataPoint bottomRight; + bottomRight = this.InverseTransform(new ScreenPoint(clientRect.Right, clientRect.Bottom)); + var latlon0 = ToLatLon(topLeft); + var latlon1 = ToLatLon(bottomRight); + var lon0 = latlon0.Longitude; + var lon1 = latlon1.Longitude; + var lat0 = latlon0.Latitude; + var lat1 = latlon1.Latitude; + + // the desired number of tiles horizontally + double tilesx = this.DrawingViewModel.ClientArea.Width / this.Model.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.Model.MinZoomLevel) + { + zoom = this.Model.MinZoomLevel; + } + + if (zoom > this.Model.MaxZoomLevel) + { + zoom = this.Model.MaxZoomLevel; + } + + // find tile coordinates for the corners + double x0, y0; + TileLayer.LatLonToTile(lat0, lon0, zoom, out x0, out y0); + double x1, y1; + TileLayer.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.Model.GetTileUri(x, y, zoom); + var img = this.Model.GetImage(uri, rc.RendersToScreen, () => this.DrawingViewModel.Invalidate()); + + if (img == null) + { + continue; + } + + // transform from tile coordinates to lat/lon + double latitude0, latitude1, longitude0, longitude1; + TileLayer.TileToLatLon(x, y, zoom, out latitude0, out longitude0); + TileLayer.TileToLatLon(x + 1, y + 1, zoom, out latitude1, out longitude1); + + // transform from lat/lon to screen coordinates + var s00 = this.Transform(ToPoint(new LatLon(latitude0, longitude0))); + var s11 = this.Transform(ToPoint(new LatLon(latitude1, longitude1))); + + var r = OxyRect.Create(s00.X, s00.Y, s11.X, s11.Y); + + // draw the image + rc.DrawClippedImage(clientRect, img, r.Left, r.Top, r.Width, r.Height, this.Model.Opacity, true); + + // Tile coordinates + // rc.DrawText(r.Center, string.Format("{0},{1}", x, y), OxyColors.Black, this.Model.FontFamily, this.Model.FontSize, this.Model.FontWeight, 0, HorizontalAlignment.Center, VerticalAlignment.Middle); + } + } + + // draw the copyright notice + var p = new ScreenPoint(clientRect.Right - 5, clientRect.Bottom - 5); + var textSize = rc.MeasureText(this.Model.CopyrightNotice, this.Model.FontFamily, this.Model.FontSize, this.Model.FontWeight); + rc.DrawRectangle(new OxyRect(p.X - textSize.Width - 2, p.Y - textSize.Height - 2, textSize.Width + 4, textSize.Height + 4), OxyColor.FromAColor(200, OxyColors.White), OxyColors.Undefined); + + rc.DrawText( + p, + this.Model.CopyrightNotice, + OxyColors.Black, + this.Model.FontFamily, + this.Model.FontSize, + this.Model.FontWeight, + 0, + HorizontalAlignment.Right, + VerticalAlignment.Bottom); + } + } + } +} diff --git a/Source/OxyPlot/Drawing/DrawingModel/Elements/UmlClassBox.cs b/Source/OxyPlot/Drawing/DrawingModel/Elements/UmlClassBox.cs new file mode 100644 index 000000000..6f444221b --- /dev/null +++ b/Source/OxyPlot/Drawing/DrawingModel/Elements/UmlClassBox.cs @@ -0,0 +1,180 @@ +// -------------------------------------------------------------------------------------------------------------------- +// +// Copyright (c) 2014 OxyPlot contributors +// +// +// Represents an UML box. +// +// -------------------------------------------------------------------------------------------------------------------- + +namespace OxyPlot.Drawing +{ + using System; + using System.Linq; + using System.Reflection; + + /// + /// Represents an UML box. + /// + public class UmlClassBox : ShapeElement + { + /// + /// Initializes a new instance of the class. + /// + public UmlClassBox() + { + this.FontFamily = "Consolas"; + this.FontSize = 6; + this.Position = new DataPoint(0, 0); + } + + /// + /// Initializes a new instance of the class. + /// + /// The type. + public UmlClassBox(Type type) + : this() + { + this.Methods = type.GetTypeInfo().DeclaredMethods.Select(mi => mi.Name).ToArray(); + this.Properties = type.GetTypeInfo().DeclaredProperties.Select(mi => mi.Name).ToArray(); + } + + /// + /// Gets or sets the position. + /// + /// + /// The position. + /// + public DataPoint Position { get; set; } + + /// + /// Gets or sets the title. + /// + /// + /// The title. + /// + public string Title { get; set; } + + /// + /// Gets or sets the properties. + /// + /// + /// The properties. + /// + public string[] Properties { get; set; } + + /// + /// Gets or sets the methods. + /// + /// + /// The methods. + /// + public string[] Methods { get; set; } + + /// + /// Creates the presentation model for the element. + /// + /// The presentation model of the parent . + /// + /// The presentation model. + /// + protected override Presenter CreatePresenter(DrawingViewModel v) + { + return new UmlClassBoxPresenter(this, v); + } + + /// + /// Represents the presentation model for the . + /// + private class UmlClassBoxPresenter : Presenter + { + /// + /// The position + /// + private ScreenPoint position; + + /// + /// The font size + /// + private double fontSize; + + /// + /// Initializes a new instance of the class. + /// + /// The model. + /// The v. + public UmlClassBoxPresenter(UmlClassBox model, DrawingViewModel v) + : base(model, v) + { + } + + /// + /// Gets the bounding box of the element. + /// + /// The render context. + /// + /// The bounding box. + /// + public override BoundingBox GetBounds(IRenderContext rc) + { + var currentFontSize = this.Transform(this.Model.FontSize); + var titleSize = rc.MeasureText(this.Model.Title, this.Model.FontFamily, currentFontSize, FontWeights.Bold); + var propertySizes = this.Model.Properties.Select(p => rc.MeasureText(p, this.Model.FontFamily, currentFontSize)).ToArray(); + var methodSizes = this.Model.Properties.Select(p => rc.MeasureText(p, this.Model.FontFamily, currentFontSize)).ToArray(); + var maxWidth = Math.Max(titleSize.Width, Math.Max(propertySizes.Max(p => p.Width), methodSizes.Max(p => p.Width))); + var totalHeight = titleSize.Height + propertySizes.Sum(p => p.Height) + methodSizes.Sum(p => p.Height); + maxWidth = this.InverseTransform(maxWidth); + totalHeight = this.InverseTransform(totalHeight); + var bb = new BoundingBox(); + bb.Union(this.Model.Position); + bb.Union(this.Model.Position.X + maxWidth, this.Model.Position.Y - totalHeight); + return bb; + } + + /// + /// Updates the element. + /// + /// The render context. + public override void Update(IRenderContext rc) + { + this.position = this.Transform(this.Model.Position); + this.fontSize = this.Transform(this.Model.FontSize); + } + + /// + /// Renders the element. + /// + /// The render context. + public override void Render(IRenderContext rc) + { + var x = this.position.X + 5; + var y = this.position.Y; + rc.DrawText(new ScreenPoint(x, y), this.Model.Title, OxyColors.Black, this.Model.FontFamily, this.fontSize, FontWeights.Bold); + var titleSize = rc.MeasureText(this.Model.Title, this.Model.FontFamily, this.fontSize, FontWeights.Bold); + y += titleSize.Height; + var y0 = y; + var maxWidth = titleSize.Width; + foreach (var p in this.Model.Properties) + { + rc.DrawText(new ScreenPoint(x, y), p, OxyColors.Black, this.Model.FontFamily, this.fontSize); + var size = rc.MeasureText(p, this.Model.FontFamily, this.fontSize); + y += size.Height; + maxWidth = Math.Max(maxWidth, size.Width); + } + + var y1 = y; + foreach (var p in this.Model.Methods) + { + rc.DrawText(new ScreenPoint(x, y), p, OxyColors.Black, this.Model.FontFamily, this.fontSize); + var size = rc.MeasureText(p, this.Model.FontFamily, this.fontSize); + y += size.Height; + maxWidth = Math.Max(maxWidth, size.Width); + } + + var rect = new OxyRect(this.position.X, this.position.Y, maxWidth + (this.fontSize / 2), y - this.position.Y); + rc.DrawRectangle(rect, OxyColors.Undefined, OxyColors.Black); + rc.DrawLineSegments(new[] { new ScreenPoint(this.position.X, y0), new ScreenPoint(rect.Right, y0), new ScreenPoint(this.position.X, y1), new ScreenPoint(rect.Right, y1) }, OxyColors.Black); + } + } + } +} diff --git a/Source/OxyPlot/Drawing/DrawingModel/FrameEventArgs.cs b/Source/OxyPlot/Drawing/DrawingModel/FrameEventArgs.cs new file mode 100644 index 000000000..ccf63054f --- /dev/null +++ b/Source/OxyPlot/Drawing/DrawingModel/FrameEventArgs.cs @@ -0,0 +1,46 @@ +// -------------------------------------------------------------------------------------------------------------------- +// +// Copyright (c) 2014 OxyPlot contributors +// +// +// Provides data for the event. +// +// -------------------------------------------------------------------------------------------------------------------- + +namespace OxyPlot.Drawing +{ + using System; + + /// + /// Provides data for the event. + /// + public class FrameEventArgs : EventArgs + { + /// + /// Initializes a new instance of the class. + /// + /// The now ticks. + /// The previous ticks. + public FrameEventArgs(long nowTicks, long previousTicks) + { + this.CumulativeTime = TimeSpan.FromTicks(nowTicks); + this.DeltaTime = TimeSpan.FromTicks(nowTicks - previousTicks); + } + + /// + /// Gets the cumulative time. + /// + /// + /// The cumulative time. + /// + public TimeSpan CumulativeTime { get; private set; } + + /// + /// Gets the delta time. + /// + /// + /// The delta time. + /// + public TimeSpan DeltaTime { get; private set; } + } +} \ No newline at end of file diff --git a/Source/OxyPlot/Drawing/DrawingModel/IDrawingElement.cs b/Source/OxyPlot/Drawing/DrawingModel/IDrawingElement.cs new file mode 100644 index 000000000..3866ac05f --- /dev/null +++ b/Source/OxyPlot/Drawing/DrawingModel/IDrawingElement.cs @@ -0,0 +1,24 @@ +// -------------------------------------------------------------------------------------------------------------------- +// +// Copyright (c) 2014 OxyPlot contributors +// +// +// Specifies functionality for elements of a DrawingModel. +// +// -------------------------------------------------------------------------------------------------------------------- + +namespace OxyPlot.Drawing +{ + /// + /// Specifies functionality for elements of a . + /// + public interface IDrawingElement + { + /// + /// Creates the presentation model for the element. + /// + /// The parent presentation model. + /// The presentation model. + DrawingElement.Presenter CreatePresentationModel(DrawingViewModel v); + } +} \ No newline at end of file diff --git a/Source/OxyPlot/Drawing/DrawingModel/PointsElement.cs b/Source/OxyPlot/Drawing/DrawingModel/PointsElement.cs new file mode 100644 index 000000000..dd7f81d57 --- /dev/null +++ b/Source/OxyPlot/Drawing/DrawingModel/PointsElement.cs @@ -0,0 +1,101 @@ +// -------------------------------------------------------------------------------------------------------------------- +// +// Copyright (c) 2014 OxyPlot contributors +// +// +// Provides an abstract base class for elements that contains points. +// +// -------------------------------------------------------------------------------------------------------------------- + +namespace OxyPlot.Drawing +{ + using System.Collections.Generic; + using System.Linq; + + /// + /// Provides an abstract base class for elements that contains points. + /// + public abstract class PointsElement : StrokedElement + { + /// + /// Initializes a new instance of the class. + /// + protected PointsElement() + { + this.Points = new List(); + } + + /// + /// Initializes a new instance of the class. + /// + /// The points. + protected PointsElement(IEnumerable points) + { + this.Points = new List(points); + } + + /// + /// Gets the points. + /// + /// + /// The points. + /// + public List Points { get; private set; } + + /// + /// Represents the presentation model for the . + /// + /// The model type. + protected abstract class PointsPresenter : Presenter where T : PointsElement + { + /// + /// Initializes a new instance of the class. + /// + /// The model. + /// The presentation model of the parent . + protected PointsPresenter(T model, DrawingViewModel v) + : base(model, v) + { + } + + /// + /// Gets the transformed points. + /// + /// + /// The transformed points. + /// + protected ScreenPoint[] TransformedPoints { get; private set; } + + /// + /// Gets the bounding box of the element. + /// + /// The render context. + /// + /// The bounding box. + /// + public override BoundingBox GetBounds(IRenderContext rc) + { + var bbox = new BoundingBox(); + foreach (var p in this.Model.Points) + { + bbox.Union(p); + } + + return bbox; + } + + /// + /// Updates the element. + /// + /// The render context. + public override void Update(IRenderContext rc) + { + this.TransformedPoints = this.Model.Points.Select(this.Transform).ToArray(); + if (this.Model.MinimumSegmentLength > 0) + { + this.TransformedPoints = ScreenPointHelper.ResamplePoints(this.TransformedPoints, this.Model.MinimumSegmentLength).ToArray(); + } + } + } + } +} \ No newline at end of file diff --git a/Source/OxyPlot/Drawing/DrawingModel/ShapeElement.cs b/Source/OxyPlot/Drawing/DrawingModel/ShapeElement.cs new file mode 100644 index 000000000..470d8ff4c --- /dev/null +++ b/Source/OxyPlot/Drawing/DrawingModel/ShapeElement.cs @@ -0,0 +1,72 @@ +// -------------------------------------------------------------------------------------------------------------------- +// +// Copyright (c) 2014 OxyPlot contributors +// +// +// Provides an abstract base class for elements that has a shape. +// +// -------------------------------------------------------------------------------------------------------------------- + +namespace OxyPlot.Drawing +{ + /// + /// Provides an abstract base class for elements that has a shape. + /// + public abstract class ShapeElement : DrawingElement + { + /// + /// Initializes a new instance of the class. + /// + protected ShapeElement() + { + this.Stroke = OxyColors.Black; + this.Fill = OxyColors.Undefined; + this.Thickness = -1; + this.TextColor = OxyColors.Black; + this.FontFamily = "Arial"; + this.FontSize = 12; + this.FontWeight = FontWeights.Normal; + } + + /// + /// Gets or sets the stroke color. + /// + /// + /// The color. The default is . + /// + public OxyColor Stroke { get; set; } + + /// + /// Gets or sets the fill color. + /// + /// + /// The color. The default is . + /// + public OxyColor Fill { get; set; } + + /// + /// Gets or sets the thickness. + /// + /// + /// The thickness. The default is -1. + /// + /// Negative numbers specifies the thickness in output device units. + public double Thickness { get; set; } + + /// + /// Gets or sets the text of the element. + /// + /// + /// The text. + /// + public string Text { get; set; } + + /// + /// Gets or sets the color of the text. + /// + /// + /// The color of the text. + /// + public OxyColor TextColor { get; set; } + } +} \ No newline at end of file diff --git a/Source/OxyPlot/Drawing/DrawingModel/StrokedElement.cs b/Source/OxyPlot/Drawing/DrawingModel/StrokedElement.cs new file mode 100644 index 000000000..5f7f82804 --- /dev/null +++ b/Source/OxyPlot/Drawing/DrawingModel/StrokedElement.cs @@ -0,0 +1,76 @@ +// -------------------------------------------------------------------------------------------------------------------- +// +// Copyright (c) 2014 OxyPlot contributors +// +// +// Represents an element with a stroke. +// +// -------------------------------------------------------------------------------------------------------------------- + +namespace OxyPlot.Drawing +{ + /// + /// Represents an element with a stroke. + /// + public abstract class StrokedElement : DrawingElement + { + /// + /// Initializes a new instance of the class. + /// + protected StrokedElement() + { + this.Color = OxyColors.Black; + this.Thickness = -1; + this.LineJoin = LineJoin.Miter; + this.LineStyle = LineStyle.Solid; + } + + /// + /// Gets or sets the color. + /// + /// + /// The color. + /// + public OxyColor Color { get; set; } + + /// + /// Gets or sets the thickness. + /// + /// + /// The thickness. + /// + public double Thickness { get; set; } + + /// + /// Gets or sets a value indicating whether this is aliased. + /// + /// + /// true if aliased; otherwise, false. + /// + public bool Aliased { get; set; } + + /// + /// Gets or sets the line join type. + /// + /// + /// The line join type. + /// + public LineJoin LineJoin { get; set; } + + /// + /// Gets or sets the line style. + /// + /// + /// The line style. + /// + public LineStyle LineStyle { get; set; } + + /// + /// Gets or sets the minimum length of the segments. + /// + /// + /// The minimum length of the segment. + /// + public double MinimumSegmentLength { get; set; } + } +} diff --git a/Source/OxyPlot/Drawing/DrawingView/DrawingViewModel.cs b/Source/OxyPlot/Drawing/DrawingView/DrawingViewModel.cs new file mode 100644 index 000000000..b496f885b --- /dev/null +++ b/Source/OxyPlot/Drawing/DrawingView/DrawingViewModel.cs @@ -0,0 +1,390 @@ +// -------------------------------------------------------------------------------------------------------------------- +// +// Copyright (c) 2014 OxyPlot contributors +// +// +// Represents a presentation model for a . +// +// -------------------------------------------------------------------------------------------------------------------- + +namespace OxyPlot.Drawing +{ + using System; + using System.Collections.Generic; + using System.Linq; + + /// + /// Represents a presentation model for a . + /// + public class DrawingViewModel : IDrawingViewModel + { + /// + /// The drawing + /// + private readonly DrawingModel drawing; + + /// + /// The view + /// + private readonly IDrawingView view; + + /// + /// The element to element presentation model map + /// + private readonly Dictionary elementMap; + + /// + /// The x-offset. + /// + private double ox; + + /// + /// The y-offset. + /// + private double oy; + + /// + /// The scale. + /// + private double scale; + + /// + /// Initializes a new instance of the class. + /// + /// The view. + /// The drawing model. + public DrawingViewModel(IDrawingView view, DrawingModel drawing) + { + this.view = view; + this.drawing = drawing; + this.drawing.Changed += this.HandleChangedDrawing; + this.elementMap = new Dictionary(); + } + + /// + /// Gets the client rectangle. + /// + /// + /// The client rectangle. + /// + public OxyRect ClientArea + { + get + { + return this.view.ClientArea; + } + } + + /// + /// Gets the element presentation models. + /// + /// + /// The element presentation models. + /// + public IEnumerable ElementPresentationModels + { + get + { + foreach (var e in this.drawing.Elements) + { + DrawingElement.Presenter vm; + if (!this.elementMap.TryGetValue(e, out vm)) + { + vm = ((IDrawingElement)e).CreatePresentationModel(this); + this.elementMap[e] = vm; + } + + yield return vm; + } + } + } + + /// + /// Returns the elements that are hit at the specified position. + /// + /// The hit test arguments. + /// + /// A sequence of hit results. + /// + public IEnumerable HitTest(HitTestArguments args) + { + // Revert the order to handle the top-level elements first + foreach (var element in this.ElementPresentationModels.Reverse()) + { + var result = element.HitTest(args); + if (result != null) + { + yield return result; + } + } + } + + /// + /// Transforms the specified point. + /// + /// The point. + /// The transformed point. + public ScreenPoint Transform(DataPoint p) + { + return new ScreenPoint((p.X - this.ox) * this.scale, (this.oy - p.Y) * this.scale); + } + + /// + /// Pans the view by the specified vector. + /// + /// The panning vector. + public void Pan(ScreenVector delta) + { + this.ox -= delta.X / this.scale; + this.oy += delta.Y / this.scale; + this.view.Invalidate(); + } + + /// + /// Pans the view by the specified vector. + /// + /// The delta. + /// The current position. + public void Pan(ScreenVector delta, ScreenPoint current) + { + this.Pan(delta); + } + + /// + /// Transforms the specified point. + /// + /// The x. + /// The y. + /// The transformed point. + public ScreenPoint Transform(double x, double y) + { + return new ScreenPoint((x - this.ox) * this.scale, (this.oy - y) * this.scale); + } + + /// + /// Transforms the specified length. + /// + /// The length. + /// The transformed length. + public double Transform(double t) + { + return t < 0 ? -t : t * this.scale; + } + + /// + /// Inverses the transform. + /// + /// The x. + /// The y. + /// The transformed point. + public DataPoint InverseTransform(double x, double y) + { + return new DataPoint((x / this.scale) + this.ox, this.oy - (y / this.scale)); + } + + /// + /// Inverse-transforms the specified point. + /// + /// The point. + /// The transformed point. + public DataPoint InverseTransform(ScreenPoint p) + { + return new DataPoint((p.x / this.scale) + this.ox, this.oy - (p.y / this.scale)); + } + + /// + /// Inverse-transforms the specified length. + /// + /// The length. + /// The transformed length. + public double InverseTransform(double t) + { + return this.scale.Equals(0) || double.IsNaN(this.scale) ? 0 : t / this.scale; + } + + /// + /// Invalidates the view. + /// + public void Invalidate() + { + this.view.Invalidate(); + } + + /// + /// Resets the view. + /// + public void Reset() + { + this.view.ZoomExtents(); + this.view.Invalidate(); + } + + /// + /// Zooms the specified rectangle. + /// + /// The rectangle. + public void Zoom(OxyRect rect) + { + var p0 = this.InverseTransform(rect.Left, rect.Bottom); + var p1 = this.InverseTransform(rect.Right, rect.Top); + var padding = this.view.DrawingPadding; + var sx = (this.view.ClientArea.Width - (padding * 2)) / (p1.X - p0.X); + var sy = (this.view.ClientArea.Height - (padding * 2)) / (p1.Y - p0.Y); + this.scale = Math.Min(sx, sy); + this.ox = ((p0.X + p1.X) * 0.5) - ((this.view.ClientArea.Center.X + padding) / this.scale); + this.oy = ((p0.Y + p1.Y) * 0.5) + ((this.view.ClientArea.Center.Y + padding) / this.scale); + this.view.Invalidate(); + } + + /// + /// Zooms the specified delta. + /// + /// The delta. + public void Zoom(double delta) + { + this.ZoomAt(new ScreenVector(delta, delta), this.view.ClientArea.Center); + } + + /// + /// Zooms at the specified position. + /// + /// The delta. + /// The position. + public void ZoomAt(ScreenVector delta, ScreenPoint p) + { + var newscale = this.scale * delta.Y; + var x = this.scale > 0 ? (p.X / this.scale) + this.ox : 0; + var y = this.scale > 0 ? this.oy - (p.Y / this.scale) : 0; + + this.ox = x - ((x - this.ox) * this.scale / newscale); + this.oy = y - ((y - this.oy) * this.scale / newscale); + this.scale = newscale; + + this.view.Invalidate(); + } + + /// + /// Zooms the extents. + /// + /// The render context. + public void ZoomExtents(IRenderContext rc) + { + this.scale = 1; + this.ox = this.oy = 0; + if (this.drawing == null) + { + return; + } + + if (this.view.ClientArea.Width <= 0 || this.view.ClientArea.Height <= 0) + { + this.scale = double.NaN; + } + + var bbox = this.GetBounds(rc); + if (bbox == null || bbox.IsEmpty()) + { + return; + } + + var rx = bbox.MaximumX - bbox.MinimumX; + var ry = bbox.MaximumY - bbox.MinimumY; + var padding = this.view.DrawingPadding; + var w = this.view.ClientArea.Width - (padding * 2); + var h = this.view.ClientArea.Height - (padding * 2); + var sx = rx > 0 ? w / rx : 1; + var sy = ry > 0 ? h / ry : 1; + + this.scale = Math.Min(sx, sy); + + this.ox = ((bbox.MaximumX + bbox.MinimumX) * 0.5) - (this.view.ClientArea.Width * 0.5 / this.scale); + this.oy = ((bbox.MaximumY + bbox.MinimumY) * 0.5) + (this.view.ClientArea.Height * 0.5 / this.scale); + + this.view.Invalidate(); + } + + /// + /// Updates the element view models. + /// + /// The render context. + public void Update(IRenderContext rc) + { + foreach (var e in this.ElementPresentationModels) + { + e.Update(rc); + } + } + + /// + /// Gets the bounding box. + /// + /// The render context.. + /// The bounding box. + public BoundingBox GetBounds(IRenderContext rc) + { + var bbox = new BoundingBox(); + foreach (var e in this.ElementPresentationModels) + { + bbox.Union(e.GetBounds(rc)); + } + + return bbox; + } + + /// + /// Renders the drawing by the specified render context. + /// + /// The render context. + public void Render(IRenderContext rc) + { + try + { + foreach (var e in this.drawing.Elements) + { + DrawingElement.Presenter vm; + if (!this.elementMap.TryGetValue(e, out vm)) + { + vm = ((IDrawingElement)e).CreatePresentationModel(this); + this.elementMap[e] = vm; + } + + vm.Render(rc); + + // this.RenderBounds(rc, vm); + } + } + catch (Exception e) + { + rc.DrawText(new ScreenPoint(10, 10), e.Message, OxyColors.Red); + } + finally + { + rc.CleanUp(); + } + } + + /// + /// Renders the bounding box for the specified element. + /// + /// The render context. + /// The element presentation model. + public void RenderBounds(IRenderContext rc, DrawingElement.Presenter vm) + { + var bounds = vm.GetBounds(rc); + var p0 = this.Transform(bounds.MinimumX, bounds.MinimumY); + var p1 = this.Transform(bounds.MaximumX, bounds.MaximumY); + var rect = new OxyRect(p0, p1); + rc.DrawRectangle(rect, OxyColors.Undefined, OxyColors.Blue); + } + + /// + /// Handles the changed drawing. + /// + /// The sender. + /// The instance containing the event data. + private void HandleChangedDrawing(object sender, ChangedEventArgs e) + { + this.Invalidate(); + } + } +} \ No newline at end of file diff --git a/Source/OxyPlot/Drawing/DrawingView/IDrawingView.cs b/Source/OxyPlot/Drawing/DrawingView/IDrawingView.cs new file mode 100644 index 000000000..1752f1bfa --- /dev/null +++ b/Source/OxyPlot/Drawing/DrawingView/IDrawingView.cs @@ -0,0 +1,49 @@ +// -------------------------------------------------------------------------------------------------------------------- +// +// Copyright (c) 2014 OxyPlot contributors +// +// +// Defines a view that can display a DrawingModel. +// +// -------------------------------------------------------------------------------------------------------------------- + +namespace OxyPlot.Drawing +{ + /// + /// Defines a view that can display a . + /// + public interface IDrawingView : IView + { + /// + /// Gets the drawing padding. + /// + /// + /// The padding. + /// + double DrawingPadding { get; } + + /// + /// Gets the actual presentation model. + /// + /// + /// The actual presentation model. + /// + DrawingViewModel ActualViewModel { get; } + + /// + /// Zooms the extents. + /// + void ZoomExtents(); + + /// + /// Invalidates this instance. + /// + void Invalidate(); + + /// + /// Gets the bounding box. + /// + /// The bounding box. + BoundingBox GetBounds(); + } +} \ No newline at end of file diff --git a/Source/OxyPlot/Drawing/DrawingView/IDrawingViewModel.cs b/Source/OxyPlot/Drawing/DrawingView/IDrawingViewModel.cs new file mode 100644 index 000000000..5c90ec1e8 --- /dev/null +++ b/Source/OxyPlot/Drawing/DrawingView/IDrawingViewModel.cs @@ -0,0 +1,102 @@ +// -------------------------------------------------------------------------------------------------------------------- +// +// Copyright (c) 2014 OxyPlot contributors +// +// +// Specifies a presentation model for the drawing view. +// +// -------------------------------------------------------------------------------------------------------------------- + +namespace OxyPlot.Drawing +{ + using System.Collections.Generic; + + /// + /// Specifies a presentation model for the drawing view. + /// + public interface IDrawingViewModel : IViewModel + { + /// + /// Gets the coordinates of the client area of the view. + /// + /// + /// The client area rectangle. + /// + OxyRect ClientArea { get; } + + /// + /// Transforms the specified point. + /// + /// The point. + /// The transformed point. + ScreenPoint Transform(DataPoint p); + + /// + /// Transforms the specified point. + /// + /// The x. + /// The y. + /// The transformed point. + ScreenPoint Transform(double x, double y); + + /// + /// Transforms the specified length. + /// + /// The length. + /// The transformed length. + double Transform(double t); + + /// + /// Inverse-transforms the specified length. + /// + /// The length. + /// The transformed length. + double InverseTransform(double t); + + /// + /// Inverse-transforms the specified point. + /// + /// The point. + /// The transformed point. + DataPoint InverseTransform(ScreenPoint p); + + /// + /// Zooms to extents. + /// + /// The render context. + void ZoomExtents(IRenderContext rc); + + /// + /// Gets the bounding box. + /// + /// The render context. + /// The bounding box. + BoundingBox GetBounds(IRenderContext rc); + + /// + /// Updates the view. + /// + /// The render context. + void Update(IRenderContext rc); + + /// + /// Renders the view. + /// + /// The render context. + void Render(IRenderContext rc); + + /// + /// Invalidates the view. + /// + void Invalidate(); + + /// + /// Returns the elements that are hit at the specified position. + /// + /// The hit test arguments. + /// + /// A sequence of hit results. + /// + IEnumerable HitTest(HitTestArguments args); + } +} \ No newline at end of file diff --git a/Source/OxyPlot/Foundation/BoundingBox.cs b/Source/OxyPlot/Foundation/BoundingBox.cs new file mode 100644 index 000000000..f35072e92 --- /dev/null +++ b/Source/OxyPlot/Foundation/BoundingBox.cs @@ -0,0 +1,149 @@ +// -------------------------------------------------------------------------------------------------------------------- +// +// Copyright (c) 2014 OxyPlot contributors +// +// +// Represents a 2D bounding box. +// +// -------------------------------------------------------------------------------------------------------------------- + +namespace OxyPlot +{ + /// + /// Represents a 2D bounding box. + /// + public class BoundingBox + { + /// + /// Initializes a new instance of the class. + /// + public BoundingBox() + { + this.MinimumX = double.NaN; + } + + /// + /// Initializes a new instance of the class. + /// + /// The minimum x. + /// The minimum y. + /// The maximum x. + /// The maximum y. + public BoundingBox(double minimumX, double minimumY, double maximumX, double maximumY) + { + this.MinimumX = minimumX; + this.MinimumY = minimumY; + this.MaximumX = maximumX; + this.MaximumY = maximumY; + } + + /// + /// Gets or sets the minimum x coordinate. + /// + /// + /// The minimum x. + /// + public double MinimumX { get; set; } + + /// + /// Gets or sets the maximum x coordinate. + /// + /// + /// The maximum x. + /// + public double MaximumX { get; set; } + + /// + /// Gets or sets the minimum y coordinate. + /// + /// + /// The minimum y. + /// + public double MinimumY { get; set; } + + /// + /// Gets or sets the maximum y coordinate. + /// + /// + /// The maximum y. + /// + public double MaximumY { get; set; } + + /// + /// Unions the specified bb. + /// + /// The bb. + public void Union(BoundingBox bb) + { + if (!bb.IsEmpty()) + { + this.Union(bb.MinimumX, bb.MinimumY); + this.Union(bb.MaximumX, bb.MaximumY); + } + } + + /// + /// Includes the specified point in the bounding box. + /// + /// The point. + public void Union(DataPoint p) + { + this.Union(p.X, p.Y); + } + + /// + /// Includes the specified point with a translation in the bounding box. + /// + /// The point. + /// The x translation. + /// The y translation. + public void Union(DataPoint p, double dx, double dy) + { + this.Union(p.X + dx, p.Y + dy); + } + + /// + /// Includes the specified point in the bounding box. + /// + /// The x coordinate. + /// The y coordinate. + public void Union(double x, double y) + { + if (this.IsEmpty()) + { + this.MinimumX = this.MaximumX = x; + this.MinimumY = this.MaximumY = y; + return; + } + + if (x < this.MinimumX) + { + this.MinimumX = x; + } + + if (x > this.MaximumX) + { + this.MaximumX = x; + } + + if (y < this.MinimumY) + { + this.MinimumY = y; + } + + if (y > this.MaximumY) + { + this.MaximumY = y; + } + } + + /// + /// Determines whether the bounding box is empty. + /// + /// true if the bounding box is empty. + public bool IsEmpty() + { + return double.IsNaN(this.MinimumX); + } + } +} \ No newline at end of file diff --git a/Source/OxyPlot/Foundation/DataPoint.cs b/Source/OxyPlot/Foundation/DataPoint.cs index 3f53d419a..c33c45b0a 100644 --- a/Source/OxyPlot/Foundation/DataPoint.cs +++ b/Source/OxyPlot/Foundation/DataPoint.cs @@ -115,5 +115,17 @@ public bool IsDefined() // ReSharper restore EqualExpressionComparison #pragma warning restore 1718 } + + /// + /// Calculates the distance to the specified point. + /// + /// The other point. + /// The distance. + public double DistanceTo(DataPoint other) + { + double dx = other.X - this.x; + double dy = other.Y - this.y; + return Math.Sqrt((dx * dx) + (dy * dy)); + } } } \ No newline at end of file diff --git a/Source/OxyPlot/Graphics/ControllerBase.cs b/Source/OxyPlot/Graphics/ControllerBase.cs index e03d220d3..ffd1f4ac0 100644 --- a/Source/OxyPlot/Graphics/ControllerBase.cs +++ b/Source/OxyPlot/Graphics/ControllerBase.cs @@ -54,6 +54,11 @@ protected ControllerBase() /// protected IList> TouchManipulators { get; private set; } + /// + /// Gets or sets the current mouse event element + /// + protected UIElement CurrentMouseEventElement { get; set; } + /// /// Handles the specified gesture. /// @@ -68,79 +73,104 @@ public virtual bool HandleGesture(IView view, OxyInputGesture gesture, OxyInputE } /// - /// Handles mouse down events. + /// Handles mouse enter events. /// /// The plot view. /// The instance containing the event data. /// true if the event was handled. - public virtual bool HandleMouseDown(IView view, OxyMouseDownEventArgs args) + public virtual bool HandleMouseEnter(IView view, OxyMouseEventArgs args) { lock (this.GetSyncRoot(view)) { if (view.ActualModel != null) { - view.ActualModel.HandleMouseDown(this, args); + view.ActualModel.HandleMouseEnter(this, args); if (args.Handled) { return true; } } - var command = this.GetCommand(new OxyMouseDownGesture(args.ChangedButton, args.ModifierKeys, args.ClickCount)); + var command = this.GetCommand(new OxyMouseEnterGesture(args.ModifierKeys)); return this.HandleCommand(command, view, args); } } /// - /// Handles mouse enter events. + /// Handles mouse leave events. /// /// The plot view. /// The instance containing the event data. /// true if the event was handled. - public virtual bool HandleMouseEnter(IView view, OxyMouseEventArgs args) + public virtual bool HandleMouseLeave(IView view, OxyMouseEventArgs args) { lock (this.GetSyncRoot(view)) { if (view.ActualModel != null) { - view.ActualModel.HandleMouseEnter(this, args); + view.ActualModel.HandleMouseLeave(this, args); if (args.Handled) { return true; } } - var command = this.GetCommand(new OxyMouseEnterGesture(args.ModifierKeys)); - return this.HandleCommand(command, view, args); + foreach (var m in this.MouseHoverManipulators.ToArray()) + { + m.Completed(args); + this.MouseHoverManipulators.Remove(m); + } + + return true; } } /// - /// Handles mouse leave events. + /// Returns the elements that are hit at the specified position. + /// + /// The view. + /// The hit test arguments. + /// + /// A sequence of hit results. + /// + public virtual IEnumerable HitTest(IView view, HitTestArguments args) + { + yield break; + } + + /// + /// Handles mouse down events. /// /// The plot view. /// The instance containing the event data. /// true if the event was handled. - public virtual bool HandleMouseLeave(IView view, OxyMouseEventArgs args) + public virtual bool HandleMouseDown(IView view, OxyMouseDownEventArgs args) { lock (this.GetSyncRoot(view)) { - if (view.ActualModel != null) + var hitargs = new HitTestArguments(args.Position, 10); + foreach (var result in this.HitTest(view, hitargs)) { - view.ActualModel.HandleMouseLeave(this, args); + args.HitTestResult = result; + result.Element.OnMouseDown(args); if (args.Handled) { + this.CurrentMouseEventElement = result.Element; return true; } } - foreach (var m in this.MouseHoverManipulators.ToArray()) + if (view.ActualModel != null) { - m.Completed(args); - this.MouseHoverManipulators.Remove(m); + view.ActualModel.HandleMouseDown(this, args); + if (args.Handled) + { + return true; + } } - return args.Handled; + var command = this.GetCommand(new OxyMouseDownGesture(args.ChangedButton, args.ModifierKeys, args.ClickCount)); + return this.HandleCommand(command, view, args); } } @@ -154,6 +184,15 @@ public virtual bool HandleMouseMove(IView view, OxyMouseEventArgs args) { lock (this.GetSyncRoot(view)) { + if (this.CurrentMouseEventElement != null) + { + this.CurrentMouseEventElement.OnMouseMove(args); + if (args.Handled) + { + return true; + } + } + if (view.ActualModel != null) { view.ActualModel.HandleMouseMove(this, args); @@ -173,7 +212,7 @@ public virtual bool HandleMouseMove(IView view, OxyMouseEventArgs args) m.Delta(args); } - return args.Handled; + return true; } } @@ -187,6 +226,16 @@ public virtual bool HandleMouseUp(IView view, OxyMouseEventArgs args) { lock (this.GetSyncRoot(view)) { + if (this.CurrentMouseEventElement != null) + { + this.CurrentMouseEventElement.OnMouseUp(args); + this.CurrentMouseEventElement = null; + if (args.Handled) + { + return true; + } + } + if (view.ActualModel != null) { view.ActualModel.HandleMouseUp(this, args); @@ -202,7 +251,7 @@ public virtual bool HandleMouseUp(IView view, OxyMouseEventArgs args) this.MouseDownManipulators.Remove(m); } - return args.Handled; + return true; } } @@ -269,7 +318,7 @@ public virtual bool HandleTouchDelta(IView view, OxyTouchEventArgs args) m.Delta(args); } - return args.Handled; + return true; } } @@ -298,7 +347,7 @@ public virtual bool HandleTouchCompleted(IView view, OxyTouchEventArgs args) this.TouchManipulators.Remove(m); } - return args.Handled; + return true; } } @@ -508,7 +557,9 @@ protected virtual bool HandleCommand(IViewCommand command, IView view, OxyInputE } command.Execute(view, this, args); - return args.Handled; + + args.Handled = true; + return true; } /// diff --git a/Source/OxyPlot/Graphics/IViewModel.cs b/Source/OxyPlot/Graphics/IViewModel.cs new file mode 100644 index 000000000..78a3cc262 --- /dev/null +++ b/Source/OxyPlot/Graphics/IViewModel.cs @@ -0,0 +1,54 @@ +// -------------------------------------------------------------------------------------------------------------------- +// +// Copyright (c) 2014 OxyPlot contributors +// +// +// Specifies functionality for the view models. +// +// -------------------------------------------------------------------------------------------------------------------- + +namespace OxyPlot +{ + /// + /// Specifies functionality for the view models. + /// + public interface IViewModel + { + /// + /// Pans the view by the specified vector. + /// + /// The panning vector. + void Pan(ScreenVector delta); + + /// + /// Pans the view by the specified vector. + /// + /// The delta. + /// The position. + void Pan(ScreenVector delta, ScreenPoint point); + + /// + /// Zooms the view by the specified scale. + /// + /// The delta scale. + void Zoom(double deltaScale); + + /// + /// Zooms to the specified rectangle. + /// + /// The zoom rectangle. + void Zoom(OxyRect zoomRectangle); + + /// + /// Zooms at the specified point. + /// + /// The zoom factor. + /// The current. + void ZoomAt(ScreenVector deltaScale, ScreenPoint current); + + /// + /// Resets the view. + /// + void Reset(); + } +} \ No newline at end of file diff --git a/Source/OxyPlot/Graphics/Model.MouseEvents.cs b/Source/OxyPlot/Graphics/Model.MouseEvents.cs index d1062f494..c9509cd85 100644 --- a/Source/OxyPlot/Graphics/Model.MouseEvents.cs +++ b/Source/OxyPlot/Graphics/Model.MouseEvents.cs @@ -232,7 +232,7 @@ public virtual void HandleTouchCompleted(object sender, OxyTouchEventArgs e) /// The instance containing the event data. public virtual void HandleKeyDown(object sender, OxyKeyEventArgs e) { - foreach (var element in this.GetHitTestElements()) + foreach (var element in this.GetElements()) { element.OnKeyDown(e); @@ -374,4 +374,4 @@ protected virtual void OnTouchCompleted(object sender, OxyTouchEventArgs e) } } } -} \ No newline at end of file +} diff --git a/Source/OxyPlot/Graphics/Model.cs b/Source/OxyPlot/Graphics/Model.cs index 09f573213..31a112c05 100644 --- a/Source/OxyPlot/Graphics/Model.cs +++ b/Source/OxyPlot/Graphics/Model.cs @@ -1,4 +1,4 @@ -// -------------------------------------------------------------------------------------------------------------------- +// -------------------------------------------------------------------------------------------------------------------- // // Copyright (c) 2014 OxyPlot contributors // @@ -10,6 +10,7 @@ namespace OxyPlot { using System.Collections.Generic; + using System.Linq; /// /// Provides an abstract base class for graphics models. @@ -59,9 +60,8 @@ public object SyncRoot /// public IEnumerable HitTest(HitTestArguments args) { - var hitTestElements = this.GetHitTestElements(); - - foreach (var element in hitTestElements) + // Revert the order to handle the top-level elements first + foreach (var element in this.GetElements().Reverse()) { var result = element.HitTest(args); if (result != null) @@ -75,6 +75,6 @@ public IEnumerable HitTest(HitTestArguments args) /// Gets all elements of the model, top-level elements first. /// /// An enumerator of the elements. - protected abstract IEnumerable GetHitTestElements(); + public abstract IEnumerable GetElements(); } -} \ No newline at end of file +} diff --git a/Source/OxyPlot/Graphics/UIElement.cs b/Source/OxyPlot/Graphics/UIElement.cs index ef1ae35b5..d726aba8a 100644 --- a/Source/OxyPlot/Graphics/UIElement.cs +++ b/Source/OxyPlot/Graphics/UIElement.cs @@ -53,7 +53,7 @@ public abstract class UIElement : SelectableElement public event EventHandler TouchCompleted; /// - /// Tests if the plot element is hit by the specified point. + /// Tests if the element is hit by the specified point. /// /// The hit test arguments. /// diff --git a/Source/OxyPlot/PlotController/EventArgs/OxyMouseEventArgs.cs b/Source/OxyPlot/PlotController/EventArgs/OxyMouseEventArgs.cs index 81f555964..d4fede7da 100644 --- a/Source/OxyPlot/PlotController/EventArgs/OxyMouseEventArgs.cs +++ b/Source/OxyPlot/PlotController/EventArgs/OxyMouseEventArgs.cs @@ -18,5 +18,10 @@ public class OxyMouseEventArgs : OxyInputEventArgs /// Gets or sets the position of the mouse cursor. /// public ScreenPoint Position { get; set; } + + /// + /// Gets or sets the view where the event occurred. + /// + public IView View { get; set; } } } \ No newline at end of file diff --git a/Source/OxyPlot/PlotModel/PlotModel.Rendering.cs b/Source/OxyPlot/PlotModel/PlotModel.Rendering.cs index 818a5ed79..9d1ad8f55 100644 --- a/Source/OxyPlot/PlotModel/PlotModel.Rendering.cs +++ b/Source/OxyPlot/PlotModel/PlotModel.Rendering.cs @@ -558,4 +558,4 @@ private void UpdatePlotArea(IRenderContext rc) this.LegendArea = this.GetLegendRectangle(legendSize); } } -} \ No newline at end of file +} diff --git a/Source/OxyPlot/PlotModel/PlotModel.cs b/Source/OxyPlot/PlotModel/PlotModel.cs index 774e634df..0f50627ea 100644 --- a/Source/OxyPlot/PlotModel/PlotModel.cs +++ b/Source/OxyPlot/PlotModel/PlotModel.cs @@ -1200,7 +1200,7 @@ protected internal virtual void OnTrackerChanged(TrackerHitResult result) /// /// An enumerator of the elements. /// - protected override IEnumerable GetHitTestElements() + public override IEnumerable GetElements() { foreach (var axis in this.Axes.Reverse().Where(a => a.IsAxisVisible && a.Layer == AxisLayer.AboveSeries)) { diff --git a/Source/OxyPlot/Rendering/OxyColor.cs b/Source/OxyPlot/Rendering/OxyColor.cs index 13fe07122..15f16b783 100644 --- a/Source/OxyPlot/Rendering/OxyColor.cs +++ b/Source/OxyPlot/Rendering/OxyColor.cs @@ -108,10 +108,21 @@ public byte R /// Invalid format. public static OxyColor Parse(string value) { + if (value == null || value == "none") + { + return OxyColors.Undefined; + } + value = value.Trim(); if (value.StartsWith("#")) { value = value.Trim('#'); + if (value.Length == 3) + { + // replicate digits + value = string.Format("{0}{0}{1}{1}{2}{2}", value[0], value[1], value[2]); + } + var u = uint.Parse(value, NumberStyles.HexNumber, CultureInfo.InvariantCulture); if (value.Length < 8) { diff --git a/Source/Settings.StyleCop b/Source/Settings.StyleCop new file mode 100644 index 000000000..a6be94c18 --- /dev/null +++ b/Source/Settings.StyleCop @@ -0,0 +1,66 @@ + + + + Ansi + Bézier + bindable + Conrec + Cornsilk + CRC + Gainsboro + github + GTK + Haversine + Matlab + Migra + MigraDoc + Minase + Nayuki + Oxy + Paeth + paginator + pdf + PdfSharp + Petzold + pieslice + pieslice-shaped + png + pt + pubid + rectangularily + RGB + SilverPdf + subpath + Sutherland-Hodgman + svg + sysid + th + underfilled + veeness + wpf + Xamarin + xaml + xps + XY + + + + + + False + + TemporaryGeneratedFile_.*\.cs$ + XamlTypeInfo\.g\.cs$ + + + + + + + + OxyPlot + Copyright (c) 2014 OxyPlot contributors + + + + \ No newline at end of file