/// <summary> /// Calculates the area above the top limit for two blood sugar points. /// </summary> /// <param name="glucoseValue1">The first blood sugar glucose value.</param> /// <param name="timestamp1">The timestamp of the first blood sugar.</param> /// <param name="glucoseValue2">The second blood sugar glucose value.</param> /// <param name="timestamp2">The timestamp of the second blood sugar.</param> /// <param name="inclusiveTopLimit">The inclusive limit of good blood sugar.</param> /// <returns>The area above the top limit (seconds * mmol/L).</returns> private static decimal calculateAreaAboveRange(decimal glucoseValue1, DateTime timestamp1, decimal glucoseValue2, DateTime timestamp2, decimal inclusiveTopLimit) { //Both values are BELOW the limit. if (glucoseValue1 <= inclusiveTopLimit && glucoseValue2 <= inclusiveTopLimit) { return(0); } //Both values are ABOVE the limit. else if (glucoseValue1 > inclusiveTopLimit && glucoseValue2 > inclusiveTopLimit) { var hoursBetween = calculateTimeDifferenceInHours(timestamp1, timestamp2); var minValue = Math.Min(glucoseValue1, glucoseValue2); var area = (minValue - inclusiveTopLimit) * hoursBetween; var maxValue = Math.Max(glucoseValue1, glucoseValue2); var triangleArea = (maxValue - minValue) * hoursBetween / 2; area += triangleArea; if (area < 0) { throw new ConstraintException("The area calculated was a negative value."); } return(area); } //One value is above the limit and the other is below. else { //Find the line traversing the blood sugar values. var hoursBetween = calculateTimeDifferenceInHours(timestamp1, timestamp2); var p1 = new PointF(0, (float)(glucoseValue1)); var p2 = new PointF((float)hoursBetween, (float)(glucoseValue2)); var line = new MathLine(p1, p2); //Find where the line crosses the top limit. var topLimitLine = new MathLine(0, (float)inclusiveTopLimit); var intersection = MathLine.GetIntersectionPoint(line, topLimitLine); //Calculate the area above the top limit. var highestPoint = p1.Y > p2.Y ? p1 : p2; var triangleBase = Math.Abs(intersection.X - highestPoint.X); var triangleHeight = highestPoint.Y - (float)inclusiveTopLimit; var triangleArea = triangleBase * triangleHeight / 2; //Return the area above the top limit. if (triangleArea < 0) { throw new ConstraintException("The area calculated was a negative value."); } return(Convert.ToDecimal(triangleArea)); } }
/// <summary> /// Gets the point in which two lines intersect. /// </summary> /// <param name="lineA">The first line.</param> /// <param name="lineB">The second line.</param> /// <returns>The point in which the two lines intersect.</returns> public static PointF GetIntersectionPoint(MathLine lineA, MathLine lineB) { //Implemented according to: //https://en.wikipedia.org/w/index.php?title=Line%E2%80%93line_intersection&oldid=815048738#Given_the_equations_of_the_lines if (lineA.Slope == lineB.Slope) { throw new ConstraintException("The slopes are identical, meaning the lines are parallel and has no intersection point!"); } float x = (lineB.Offset - lineA.Offset) / (lineA.Slope - lineB.Slope); //Will never be division by zero due to the exception above. float y = lineA.GetY(x); PointF intersection = new PointF(x, y); return(intersection); }