private async static Task <int> Suns(Predictions predictions) { var querycount = 0; predictions.OnQuery += () => { querycount++; }; // this should cause a query var suns = await predictions.CurrentSuns(); foreach (var s in suns) { Console.WriteLine($"{s.Date} {s.Type}"); } if (suns.Count == 0 || querycount <= 0) { throw new Exception("Invalid query"); } var previousquerycount = querycount; // this round should not cause a query suns = await predictions.CurrentSuns(); if (suns.Count == 0 || querycount != previousquerycount) { 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; }
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 extremes = await Prediction.CurrentExtremes(); var suns = await Prediction.CurrentSuns(); // gather the tide extreme data var extremedetails = new List <ExtremeDetails>(); ExtremeDetails current = null; foreach (var ex in extremes.OrderBy(e => e.Date)) { // check if the current is complete if (current != null && (current.Date.Date != ex.Date.Date || current.HighDate != default(DateTime))) { // add it extremedetails.Add(current); current = null; } // check if we need to create a new one if (current == null) { current = new ExtremeDetails() { Date = ex.Date.Date }; } // add the tide info if (ex.Type.Equals("h", StringComparison.OrdinalIgnoreCase)) { if (current.HighDate != default(DateTime)) { throw new Exception("Invalid high tide"); } current.HighDate = ex.Date; current.HighValue = ex.Value; } else if (ex.Type.Equals("l", StringComparison.OrdinalIgnoreCase)) { if (current.LowDate != default(DateTime)) { throw new Exception("Invalid low tide"); } current.LowDate = ex.Date; current.LowValue = ex.Value; } else { throw new Exception($"unknown extreme type {ex.Type}"); } } if (current != null) { extremedetails.Add(current); } var now = DateTime.Now; var rowheight = 24f * Ratio; var margin = 20f * Ratio; var headerfontsize = 20f * Ratio; var headerfontname = "Courier New"; // "Eras Light ITC"; var datafontsize = 18f * Ratio; var datafontname = "Courier New"; var point = new Point() { X = 0f, Y = 0f }; try { await Canvas.SuspendLayout(); // clear Canvas.Clear(RGBA.Black); Canvas.Text(RGBA.White, point, $"{now:MMM dd, yyyy} {Prediction.Location}", headerfontsize, headerfontname); // // tide extremes // point.Y = (rowheight * 1.5f); point.X = (datafontsize * 4f); Canvas.Text(RGBA.White, point, "low", datafontsize, datafontname); point.X = (datafontsize * 17f); Canvas.Text(RGBA.White, point, "high", datafontsize, datafontname); var prvdate = default(DateTime); foreach (var ex in extremedetails) { if (ex.Date.Date >= now.Date && point.Y < (Canvas.Height - (rowheight * 2))) { point.Y += rowheight; if (!prvdate.Date.Equals(ex.Date.Date)) { point.Y += (rowheight / 4f); point.X = 0f; Canvas.Text(RGBA.White, point, $"{ex.Date:ddd}", datafontsize, datafontname); } if (ex.LowDate != default(DateTime)) { point.X = (datafontsize * 4f); Canvas.Text(RGBA.White, point, $"{ex.LowDate:hh:mm tt} {(ex.LowValue > 0f ? " " : "")}{ex.LowValue:f2}", datafontsize, datafontname); } if (ex.HighDate != default(DateTime)) { point.X = (datafontsize * 16f); Canvas.Text(RGBA.White, point, $"{ex.HighDate:hh:mm tt} {(ex.HighValue < 10f ? " " : "")}{ex.HighValue:f2}", datafontsize, datafontname); } prvdate = ex.Date; } } } 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); }