/// <summary> /// Generates Balls, BoatMarkers, Gates once Course Entry & Exit coordinates are available. /// </summary> private static void GenerateCourseFeatures() { // Pre Gates (55m) PreGates[0] = new CoursePosition(-1.25, 0); PreGates[1] = new CoursePosition(1.25, 0); PreGates[2] = new CoursePosition(-1.25, LengthM); PreGates[3] = new CoursePosition(1.25, LengthM); // Entry Gates Gates[0] = new CoursePosition(-1.25, 55); Gates[1] = new CoursePosition(1.25, 55); // Exit Gates Gates[2] = new CoursePosition(-1.25, LengthM - 55); Gates[3] = new CoursePosition(1.25, LengthM - 55); Balls[0] = new CoursePosition(-11.5, 27 + 55); // Ball 1 for (int i = 1; i < 6; i++) { // Alternate X position (-11.5, 11.5) Balls[i] = new CoursePosition(Balls[i - 1].X * -1d, Balls[i - 1].Y + 41); } for (int i = 0; i < Balls.Length; i++) { BoatMarkers[i * 2] = new CoursePosition(-1.15, Balls[i].Y); BoatMarkers[i * 2 + 1] = new CoursePosition(1.15, Balls[i].Y); } }
/// <summary> /// Converts relative course position X,Y coordiantes to a point on the drawable screen. /// Screen size is always positive, for example (0,0) upper left (46,738) lower right at a ScaleFactor of 2.0. /// </summary> /// <param name="position"></param> /// <returns></returns> private PointF PointFromCoursePosition(CoursePosition position) { // CenterOffset is used to create a positive X coordinate from CoursePosition which is relative to // pre-gate where center line is x=0,y=0. float x = ScaleFactor * ((float)position.X + CenterOffset); float y = (ScaleFactor * (float)position.Y) + TopBottomMargin; return(new PointF(x, y)); }
/// /// <summary> Get handle position in x,y coordinates from the pilon. </summary> /// private CoursePosition CalculateRopeHandlePosition(Measurement current) { CoursePosition virtualHandlePos = m_rope.GetHandlePosition(current.RopeAngleDegrees); // Actual handle position is calculated relative to the pilon/boat position, behind the boat. double y = current.BoatPosition.Y - virtualHandlePos.Y; double x = current.BoatPosition.X - virtualHandlePos.X; return new CoursePosition(x, y); }
public void CoursePositionFromGeoTest() { // Grab a boatposition and verify where in the X,Y course plane it should fit. // 7.45, 42.289983, -71.358973, 13.68, 0.11289 <-- before the course // 21.63, 42.288066, -71.359257, 14.87, 0.50935 <-- just prior to ball 1, after gate crossing // 40.71, 42.285529, -71.359519, 14.27, 0.59728 <-- between exit gates and the 55's // 45.32, 42.285165, -71.359369, 5.60, -0.10074 <-- way past the course, looping around // 15.02, 42.288937, -71.359136, 14.33, 0.77112 <-- boat is passing through the 55s. //42.2867806,"Longitude":-71.3594418 == Chet @ 15 seconds into the GOPR0565.mp4 // .\slalom\SlalomTracker\Video\MetadataExtractor\GOPR0565.json CoursePassFactory factory = new CoursePassFactory(); CoursePass pass = factory.FromFile("./Video/GOPR0565.json"); CoursePosition position = pass.CoursePositionFromGeo(42.2867806, -71.3594418); Assert.IsTrue((int)position.X == 0, "Incorrect course X position."); Assert.IsTrue((int)position.Y == 61, "Incorrect course Y position."); }
private void DrawCourseBounds(List <GeoCoordinate> list, Color color) { // Convert geos to relative course positions, then to absolute screen points. List <PointF> points = new List <PointF>(list.Count); for (int i = 0; i < list.Count; i++) { CoursePosition position = _pass.CoursePositionFromGeo(list[i]); points.Add(PointFromCoursePosition(position)); } Pen pen = new Pen(color, 0.6F); pen.DashStyle = System.Drawing.Drawing2D.DashStyle.Dot; _graphics.DrawLine(pen, points[0], points[1]); _graphics.DrawLine(pen, points[1], points[2]); _graphics.DrawLine(pen, points[2], points[3]); _graphics.DrawLine(pen, points[3], points[0]); }
void DrawHandleSpeed(Measurement m, int measurementIndex) { const double SpeedGraphHeight = 10.0d; double speedHeight = (Math.Abs(m.RopeSwingSpeedRadS) / maxHandleSpeed) * SpeedGraphHeight; bool accelerating = false; // if (speedHeight == SpeedGraphHeight) // { // string maxSpeed = Math.Round(m.HandleSpeedMps * 2.23694, 1) + "mph"; // parent.DrawTextNearMeasurement(m, maxSpeed); // } if (measurementIndex > 0) { double prevSpeed = parent._pass.Measurements[measurementIndex - 1].RopeSwingSpeedRadS; accelerating = Math.Abs(m.RopeSwingSpeedRadS) >= Math.Abs(prevSpeed); } // Course.WidthM CoursePosition startPosition = new CoursePosition(Course.WidthM, m.HandlePosition.Y); CoursePosition endPosition = new CoursePosition(Course.WidthM - speedHeight, m.HandlePosition.Y); PointF startPoint = parent.PointFromCoursePosition(startPosition); PointF endPoint = parent.PointFromCoursePosition(endPosition); Color color = GetAcceleratingColor(accelerating); Pen pen = new Pen(color, 5.0f); parent._graphics.DrawLine(pen, startPoint, endPoint); // // Get the root mean square of the last 10 measurements. // double averageSpeed = parent._pass.Measurements.GetRange(measurementIndex-10, 10) // .Select(s => s.HandleSpeedMps) // .RootMeanSquare() * 2.23694; // string speed = Math.Round(averageSpeed, 1) + "mph"; // parent.DrawTextNearMeasurement(m, speed); }