private async static Task <int> Tides(Predictions predictions) { var querycount = 0; predictions.OnQuery += () => { querycount++; }; // this should cause a query var tides = await predictions.CurrentTides(); foreach (var tide in tides) { Console.WriteLine($"{tide.Date} {tide.Value}"); } if (tides.Count == 0 || querycount != 1) { throw new Exception("Invalid query"); } // this round should not cause a query tides = await predictions.CurrentTides(); if (tides.Count == 0 || querycount != 1) { throw new Exception("Invalid query"); } Console.WriteLine(); var extremes = await predictions.CurrentExtremes(); foreach (var e in extremes) { Console.WriteLine($"{e.Date} {e.Value} {e.Type}"); } if (extremes.Count == 0 || querycount != 2) { throw new Exception($"Invalid query : {extremes.Count} {querycount}"); } // this round should not cause a query extremes = await predictions.CurrentExtremes(); if (extremes.Count == 0 || querycount != 2) { throw new Exception("Invalid query"); } return(0); }
private async void FrameUpdate(object state) { if (Canvas == null) { throw new Exception("must have a valid canvas to draw too"); } // the timer is reentrant, so only allow one instance to run if (System.Threading.Interlocked.CompareExchange(ref FrameLock, 1, 0) != 0) { return; } // grab predictions var tides = await Prediction.CurrentTides(); var suns = await Prediction.CurrentSuns(); // locations var dimension = Math.Min(Canvas.Width, Canvas.Height); var center = new Point((dimension / 2f), (dimension / 2f), z: 0f); var points = new Point[2]; var fontsize = 18f * Ratio; var fontname = "Courier New"; // outer ring var ringthickness = (float)Math.Round(0.25f * Ratio, 1); if (ringthickness < 1f) { ringthickness = 1f; } var innerradius = dimension / 20f; var outerradius = (dimension * 0.37f) + innerradius + ringthickness; var tidelinethickness = (float)Math.Round(0.25f * Ratio, 1); if (tidelinethickness < 1f) { tidelinethickness = 1f; } // get time var now = DateTime.Now; var later = now.AddHours(24); // calculate the local min/max var min = Single.MaxValue; var max = Single.MinValue; foreach (var tide in tides) { if (tide.Date >= now && tide.Date < later) { min = Math.Min(min, tide.Value); max = Math.Max(max, tide.Value); } } // adjust so that the min/max do not rest on the line min -= (0.1f * Ratio); max += (0.1f * Ratio); // flip the sign of min to bring to 0 min *= -1; try { await Canvas.SuspendLayout(); // clear Canvas.Clear(RGBA.Black); // outer ring Canvas.Ellipse(RingColor, center, width: 2 * outerradius, height: 2 * outerradius, fill: false, border: false, ringthickness); // clock numbers for (int i = 1; i <= 24; i++) { var angle = i * (360f / 24f); // draw line CalculateLineByAngle(center.X, center.Y, angle, outerradius, out points[0].X, out points[0].Y, out points[1].X, out points[1].Y); Canvas.Polygon(RingColor, points, fill: false, border: false, ringthickness); // draw number CalculateLineByAngle(center.X, center.Y, angle, outerradius + (25f * Ratio), out points[0].X, out points[0].Y, out points[1].X, out points[1].Y); // adjust for the font size points[1].X -= (15f * Ratio); points[1].Y -= (8f * Ratio); Canvas.Text(RingColor, points[1], Clocknumber(i), fontsize, fontname); } // draw the tides as a sun burst var count = 0; foreach (var tide in tides) { if (tide.Date >= now && tide.Date < later) { if (LowResolution && count++ % 2 == 0) { continue; } // calculate angles CalculateAngleByClockface(tide.Date.Hour, tide.Date.Minute, tide.Date.Second, out float hour, out float minute, out float seccond); // calculate the magnitude of the line var distance = ((tide.Value + min) / (min + max)) * (outerradius - innerradius); // calculate the line CalculateLineByAngle(center.X, center.Y, hour, innerradius, out points[1].X, out points[1].Y, out points[0].X, out points[0].Y); CalculateLineByAngle(points[0].X, points[0].Y, hour, distance, out points[0].X, out points[0].Y, out points[1].X, out points[1].Y); // draw the line var angledelta = Math.Min(Math.Min(Math.Abs(Angle - hour), Math.Abs((Angle + 360) - hour)), Math.Abs(Angle - (hour + 360))); var color = RGBA.Black; if (tide.Date.Subtract(now).TotalMinutes < (LowResolution ? 12 : 6)) { color = CurrentTimeColor; } else if (angledelta < 10) { color = HighlightHghColor; } else if (angledelta < 20) { color = HighlightMidColor; } else if (angledelta < 30) { color = HighlightLowColor; } else { color = SpokeColor; } Canvas.Polygon(color, points, fill: false, border: false, tidelinethickness); } } // insert sunrise/sunset information foreach (var sun in suns) { if (sun.Date.Date == now.Date.Date) { // calculate angles CalculateAngleByClockface(sun.Date.Hour, sun.Date.Minute, sun.Date.Second, out float hour, out float minute, out float seccond); CalculateLineByAngle(center.X, center.Y, hour, outerradius, out points[1].X, out points[1].Y, out points[0].X, out points[0].Y); var diameter = (20f * Ratio); if (sun.Type.Equals("sunrise", StringComparison.OrdinalIgnoreCase)) { Canvas.Ellipse(RGBA.White, points[0], diameter, diameter, fill: true, border: false, thickness: 2f * Ratio); } else if (sun.Type.Equals("sunset", StringComparison.OrdinalIgnoreCase)) { Canvas.Ellipse(RGBA.White, points[0], diameter, diameter, fill: false, border: true, thickness: 2f * Ratio); } else { throw new Exception($"unknown sun type : {sun.Type}"); } } } } finally { await Canvas.ResumeLayout(); } // fire that the frame is done if (OnRendered != null) { OnRendered(); } // set state back to not running System.Threading.Volatile.Write(ref FrameLock, 0); // increase the angle Angle = (Angle + (LowResolution ? 2f : 0.25f)) % 360f; }