public Point GetShift(float[] cursor_position) { if (cursor_position.Length != calibration_mode.additional_dimensions_configuration.CoordinatesCount) { return(new Point(0, 0)); } var closest_corrections = shift_storage.GetClosestCorrections(cursor_position); if (closest_corrections == null) { Debug.Assert(shift_storage.Corrections.Count() == 0 || !Helpers.AreCoordinatesSane(cursor_position)); return(new Point(0, 0)); } float sum_of_reverse_distances = 0; foreach (var index in closest_corrections) { sum_of_reverse_distances += (1 / index.distance); } ApplyShades(closest_corrections); foreach (var correction in closest_corrections) { correction.weight = correction.weight / correction.distance / sum_of_reverse_distances; } Helpers.NormalizeWeights(closest_corrections); var result = Helpers.GetWeightedAverage(closest_corrections); if (shift_storage.calibration_window != null) { var lables = new List <Tuple <string /*text*/, System.Windows.Point> >(); foreach (var correction in closest_corrections) { lables.Add(new Tuple <string, System.Windows.Point>((int)(correction.weight * 100) + "%", new System.Windows.Point( correction.correction.сoordinates[0], correction.correction.сoordinates[1]))); } shift_storage.calibration_window.UpdateCorrectionsLables(lables); shift_storage.calibration_window.UpdateCurrentCorrection(new EyeTrackerErrorCorrection(cursor_position, result)); } return(result); }
public Point GetShift(float[] cursor_position) { if (cursor_position.Length != calibration_mode.additional_dimensions_configuration.CoordinatesCount) { return(new Point(0, 0)); } // |GetClosestCorrections| is computationaly heavy. We call it once and create copies for V0 and V1 parts of this function. List <ShiftsStorage.PointInfo> closest_corrections_v0 = new List <ShiftsStorage.PointInfo>(calibration_mode.considered_zones_count); List <ShiftsStorage.PointInfo> closest_corrections_v1 = new List <ShiftsStorage.PointInfo>(calibration_mode.considered_zones_count_v1); { var closest_corrections = shift_storage.GetClosestCorrections(cursor_position); if (closest_corrections == null || closest_corrections.Count() == 0) { Debug.Assert(shift_storage.Corrections.Count() == 0 || !Helpers.AreCoordinatesSane(cursor_position)); return(new Point(0, 0)); } for (int i = 0; i < closest_corrections.Count; i++) { var correction = closest_corrections[i]; if (i < calibration_mode.considered_zones_count) { closest_corrections_v0.Add(new ShiftsStorage.PointInfo { correction = correction.correction, distance = correction.distance, weight = correction.weight, vector_from_correction_to_cursor = correction.vector_from_correction_to_cursor }); } if (i < calibration_mode.considered_zones_count_v1) { closest_corrections_v1.Add(new ShiftsStorage.PointInfo { correction = correction.correction, distance = correction.distance, weight = correction.weight, vector_from_correction_to_cursor = correction.vector_from_correction_to_cursor }); } } } // V0 part (average of closest error corrections weighted by distance): float sum_of_reverse_distances = 0; foreach (var index in closest_corrections_v0) { sum_of_reverse_distances += (1 / index.distance); } foreach (var correction in closest_corrections_v0) { correction.weight = 1 / correction.distance / sum_of_reverse_distances; } // V1 part (same as V0 plus shading) sum_of_reverse_distances = 0; foreach (var index in closest_corrections_v1) { sum_of_reverse_distances += (1 / index.distance); } ApplyShades(closest_corrections_v1); foreach (var correction in closest_corrections_v1) { correction.weight = correction.weight / correction.distance / sum_of_reverse_distances; } Helpers.NormalizeWeights(closest_corrections_v1); // Compute ratio of V0/V1 infuence on final result. Debug.Assert(calibration_mode.correction_fade_out_distance > 0); var vector_from_correction_to_cursor = closest_corrections_v1[0].vector_from_correction_to_cursor; float XYdistance = (float)Math.Sqrt( vector_from_correction_to_cursor[0] * vector_from_correction_to_cursor[0] + vector_from_correction_to_cursor[1] * vector_from_correction_to_cursor[1]); // Longer the distance lower the factor. float v0_vs_v1_factor = 1.0f - (float)Math.Pow( XYdistance / calibration_mode.correction_fade_out_distance, 4); if (v0_vs_v1_factor < 0) { v0_vs_v1_factor = 0; } // Merge v0 and v1 to single set using the computed factor. List <ShiftsStorage.PointInfo> v1_v0_hybrid_corrections = new List <ShiftsStorage.PointInfo>(); foreach (var correction in closest_corrections_v1) { correction.weight = v0_vs_v1_factor * correction.weight; v1_v0_hybrid_corrections.Add(correction); } foreach (var correction in closest_corrections_v0) { correction.weight = (1 - v0_vs_v1_factor) * correction.weight; int i = 0; for (; i < v1_v0_hybrid_corrections.Count; i++) { if (correction.correction == v1_v0_hybrid_corrections[i].correction) { v1_v0_hybrid_corrections[i].weight += correction.weight; break; } } if (i == v1_v0_hybrid_corrections.Count) { v1_v0_hybrid_corrections.Add(correction); } } var result = Helpers.GetWeightedAverage(v1_v0_hybrid_corrections); if (shift_storage.calibration_window != null) { var lables = new List <Tuple <string /*text*/, System.Windows.Point> >(); foreach (var correction in v1_v0_hybrid_corrections) { lables.Add(new Tuple <string, System.Windows.Point>((int)(correction.weight * 100) + "%", new System.Windows.Point( correction.correction.сoordinates[0], correction.correction.сoordinates[1]))); } shift_storage.calibration_window.UpdateCorrectionsLables(lables); shift_storage.calibration_window.UpdateCurrentCorrection(new EyeTrackerErrorCorrection(cursor_position, result)); } return(result); }