private void ImportOtherDrawingsData(Metadata metadata) { LinearKinematics linearKinematics = new LinearKinematics(); // Trackable drawing's individual points. foreach (ITrackable trackable in metadata.TrackableDrawings()) { Dictionary <string, TrackablePoint> trackablePoints = metadata.TrackabilityManager.GetTrackablePoints(trackable); if (trackablePoints == null) { continue; } foreach (var pair in trackablePoints) { TrackablePoint tp = pair.Value; Timeline <TrackFrame> timeline = pair.Value.Timeline; if (timeline.Count == 0) { continue; } List <TimedPoint> samples = timeline.Enumerate().Select(p => new TimedPoint(p.Location.X, p.Location.Y, p.Time)).ToList(); FilteredTrajectory traj = new FilteredTrajectory(); traj.Initialize(samples, metadata.CalibrationHelper); TimeSeriesCollection tsc = linearKinematics.BuildKinematics(traj, metadata.CalibrationHelper); string name = trackable.Name; Color color = trackable.Color; // Custom drawings may have dedicated names for their handles. DrawingGenericPosture dgp = trackable as DrawingGenericPosture; if (dgp == null) { name = name + " - " + pair.Key; } else { foreach (var handle in dgp.GenericPostureHandles) { if (handle.Reference.ToString() != pair.Key) { continue; } name = name + " - " + (string.IsNullOrEmpty(handle.Name) ? pair.Key : handle.Name); color = handle.Color == Color.Transparent ? trackable.Color : handle.Color; break; } } TimeSeriesPlotData data = new TimeSeriesPlotData(name, color, tsc); timeSeriesData.Add(data); filteredTrajectories.Add(data, traj); } } }
public TimeSeriesCollection BuildKinematics(FilteredTrajectory traj, CalibrationHelper calibrationHelper) { TimeSeriesCollection tsc = new TimeSeriesCollection(traj.Length); if (traj.Length == 0) { return(tsc); } tsc.AddTimes(traj.Times); tsc.AddComponent(Kinematics.XRaw, traj.RawXs); tsc.AddComponent(Kinematics.YRaw, traj.RawYs); tsc.AddComponent(Kinematics.X, traj.Xs); tsc.AddComponent(Kinematics.Y, traj.Ys); Func <int, PointF> getCoord; if (traj.CanFilter) { getCoord = traj.Coordinates; } else { getCoord = traj.RawCoordinates; } tsc.InitializeKinematicComponents(new List <Kinematics>() { Kinematics.LinearDistance, Kinematics.LinearHorizontalDisplacement, Kinematics.LinearVerticalDisplacement, Kinematics.LinearSpeed, Kinematics.LinearHorizontalVelocity, Kinematics.LinearVerticalVelocity, Kinematics.LinearAcceleration, Kinematics.LinearHorizontalAcceleration, Kinematics.LinearVerticalAcceleration, }); ComputeDistances(tsc, calibrationHelper, getCoord); ComputeVelocities(tsc, calibrationHelper, getCoord); ComputeAccelerations(tsc, calibrationHelper, getCoord); return(tsc); }
public static Circle Fit(FilteredTrajectory traj) { if (traj.Length < 3) { return(Circle.Empty); } // Least-squares circle fitting. // Ref: "Circle fitting by linear and nonlinear least squares", Coope, I.D., // Journal of Optimization Theory and Applications Volume 76, Issue 2, New York: Plenum Press, February 1993. // Implementation based on JS implementation: // http://jsxgraph.uni-bayreuth.de/wiki/index.php/Least-squares_circle_fitting int rows = traj.Length; Matrix <double> m = Matrix <double> .Build.Dense(rows, 3); Matrix <double> v = Matrix <double> .Build.Dense(rows, 1); for (int i = 0; i < rows; i++) { PointF point = traj.Coordinates(i); m[i, 0] = point.X; m[i, 1] = point.Y; m[i, 2] = 1.0; v[i, 0] = point.X * point.X + point.Y * point.Y; } try { Matrix <double> mt = m.Clone().Transpose(); Matrix <double> b = mt.Multiply(m); Matrix <double> c = mt.Multiply(v); Matrix <double> z = b.Solve(c); PointF center = new PointF((float)(z[0, 0] * 0.5), (float)(z[1, 0] * 0.5)); double radius = Math.Sqrt(z[2, 0] + (center.X * center.X) + (center.Y * center.Y)); return(new Circle(center, (float)radius)); } catch (InvalidOperationException) { return(Circle.Empty); } }
private static void ImportAngleDrawingsData(Metadata metadata, List <TimeSeriesPlotData> timeSeriesData) { // Create three filtered trajectories named o, a, b directly based on the trackable points. foreach (DrawingAngle drawingAngle in metadata.Angles()) { Dictionary <string, FilteredTrajectory> trajs = new Dictionary <string, FilteredTrajectory>(); Dictionary <string, TrackablePoint> trackablePoints = metadata.TrackabilityManager.GetTrackablePoints(drawingAngle); bool tracked = true; foreach (string key in trackablePoints.Keys) { Timeline <TrackFrame> timeline = trackablePoints[key].Timeline; if (timeline.Count == 0) { tracked = false; break; } List <TimedPoint> samples = timeline.Enumerate().Select(p => new TimedPoint(p.Location.X, p.Location.Y, p.Time)).ToList(); FilteredTrajectory traj = new FilteredTrajectory(); traj.Initialize(samples, metadata.CalibrationHelper); trajs.Add(key, traj); } if (!tracked) { continue; } TimeSeriesCollection tsc = angularKinematics.BuildKinematics(trajs, drawingAngle.AngleOptions, metadata.CalibrationHelper); TimeSeriesPlotData data = new TimeSeriesPlotData(drawingAngle.Name, drawingAngle.Color, tsc); timeSeriesData.Add(data); } }
private PlotModel CreateCutoffPlot(IEnumerable <TimeSeriesPlotData> timeSeriesPlotData) { if (timeSeriesPlotData == null) { return(null); } PlotModel model = new PlotModel(); model.TitleFontSize = 12; model.Title = "Residuals autocorrelation"; LinearAxis xAxis = new LinearAxis(); xAxis.Position = AxisPosition.Bottom; xAxis.MajorGridlineStyle = LineStyle.Solid; xAxis.MinorGridlineStyle = LineStyle.Dot; xAxis.Title = "Cutoff frequency (Hz)"; xAxis.TitleFontSize = 10; model.Axes.Add(xAxis); LinearAxis yAxis = new LinearAxis(); yAxis.Position = AxisPosition.Left; yAxis.MajorGridlineStyle = LineStyle.Solid; yAxis.MinorGridlineStyle = LineStyle.Dot; yAxis.Title = "Autocorrelation (normalized)"; yAxis.TitleFontSize = 10; yAxis.Maximum = 1.0f; model.Axes.Add(yAxis); lvCutoffFrequencies.Items.Clear(); foreach (TimeSeriesPlotData tspd in timeSeriesPlotData) { if (!filteredTrajectories.ContainsKey(tspd) || !filteredTrajectories[tspd].CanFilter) { continue; } // X=red and Y=green matches the typical mapping used in 3D apps. LineSeries xseries = new LineSeries(); xseries.Color = OxyColors.Tomato; xseries.MarkerType = MarkerType.None; xseries.Smooth = true; LineSeries yseries = new LineSeries(); yseries.Color = OxyColors.Green; yseries.MarkerType = MarkerType.None; yseries.Smooth = true; FilteredTrajectory ft = filteredTrajectories[tspd]; foreach (FilteringResult r in ft.FilterResultXs) { xseries.Points.Add(new DataPoint(r.CutoffFrequency, r.DurbinWatson)); } foreach (FilteringResult r in ft.FilterResultYs) { yseries.Points.Add(new DataPoint(r.CutoffFrequency, r.DurbinWatson)); } model.Series.Add(xseries); model.Series.Add(yseries); // Filtering tab. if (ft.XCutoffIndex >= 0 && ft.YCutoffIndex >= 0) { double xcutoff = ft.FilterResultXs[ft.XCutoffIndex].CutoffFrequency; double ycutoff = ft.FilterResultXs[ft.YCutoffIndex].CutoffFrequency; string strXCutoff = string.Format("{0:0.000}", xcutoff); string strYCutoff = string.Format("{0:0.000}", ycutoff); lvCutoffFrequencies.Items.Add(new ListViewItem(new string[] { tspd.Label, strXCutoff, strYCutoff })); } } return(model); }
private static void ImportCustomDrawingsData(Metadata metadata, List <TimeSeriesPlotData> timeSeriesData) { // Collect angular trajectories for all the angles in all the custom tools. foreach (DrawingGenericPosture drawing in metadata.GenericPostures()) { Dictionary <string, TrackablePoint> trackablePoints = metadata.TrackabilityManager.GetTrackablePoints(drawing); // First create trajectories for all the trackable points in the drawing. // This avoids duplicating the filtering operation for points shared by more than one angle. // Here the trajectories are indexed by the original alias in the custom tool, based on the index. Dictionary <string, FilteredTrajectory> trajs = new Dictionary <string, FilteredTrajectory>(); bool tracked = true; foreach (string key in trackablePoints.Keys) { Timeline <TrackFrame> timeline = trackablePoints[key].Timeline; if (timeline.Count == 0) { // The point is trackable but doesn't have any timeline data. // This happens if the user is not tracking that drawing, so we don't need to go further. tracked = false; break; } List <TimedPoint> samples = timeline.Enumerate().Select(p => new TimedPoint(p.Location.X, p.Location.Y, p.Time)).ToList(); FilteredTrajectory traj = new FilteredTrajectory(); traj.Initialize(samples, metadata.CalibrationHelper); trajs.Add(key, traj); } if (!tracked) { continue; } // Loop over all angles in this drawing and find the trackable aliases of the points making up the particular angle. // The final collection of trajectories for each angle should have indices named o, a, b. foreach (GenericPostureAngle gpa in drawing.GenericPostureAngles) { // From integer indices to tracking aliases. string keyO = gpa.Origin.ToString(); string keyA = gpa.Leg1.ToString(); string keyB = gpa.Leg2.ToString(); // All points in an angle must be trackable as there is currently no way to get the static point coordinate. if (!trajs.ContainsKey(keyO) || !trajs.ContainsKey(keyA) || !trajs.ContainsKey(keyB)) { continue; } // Remap to oab. Dictionary <string, FilteredTrajectory> angleTrajs = new Dictionary <string, FilteredTrajectory>(); angleTrajs.Add("o", trajs[keyO]); angleTrajs.Add("a", trajs[keyA]); angleTrajs.Add("b", trajs[keyB]); AngleOptions options = new AngleOptions(gpa.Signed, gpa.CCW, gpa.Supplementary); TimeSeriesCollection tsc = angularKinematics.BuildKinematics(angleTrajs, options, metadata.CalibrationHelper); string name = drawing.Name; if (!string.IsNullOrEmpty(gpa.Name)) { name = name + " - " + gpa.Name; } Color color = gpa.Color == Color.Transparent ? drawing.Color : gpa.Color; TimeSeriesPlotData data = new TimeSeriesPlotData(name, color, tsc); timeSeriesData.Add(data); } } }