// Draw the tangent and normal to the equation at diffAt // Method takes a Graphics object to draw to the panel and the target of differention set by the user private float DrawTangentAndNormalLines(Graphics g, float diffAt) { // Create a new object to allow the estimation of the derivative of the target equation TargetFunction at diffAt var diff = new CentralDifferenceMethod(TargetFunction, diffAt); // The gradient of the function at diffAt double grad; try { // Evaluate the target function at diffAt float fa = TargetFunction.EvaluateF(diffAt.ToString(CultureInfo.InvariantCulture)); // Obtain the value of the first derivative of the functiona at diffAt // This will become the gradient of the tangent line grad = diff.DeriveFirst(); PointF originPoint = ToCartesianPoint(0, 0); PointF widthPoint = ToCartesianPoint(Width, 0); // If the gradient is defined if (!Double.IsNaN(grad)) { // Convert the gradient to a float to allow for drawing and get the normal gradient float tangentGrad = Convert.ToSingle(grad); float normalGrad = Convert.ToSingle(-1 / grad); // Set the NormalGrad property to the gradient of the normal line, rounding to avoid innacuracies NormalGrad = (float) Math.Round(normalGrad, 3); // If the gradient is defined and can be drawn if (Math.Abs(grad) < 1250) { // Draw the tangent to the function DrawLine(g, Color.Red, 3F, originPoint.X, fa + tangentGrad * (originPoint.X - diffAt), widthPoint.X, fa + tangentGrad * (widthPoint.X - diffAt), false); // If the normal is defined and can be drawn if (Math.Abs(grad) > 0.010) { // Draw the normal with a dashed line DrawLine(g, Color.Gray, 3F, originPoint.X, fa + normalGrad * (originPoint.X - diffAt), widthPoint.X, fa + normalGrad * (widthPoint.X - diffAt), true); } } // Get the equations of the tangent and normal and set the corresponding fields to their values Tangent = "y - " + Math.Round(fa, 3) + " = " + Math.Round(grad, 3) + " (x - " + Math.Round(diffAt, 3) + ")"; Normal = "y - " + Math.Round(fa, 3) + " = " + NormalGrad + " (x - " + Math.Round(diffAt, 3) + ")"; } else { // If the gradient is not defined return NaN return Single.NaN; } } catch (Exception) { // If any errors occured return NaN return Single.NaN; } // Return the gradient of the function return Convert.ToSingle(grad); }
// Method tells the grapher to find any local extrema within the graph view // Method returns a list of Extrema objects, each representing a local minimum or maximum // A function has a minimum or maxmimum when the first derivative is zero // If the second derivative at a minimum or maximum is negative, then the function is at a // maximum. Otherwise the function is at a minimum // Currently this method can produce repeated and innaccurate results due to innacuracies in the // calculation of the derivatives public List <Extrema> FindExtrema() { // Get the values of bounds of the current graph view // These values will become the bounds of the searching radius PointF min = ToCartesianPoint(0, 5); PointF max = ToCartesianPoint(Width, 5); // Set the current target and visible target to the minimum visible point on the graph float currentTarget = min.X; // The target variable defines the point visible to the user during the calculation target = min.X; // Set the finding field to true finding = true; // Obtain an object to estimate the derivatives of the target function var m = new CentralDifferenceMethod(TargetFunction, currentTarget); // Make a list object to hold the extrema that have been found var ex = new List <Extrema>(); try { // While the target is still in the searching bounds while (currentTarget < max.X) { // Estimate the first derivative double res = m.DeriveFirst(); // If the first derivative is within a tolerance to zero if (Math.Abs(Math.Round(res, 3)) < 0.0025) { // Calculate the second derivative double second = m.DeriveSecond(); // If the function is at a maximum if (second < 0) { // Add a new Extrema to the list with the current target point ex = AddExtrema(ex, currentTarget, "Local Maximum"); } else { // The function is at a minimum // Add a new Extrema to the list with the current target point ex = AddExtrema(ex, currentTarget, "Local Minimum"); } } // Increment the target points currentTarget += 0.001F; target += 0.08F; // Set the target point of the differentiation object to get ready for thex next calculation m.TargetPoint = currentTarget; // If the grapher is still searching, repaint the graph to update the user on progress if (target < max.X) { Invalidate(); Update(); } } } catch (Exception) { // Prompt the user if any errors occur during the calculations MessageBox.Show("Unable to find extrema", "Eror", MessageBoxButtons.OK, MessageBoxIcon.Error); return(null); } // Prompt the user that the grapher has finished searching MessageBox.Show("Finished finding extrema", "Success", MessageBoxButtons.OK, MessageBoxIcon.Information); // Reset variables and return the list of extrema found finding = false; target = max.X; Invalidate(); return(ex); }
// Method tells the grapher to find any local extrema within the graph view // Method returns a list of Extrema objects, each representing a local minimum or maximum // A function has a minimum or maxmimum when the first derivative is zero // If the second derivative at a minimum or maximum is negative, then the function is at a // maximum. Otherwise the function is at a minimum // Currently this method can produce repeated and innaccurate results due to innacuracies in the // calculation of the derivatives public List<Extrema> FindExtrema() { // Get the values of bounds of the current graph view // These values will become the bounds of the searching radius PointF min = ToCartesianPoint(0, 5); PointF max = ToCartesianPoint(Width, 5); // Set the current target and visible target to the minimum visible point on the graph float currentTarget = min.X; // The target variable defines the point visible to the user during the calculation target = min.X; // Set the finding field to true finding = true; // Obtain an object to estimate the derivatives of the target function var m = new CentralDifferenceMethod(TargetFunction, currentTarget); // Make a list object to hold the extrema that have been found var ex = new List<Extrema>(); try { // While the target is still in the searching bounds while (currentTarget < max.X) { // Estimate the first derivative double res = m.DeriveFirst(); // If the first derivative is within a tolerance to zero if (Math.Abs(Math.Round(res, 3)) < 0.0025) { // Calculate the second derivative double second = m.DeriveSecond(); // If the function is at a maximum if (second < 0) { // Add a new Extrema to the list with the current target point ex = AddExtrema(ex, currentTarget, "Local Maximum"); } else { // The function is at a minimum // Add a new Extrema to the list with the current target point ex = AddExtrema(ex, currentTarget, "Local Minimum"); } } // Increment the target points currentTarget += 0.001F; target += 0.08F; // Set the target point of the differentiation object to get ready for thex next calculation m.TargetPoint = currentTarget; // If the grapher is still searching, repaint the graph to update the user on progress if (target < max.X) { Invalidate(); Update(); } } } catch (Exception) { // Prompt the user if any errors occur during the calculations MessageBox.Show("Unable to find extrema", "Eror", MessageBoxButtons.OK, MessageBoxIcon.Error); return null; } // Prompt the user that the grapher has finished searching MessageBox.Show("Finished finding extrema", "Success", MessageBoxButtons.OK, MessageBoxIcon.Information); // Reset variables and return the list of extrema found finding = false; target = max.X; Invalidate(); return ex; }
// Draw the tangent and normal to the equation at diffAt // Method takes a Graphics object to draw to the panel and the target of differention set by the user private float DrawTangentAndNormalLines(Graphics g, float diffAt) { // Create a new object to allow the estimation of the derivative of the target equation TargetFunction at diffAt var diff = new CentralDifferenceMethod(TargetFunction, diffAt); // The gradient of the function at diffAt double grad; try { // Evaluate the target function at diffAt float fa = TargetFunction.EvaluateF(diffAt.ToString(CultureInfo.InvariantCulture)); // Obtain the value of the first derivative of the functiona at diffAt // This will become the gradient of the tangent line grad = diff.DeriveFirst(); PointF originPoint = ToCartesianPoint(0, 0); PointF widthPoint = ToCartesianPoint(Width, 0); // If the gradient is defined if (!Double.IsNaN(grad)) { // Convert the gradient to a float to allow for drawing and get the normal gradient float tangentGrad = Convert.ToSingle(grad); float normalGrad = Convert.ToSingle(-1 / grad); // Set the NormalGrad property to the gradient of the normal line, rounding to avoid innacuracies NormalGrad = (float)Math.Round(normalGrad, 3); // If the gradient is defined and can be drawn if (Math.Abs(grad) < 1250) { // Draw the tangent to the function DrawLine(g, Color.Red, 3F, originPoint.X, fa + tangentGrad * (originPoint.X - diffAt), widthPoint.X, fa + tangentGrad * (widthPoint.X - diffAt), false); // If the normal is defined and can be drawn if (Math.Abs(grad) > 0.010) { // Draw the normal with a dashed line DrawLine(g, Color.Gray, 3F, originPoint.X, fa + normalGrad * (originPoint.X - diffAt), widthPoint.X, fa + normalGrad * (widthPoint.X - diffAt), true); } } // Get the equations of the tangent and normal and set the corresponding fields to their values Tangent = "y - " + Math.Round(fa, 3) + " = " + Math.Round(grad, 3) + " (x - " + Math.Round(diffAt, 3) + ")"; Normal = "y - " + Math.Round(fa, 3) + " = " + NormalGrad + " (x - " + Math.Round(diffAt, 3) + ")"; } else { // If the gradient is not defined return NaN return(Single.NaN); } } catch (Exception) { // If any errors occured return NaN return(Single.NaN); } // Return the gradient of the function return(Convert.ToSingle(grad)); }