Ejemplo n.º 1
0
        public static void SubmitCalibrationValue(
            int step,
            AudioChannel channel,
            double offset)
        {
            double left  = inProgressCalibration[step].levelOffsetL;
            double right = inProgressCalibration[step].levelOffsetR;

            switch (channel)
            {
            case AudioChannel.Left:
                left += offset;
                break;

            case AudioChannel.Right:
                right += offset;
                break;

            default:
                Debug.LogError($"Unexpected Channel: {channel}");
                break;
            }

            inProgressCalibration[step] = new CalibrationPoint(
                levelIn: inProgressCalibration[step].levelIn,
                levelOffsetL: left,
                levelOffsetR: right);
        }
Ejemplo n.º 2
0
        public static void Save(string avatarId, CalibrationPoint point, CalibrationData data)
        {
            if (!SavedAvatars.ContainsKey(avatarId))
            {
                SavedAvatars[avatarId] = new Dictionary <CalibrationPoint, CalibrationData>();
            }

            SavedAvatars[avatarId][point] = data;
        }
Ejemplo n.º 3
0
 public void PointEnd(CalibrationPoint calPoint)
 {
     try
     {
         CalibrationPointEventArgs args = new CalibrationPointEventArgs(calPoint.Number, calPoint.Point);
         RaiseEvent(args);
     }
     catch (Exception ex)
     {
         ErrorLogger.WriteLine("CalibrationCommands, could not raise PointEnd, Message: " + ex.Message);
     }
 }
Ejemplo n.º 4
0
        public void TestCalibrationResult()
        {
            CalibrationResult cr = new CalibrationResult();

            cr.AverageErrorDegree      = 11.1d;
            cr.AverageErrorDegreeRight = 800.13d;

            CalibrationPoint cp = new CalibrationPoint();

            cp.StandardDeviation.Left = 123.123d;
            cp.Accuracy.Left          = 324.159d;
            cp.MeanError.Left         = 657.159d;
            cp.Coordinates            = new Point2D(321.123f, 432.234f);
            cr.Calibpoints            = new CalibrationPoint[] { cp };

            String            json = JsonConvert.SerializeObject(cr);
            CalibrationResult cr2  = JsonConvert.DeserializeObject <CalibrationResult>(json);

            Assert.AreEqual(cr, cr2);
            Assert.AreEqual(cr.GetHashCode(), cr2.GetHashCode());
        }
Ejemplo n.º 5
0
		/// <summary>
		/// Creates an instance of Windows.Devices.Sensors.NonLinearCalibration
		/// with the specified point count, minimum and maximum 
		/// reading values and calibration points.
		/// </summary>
		/// <param name="minimum">The minimum adjusted reading value allowed.</param>
		/// <param name="maximum">The maximum adjusted reading value allowed.</param>
		/// <param name="calibrationPoints">The calibrations points used to adjust the reading.</param>
		public LinearCalibration(float minimum, float maximum, CalibrationPoint[] calibrationPoints)
			: base(_calibrationPointCount, minimum, maximum, calibrationPoints)
		{
		}
Ejemplo n.º 6
0
		/// <summary>
		/// Calculates the values a, b and c in the formula y = mx + b
		/// </summary>
		public virtual void CalculateFormulaVariables(CalibrationPoint[] calibrationPoints, out float m, out float b)
		{
			if (calibrationPoints.Length == this.CalibrationPointCount)
			{
				// ***
				// *** These value are cast into variables here to hopefully
				// *** makes this more readable
				// ***
				float x1 = calibrationPoints[0].X;
				float x2 = calibrationPoints[1].X;

				float y1 = calibrationPoints[0].Y;
				float y2 = calibrationPoints[1].Y;

				m = (y2 - y1) / (x2 - x1);

				float b1 = m * x1;
				float b2 = m * x2;

				b = (b1 + b2) / 2;
			}
			else if (calibrationPoints.Length < this.CalibrationPointCount)
			{
				// ***
				// *** Throw a specific exception letting the caller 
				// *** know there are less than the three required points.
				// ***
				throw new ArgumentOutOfRangeException(string.Format("There are too few points defined. {0} must be an array of three points.", nameof(calibrationPoints)));
			}
			else
			{
				// ***
				// *** Throw a specific exception letting the caller 
				// *** know there are more than the three required points.
				// ***
				throw new ArgumentOutOfRangeException(string.Format("There are too many points defined. {0} must be an array of three points.", nameof(calibrationPoints)));
			}
		}
Ejemplo n.º 7
0
		/// <summary>
		/// Creates an instance of Windows.Devices.Sensors.AdjustedNonLinearCalibration
		/// with the specified point count, maximum 
		/// reading values and calibration points.
		/// </summary>
		/// <param name="maximum">The maximum adjusted reading value allowed.</param>
		/// <param name="calibrationPoints">The calibrations points used to adjust the reading.</param>
		public AdjustedNonLinearCalibration(float maximum, CalibrationPoint[] calibrationPoints)
			: base(_calibrationPointCount, maximum, calibrationPoints)
        {
		}
Ejemplo n.º 8
0
		/// <summary>
		/// Calculates the values a, b and c in the formula y = ax² + bx + c
		/// </summary>
		public virtual void CalculateFormulaVariables(CalibrationPoint[] calibrationPoints, out float a, out float b, out float c)
		{
			if (calibrationPoints.Length == this.CalibrationPointCount)
			{
				// ***
				// *** These value are cast into variables here to hopefully
				// *** makes this more readable
				// ***
				float x1 = calibrationPoints[0].X;
				float x2 = calibrationPoints[1].X;
				float x3 = calibrationPoints[2].X;

				float y1 = calibrationPoints[0].Y;
				float y2 = calibrationPoints[1].Y;
				float y3 = calibrationPoints[2].Y;

				float denom = (x1 - x2) * (x1 - x3) * (x2 - x3);
				a = (x3 * (y2 - y1) + x2 * (y1 - y3) + x1 * (y3 - y2)) / denom;
				b = (x3 * x3 * (y1 - y2) + x2 * x2 * (y3 - y1) + x1 * x1 * (y2 - y3)) / denom;
				c = (x2 * x3 * (x2 - x3) * y1 + x3 * x1 * (x3 - x1) * y2 + x1 * x2 * (x1 - x2) * y3) / denom;
			}
			else if (calibrationPoints.Length < this.CalibrationPointCount)
			{
				// ***
				// *** Throw a specific exception letting the caller 
				// *** know there are less than the three required points.
				// ***
				throw new ArgumentOutOfRangeException(string.Format("There are too few points defined. {0} must be an array of three points.", nameof(calibrationPoints)));
			}
			else
			{
				// ***
				// *** Throw a specific exception letting the caller 
				// *** know there are more than the three required points.
				// ***
				throw new ArgumentOutOfRangeException(string.Format("There are too many points defined. {0} must be an array of three points.", nameof(calibrationPoints)));
			}
		}
Ejemplo n.º 9
0
 public void PointStart(CalibrationPoint calPoint)
 {
     try
     {
         CalibrationPointEventArgs args = new CalibrationPointEventArgs(calPoint.Number, calPoint.Point);
         RaiseEvent(args);
     }
     catch (Exception ex)
     {
         ErrorLogger.WriteLine("CalibrationCommands, could not raise PointStart, Message: " + ex.Message);
     }
 }
Ejemplo n.º 10
0
        /// <summary> Get distance from blob center to calibrationpoint. </summary>
        PointF GetBlobDistance(Blob b, CalibrationPoint cp)
        {
            if (b == null || cp == null)
                throw new ArgumentNullException();

            //Since screen and webcam resolution don't match, use relative distances
            PointF relWebcam = GetRelativeBlobPosition(b);

            return new PointF(Math.Abs(cp.ScreenX - relWebcam.X), Math.Abs(cp.ScreenY - relWebcam.Y));
        }
Ejemplo n.º 11
0
 PointF GetAbsoluteCalibrationPointWebcam(CalibrationPoint cp)
 {
     return new PointF(cp.WebcamX * inputProvider.Camera.DesiredFrameSize.Width, cp.WebcamY * inputProvider.Camera.DesiredFrameSize.Height);
 }
Ejemplo n.º 12
0
 PointF GetAbsoluteCalibrationPointScreen(CalibrationPoint cp)
 {
     return new PointF(cp.ScreenX * Size.Width, cp.ScreenY * Size.Height);
 }
Ejemplo n.º 13
0
		/// <summary>
		/// Creates an instance of Porrey.Uwp.IoT.Calibration
		/// with the specified point count, minimum and maximum 
		/// reading values and calibration points.
		/// </summary>
		/// <param name="pointCount">The required number of calibration points.</param>
		/// <param name="minimum">The minimum adjusted reading value allowed.</param>
		/// <param name="maximum">The maximum adjusted reading value allowed.</param>
		/// <param name="calibrationPoints">The calibrations points used to adjust the reading.</param>
		public CalibratedMeasurement(int pointCount, float minimum, float maximum, CalibrationPoint[] calibrationPoints)
		{
			this.CalibrationPointCount = pointCount;
			this.Minimum = minimum;
			this.Maximum = maximum;
			this.CalibrationPoints = calibrationPoints;
		}
Ejemplo n.º 14
0
		/// <summary>
		/// Called when the calibration points are changed.
		/// </summary>
		/// <param name="calibrationPoints">The new calibration points.</param>
		protected virtual void OnCalibrationPointsChanged(CalibrationPoint[] calibrationPoints)
		{
		}
Ejemplo n.º 15
0
		protected override void OnCalibrationPointsChanged(CalibrationPoint[] calibrationPoints)
		{
			this.CalculateFormulaVariables(calibrationPoints, out _m, out _b);
		}
Ejemplo n.º 16
0
        private void DisplayCalibrationCurve()
        {
            Text = TabText = _originalFormTitle;
            CalibrationCurveOptions options = Settings.Default.CalibrationCurveOptions;

            zedGraphControl.GraphPane.YAxis.Type = options.LogYAxis ? AxisType.Log : AxisType.Linear;
            zedGraphControl.GraphPane.XAxis.Type = options.LogXAxis ? AxisType.Log : AxisType.Linear;
            bool logPlot = options.LogXAxis || options.LogYAxis;

            zedGraphControl.GraphPane.Legend.IsVisible = options.ShowLegend;
            _scatterPlots    = null;
            CalibrationCurve = null;
            FiguresOfMerit   = FiguresOfMerit.EMPTY;
            SrmDocument document = DocumentUiContainer.DocumentUI;

            if (!document.Settings.HasResults)
            {
                zedGraphControl.GraphPane.Title.Text =
                    QuantificationStrings.CalibrationForm_DisplayCalibrationCurve_No_results_available;
                return;
            }
            PeptideDocNode      peptide;
            PeptideGroupDocNode peptideGroup;

            if (!TryGetSelectedPeptide(out peptideGroup, out peptide))
            {
                zedGraphControl.GraphPane.Title.Text =
                    ModeUIAwareStringFormat(QuantificationStrings
                                            .CalibrationForm_DisplayCalibrationCurve_Select_a_peptide_to_see_its_calibration_curve);
                return;
            }
            if (-1 == document.Children.IndexOf(peptideGroup))
            {
                zedGraphControl.GraphPane.Title.Text = ModeUIAwareStringFormat(QuantificationStrings.CalibrationForm_DisplayCalibrationCurve_The_selected_peptide_is_no_longer_part_of_the_Skyline_document_);
                return;
            }
            PeptideQuantifier peptideQuantifier = PeptideQuantifier.GetPeptideQuantifier(document, peptideGroup,
                                                                                         peptide);
            CalibrationCurveFitter curveFitter = new CalibrationCurveFitter(peptideQuantifier, document.Settings);

            if (curveFitter.IsEnableSingleBatch && Settings.Default.CalibrationCurveOptions.SingleBatch)
            {
                curveFitter.SingleBatchReplicateIndex = _skylineWindow.SelectedResultsIndex;
            }

            Text = TabText = GetFormTitle(curveFitter);
            if (peptideQuantifier.QuantificationSettings.RegressionFit == RegressionFit.NONE)
            {
                if (!(peptideQuantifier.NormalizationMethod is NormalizationMethod.RatioToLabel))
                {
                    zedGraphControl.GraphPane.Title.Text =
                        ModeUIAwareStringFormat(QuantificationStrings.CalibrationForm_DisplayCalibrationCurve_Use_the_Quantification_tab_on_the_Peptide_Settings_dialog_to_control_the_conversion_of_peak_areas_to_concentrations_);
                }
                else
                {
                    if (!peptide.InternalStandardConcentration.HasValue)
                    {
                        zedGraphControl.GraphPane.Title.Text =
                            ModeUIAwareStringFormat(QuantificationStrings.CalibrationForm_DisplayCalibrationCurve_To_convert_peak_area_ratios_to_concentrations__specify_the_internal_standard_concentration_for__0__, peptide);
                    }
                    else
                    {
                        zedGraphControl.GraphPane.Title.Text = null;
                    }
                }
            }
            else
            {
                if (curveFitter.GetStandardConcentrations().Any())
                {
                    zedGraphControl.GraphPane.Title.Text = null;
                }
                else
                {
                    zedGraphControl.GraphPane.Title.Text = QuantificationStrings.CalibrationForm_DisplayCalibrationCurve_To_fit_a_calibration_curve__set_the_Sample_Type_of_some_replicates_to_Standard__and_specify_their_concentration_;
                }
            }

            zedGraphControl.GraphPane.XAxis.Title.Text = curveFitter.GetXAxisTitle();
            zedGraphControl.GraphPane.YAxis.Title.Text = curveFitter.GetYAxisTitle();
            CalibrationCurve = curveFitter.GetCalibrationCurve();
            FiguresOfMerit   = curveFitter.GetFiguresOfMerit(CalibrationCurve);
            double minX = double.MaxValue, maxX = double.MinValue;
            double minY = double.MaxValue;

            _scatterPlots = new CurveList();

            IEnumerable <SampleType> sampleTypes = SampleType.ListSampleTypes()
                                                   .Where(Options.DisplaySampleType);

            foreach (var sampleType in sampleTypes)
            {
                PointPairList pointPairList         = new PointPairList();
                PointPairList pointPairListExcluded = new PointPairList();
                foreach (var standardIdentifier in curveFitter.EnumerateCalibrationPoints())
                {
                    if (!Equals(sampleType, curveFitter.GetSampleType(standardIdentifier)))
                    {
                        continue;
                    }

                    double?y           = curveFitter.GetYValue(standardIdentifier);
                    double?xCalculated = curveFitter.GetCalculatedXValue(CalibrationCurve, standardIdentifier);
                    double?x           = curveFitter.GetSpecifiedXValue(standardIdentifier)
                                         ?? xCalculated;
                    if (y.HasValue && x.HasValue)
                    {
                        PointPair point = new PointPair(x.Value, y.Value)
                        {
                            Tag = standardIdentifier
                        };
                        if (sampleType.AllowExclude && null == standardIdentifier.LabelType && peptide.IsExcludeFromCalibration(standardIdentifier.ReplicateIndex))
                        {
                            pointPairListExcluded.Add(point);
                        }
                        else
                        {
                            pointPairList.Add(point);
                        }
                        if (!IsNumber(x) || !IsNumber(y))
                        {
                            continue;
                        }
                        if (!logPlot || x.Value > 0)
                        {
                            minX = Math.Min(minX, x.Value);
                        }
                        if (!logPlot || y.Value > 0)
                        {
                            minY = Math.Min(minY, y.Value);
                        }
                        maxX = Math.Max(maxX, x.Value);
                        if (IsNumber(xCalculated))
                        {
                            maxX = Math.Max(maxX, xCalculated.Value);
                            if (!logPlot || xCalculated.Value > 0)
                            {
                                minX = Math.Min(minX, xCalculated.Value);
                            }
                        }
                    }
                }
                if (pointPairList.Any())
                {
                    var lineItem = zedGraphControl.GraphPane.AddCurve(sampleType.ToString(), pointPairList,
                                                                      sampleType.Color, sampleType.SymbolType);
                    lineItem.Line.IsVisible = false;
                    lineItem.Symbol.Fill    = new Fill(sampleType.Color);
                    _scatterPlots.Add(lineItem);
                }
                if (pointPairListExcluded.Any())
                {
                    string curveLabel = pointPairList.Any() ? null : sampleType.ToString();
                    var    lineItem   = zedGraphControl.GraphPane.AddCurve(curveLabel, pointPairListExcluded,
                                                                           sampleType.Color, sampleType.SymbolType);
                    lineItem.Line.IsVisible = false;
                    _scatterPlots.Add(lineItem);
                }
            }
            List <string> labelLines    = new List <String>();
            RegressionFit regressionFit = document.Settings.PeptideSettings.Quantification.RegressionFit;

            if (regressionFit != RegressionFit.NONE)
            {
                if (minX <= maxX)
                {
                    int interpolatedLinePointCount = 100;
                    if (!logPlot && regressionFit != RegressionFit.LINEAR_IN_LOG_SPACE)
                    {
                        if (regressionFit == RegressionFit.LINEAR_THROUGH_ZERO)
                        {
                            minX = Math.Min(0, minX);
                        }
                        if (regressionFit != RegressionFit.QUADRATIC)
                        {
                            interpolatedLinePointCount = 2;
                        }
                    }
                    double[] xValues;
                    if (CalibrationCurve.TurningPoint.HasValue)
                    {
                        xValues = new[] { minX, CalibrationCurve.TurningPoint.Value, maxX };
                    }
                    else
                    {
                        xValues = new[] { minX, maxX };
                    }
                    Array.Sort(xValues);
                    LineItem interpolatedLine = CreateInterpolatedLine(CalibrationCurve, xValues,
                                                                       interpolatedLinePointCount, logPlot);
                    if (null != interpolatedLine)
                    {
                        zedGraphControl.GraphPane.CurveList.Add(interpolatedLine);
                    }
                }
                labelLines.Add(CalibrationCurve.ToString());

                if (CalibrationCurve.RSquared.HasValue)
                {
                    labelLines.Add(CalibrationCurve.RSquaredDisplayText(CalibrationCurve.RSquared.Value));
                }
                if (!Equals(curveFitter.QuantificationSettings.RegressionWeighting, RegressionWeighting.NONE))
                {
                    labelLines.Add(string.Format(@"{0}: {1}",
                                                 QuantificationStrings.Weighting, curveFitter.QuantificationSettings.RegressionWeighting));
                }
                if (options.ShowFiguresOfMerit)
                {
                    string strFiguresOfMerit = FiguresOfMerit.ToString();
                    if (!string.IsNullOrEmpty(strFiguresOfMerit))
                    {
                        labelLines.Add(strFiguresOfMerit);
                    }
                }
            }

            CalibrationPoint?selectionIdentifier = null;

            if (options.ShowSelection)
            {
                if (curveFitter.IsotopologResponseCurve)
                {
                    var labelType = (_skylineWindow.SequenceTree.SelectedNode as SrmTreeNode)
                                    ?.GetNodeOfType <TransitionGroupTreeNode>()?.DocNode.LabelType;
                    if (labelType != null)
                    {
                        selectionIdentifier =
                            new CalibrationPoint(_skylineWindow.SelectedResultsIndex,
                                                 labelType);
                    }
                }
                else
                {
                    selectionIdentifier =
                        new CalibrationPoint(_skylineWindow.SelectedResultsIndex, null);
                }
            }
            if (selectionIdentifier.HasValue)
            {
                double?ySelected = curveFitter.GetYValue(selectionIdentifier.Value);
                if (IsNumber(ySelected))
                {
                    double?     xSelected         = curveFitter.GetCalculatedXValue(CalibrationCurve, selectionIdentifier.Value);
                    var         selectedLineColor = Color.FromArgb(128, GraphSummary.ColorSelected);
                    const float selectedLineWidth = 2;
                    double?     xSpecified        = curveFitter.GetSpecifiedXValue(selectionIdentifier.Value);
                    if (IsNumber(xSelected))
                    {
                        ArrowObj arrow = new ArrowObj(xSelected.Value, ySelected.Value, xSelected.Value,
                                                      ySelected.Value)
                        {
                            Line = { Color = GraphSummary.ColorSelected }
                        };
                        zedGraphControl.GraphPane.GraphObjList.Insert(0, arrow);
                        var verticalLine = new LineObj(xSelected.Value, ySelected.Value, xSelected.Value,
                                                       options.LogYAxis ? minY / 10 : 0)
                        {
                            Line                 = { Color = selectedLineColor, Width = selectedLineWidth },
                            Location             = { CoordinateFrame = CoordType.AxisXYScale },
                            ZOrder               = ZOrder.E_BehindCurves,
                            IsClippedToChartRect = true
                        };
                        zedGraphControl.GraphPane.GraphObjList.Add(verticalLine);
                        if (IsNumber(xSpecified))
                        {
                            var horizontalLine = new LineObj(xSpecified.Value, ySelected.Value, xSelected.Value,
                                                             ySelected.Value)
                            {
                                Line                 = { Color = selectedLineColor, Width = selectedLineWidth },
                                Location             = { CoordinateFrame = CoordType.AxisXYScale },
                                ZOrder               = ZOrder.E_BehindCurves,
                                IsClippedToChartRect = true
                            };
                            zedGraphControl.GraphPane.GraphObjList.Add(horizontalLine);
                        }
                    }
                    else
                    {
                        // We were not able to map the observed intensity back to the calibration curve, but we still want to
                        // indicate where the currently selected point is.
                        if (IsNumber(xSpecified))
                        {
                            // If the point has a specified concentration, then use that.
                            ArrowObj arrow = new ArrowObj(xSpecified.Value, ySelected.Value, xSpecified.Value,
                                                          ySelected.Value)
                            {
                                Line = { Color = GraphSummary.ColorSelected }
                            };
                            zedGraphControl.GraphPane.GraphObjList.Insert(0, arrow);
                        }
                        else
                        {
                            // Otherwise, draw a horizontal line at the appropriate y-value.
                            var horizontalLine = new LineObj(minX, ySelected.Value, maxX, ySelected.Value)
                            {
                                Line                 = { Color = selectedLineColor, Width = selectedLineWidth },
                                Location             = { CoordinateFrame = CoordType.AxisXYScale },
                                IsClippedToChartRect = true,
                            };
                            ZedGraphControl.GraphPane.GraphObjList.Add(horizontalLine);
                        }
                    }
                }

                QuantificationResult quantificationResult = null;
                double?calculatedConcentration;
                if (curveFitter.IsotopologResponseCurve)
                {
                    calculatedConcentration =
                        curveFitter.GetCalculatedConcentration(CalibrationCurve, selectionIdentifier.Value);
                }
                else
                {
                    quantificationResult    = curveFitter.GetPeptideQuantificationResult(selectionIdentifier.Value.ReplicateIndex);
                    calculatedConcentration = quantificationResult?.CalculatedConcentration;
                }
                if (calculatedConcentration.HasValue)
                {
                    labelLines.Add(string.Format(@"{0} = {1}",
                                                 QuantificationStrings.Calculated_Concentration,
                                                 QuantificationResult.FormatCalculatedConcentration(calculatedConcentration.Value,
                                                                                                    curveFitter.QuantificationSettings.Units)));
                }
                else if (quantificationResult != null && !quantificationResult.NormalizedArea.HasValue)
                {
                    labelLines.Add(QuantificationStrings.CalibrationForm_DisplayCalibrationCurve_The_selected_replicate_has_missing_or_truncated_transitions);
                }
            }
            if (Options.ShowFiguresOfMerit)
            {
                if (IsNumber(FiguresOfMerit.LimitOfDetection))
                {
                    var lodLine = new LineObj(Color.DarkMagenta, FiguresOfMerit.LimitOfDetection.Value, 0,
                                              FiguresOfMerit.LimitOfDetection.Value, 1)
                    {
                        Location = { CoordinateFrame = CoordType.XScaleYChartFraction }
                    };
                    zedGraphControl.GraphPane.GraphObjList.Add(lodLine);
                }
                if (IsNumber(FiguresOfMerit.LimitOfQuantification))
                {
                    var loqLine = new LineObj(Color.DarkCyan, FiguresOfMerit.LimitOfQuantification.Value, 0,
                                              FiguresOfMerit.LimitOfQuantification.Value, 1)
                    {
                        Location = { CoordinateFrame = CoordType.XScaleYChartFraction }
                    };
                    zedGraphControl.GraphPane.GraphObjList.Add(loqLine);
                }
            }
            if (labelLines.Any())
            {
                TextObj text = new TextObj(TextUtil.LineSeparate(labelLines), .01, 0,
                                           CoordType.ChartFraction, AlignH.Left, AlignV.Top)
                {
                    IsClippedToChartRect = true,
                    ZOrder   = ZOrder.E_BehindCurves,
                    FontSpec = GraphSummary.CreateFontSpec(Color.Black),
                };
                zedGraphControl.GraphPane.GraphObjList.Add(text);
            }
        }
Ejemplo n.º 17
0
        /// <summary> Get the total relative distance (sum of X and Y). This may be a good indication of how close the blob is to the cp.</summary>
        float GetBlobDistanceIndicator(Blob b, CalibrationPoint cp)
        {
            if (b == null || cp == null)
                throw new ArgumentNullException();

            return GetBlobDistance(b, cp).X + GetBlobDistance(b, cp).Y;
        }