|
| 1 | +// Copyright (c) Files Community |
| 2 | +// Licensed under the MIT License. |
| 3 | + |
| 4 | +namespace Files.App.Controls |
| 5 | +{ |
| 6 | + internal static partial class Helpers |
| 7 | + { |
| 8 | + /// <summary> |
| 9 | + /// Calculates the modulus of a number with respect to a divider. |
| 10 | + /// The result is always positive or zero, regardless of the input values. |
| 11 | + /// </summary> |
| 12 | + /// <param name="number">The input number.</param> |
| 13 | + /// <param name="divider">The divider (non-zero).</param> |
| 14 | + /// <returns>The positive modulus result.</returns> |
| 15 | + internal static double CalculateModulus(double number, double divider) |
| 16 | + { |
| 17 | + // Calculate the modulus |
| 18 | + var result = number % divider; |
| 19 | + |
| 20 | + // Ensure the result is positive or zero |
| 21 | + result = result < 0 ? result + divider : result; |
| 22 | + |
| 23 | + return result; |
| 24 | + } |
| 25 | + |
| 26 | + /// <summary> |
| 27 | + /// Calculates an interpolated thickness value based on the provided parameters. |
| 28 | + /// </summary> |
| 29 | + /// <param name="d">The DependencyObject representing the control.</param> |
| 30 | + /// <param name="startValue">The starting value for interpolation.</param> |
| 31 | + /// <param name="value">The current value to interpolate.</param> |
| 32 | + /// <param name="endValue">The ending value for interpolation.</param> |
| 33 | + /// <param name="startThickness">The starting thickness value.</param> |
| 34 | + /// <param name="endThickness">The ending thickness value.</param> |
| 35 | + /// <param name="useEasing">Indicates whether to apply an easing function.</param> |
| 36 | + /// <returns>The interpolated thickness value.</returns> |
| 37 | + internal static double GetThicknessTransition(DependencyObject d, double startValue, double value, double endValue, double startThickness, double endThickness, bool useEasing) |
| 38 | + { |
| 39 | + // Ensure that value is within the range [startValue, endValue] |
| 40 | + value = Math.Max(startValue, Math.Min(endValue, value)); |
| 41 | + |
| 42 | + // Calculate the interpolation factor (t) between 0 and 1 |
| 43 | + var t = (value - startValue) / (endValue - startValue); |
| 44 | + |
| 45 | + double interpolatedThickness; |
| 46 | + |
| 47 | + if (useEasing) |
| 48 | + { |
| 49 | + // Apply an easing function (e.g., quadratic ease-in-out) |
| 50 | + var easedT = Helpers.EaseOutCubic(t); |
| 51 | + |
| 52 | + // Interpolate the thickness |
| 53 | + interpolatedThickness = startThickness + easedT * (endThickness - startThickness); |
| 54 | + } |
| 55 | + else |
| 56 | + { |
| 57 | + // Interpolate the thickness |
| 58 | + interpolatedThickness = startThickness + t * (endThickness - startThickness); |
| 59 | + } |
| 60 | + |
| 61 | + return interpolatedThickness; |
| 62 | + } |
| 63 | + |
| 64 | + /// <summary> |
| 65 | + /// Calculates an interpolated angle based on the provided parameters. |
| 66 | + /// </summary> |
| 67 | + /// <param name="d">The DependencyObject representing the control.</param> |
| 68 | + /// <param name="startValue">The starting value for interpolation.</param> |
| 69 | + /// <param name="value">The current value to interpolate.</param> |
| 70 | + /// <param name="endValue">The ending value for interpolation.</param> |
| 71 | + /// <param name="startAngle">The starting angle value.</param> |
| 72 | + /// <param name="endAngle">The ending angle value.</param> |
| 73 | + /// <param name="valueAngle">The angle corresponding to the current value.</param> |
| 74 | + /// <param name="useEasing">Indicates whether to apply an easing function.</param> |
| 75 | + /// <returns>The interpolated angle value.</returns> |
| 76 | + internal static double GetAdjustedAngle(DependencyObject d, double startValue, double value, double endValue, double startAngle, double endAngle, double valueAngle, bool useEasing) |
| 77 | + { |
| 78 | + // Ensure that value is within the range [startValue, endValue] |
| 79 | + value = Math.Max(startValue, Math.Min(endValue, value)); |
| 80 | + |
| 81 | + // Calculate the interpolation factor (t) between 0 and 1 |
| 82 | + var t = (value - startValue) / (endValue - startValue); |
| 83 | + |
| 84 | + double interpolatedAngle; |
| 85 | + |
| 86 | + if (useEasing) |
| 87 | + { |
| 88 | + // Apply an easing function |
| 89 | + var easedT = Helpers.EaseOutCubic(t); |
| 90 | + |
| 91 | + // Interpolate the angle |
| 92 | + interpolatedAngle = startAngle + easedT * (endAngle - startAngle); |
| 93 | + } |
| 94 | + else |
| 95 | + { |
| 96 | + // Interpolate the angle |
| 97 | + interpolatedAngle = startAngle + t * (endAngle - startAngle); |
| 98 | + } |
| 99 | + |
| 100 | + return interpolatedAngle; |
| 101 | + } |
| 102 | + |
| 103 | + /// <summary> |
| 104 | + /// Converts a value within a specified range to a percentage. |
| 105 | + /// </summary> |
| 106 | + /// <param name="value">The value to convert.</param> |
| 107 | + /// <param name="minValue">The minimum value of the input range.</param> |
| 108 | + /// <param name="maxValue">The maximum value of the input range.</param> |
| 109 | + /// <returns>The percentage value (between 0 and 100).</returns> |
| 110 | + internal static double DoubleToPercentage(double value, double minValue, double maxValue) |
| 111 | + { |
| 112 | + // Ensure value is within the specified range |
| 113 | + if (value < minValue) |
| 114 | + { |
| 115 | + return 0.0; // Below the range |
| 116 | + } |
| 117 | + else if (value > maxValue) |
| 118 | + { |
| 119 | + return 100.0; // Above the range |
| 120 | + } |
| 121 | + else |
| 122 | + { |
| 123 | + // Calculate the normalized value |
| 124 | + var normalizedValue = (value - minValue) / (maxValue - minValue); |
| 125 | + |
| 126 | + // Convert to percentage |
| 127 | + var percentage = normalizedValue * 100.0; |
| 128 | + |
| 129 | + double roundedPercentage = Math.Round(percentage, 2, MidpointRounding.ToEven); |
| 130 | + return roundedPercentage; |
| 131 | + } |
| 132 | + } |
| 133 | + |
| 134 | + /// <summary> |
| 135 | + /// Converts a percentage within a specified range to a value. |
| 136 | + /// </summary> |
| 137 | + /// <param name="percentage">The percentage to convert.</param> |
| 138 | + /// <param name="minValue">The minimum value of the input range.</param> |
| 139 | + /// <param name="maxValue">The maximum value of the input range.</param> |
| 140 | + /// <returns>The percentage value (between 0 and 100).</returns> |
| 141 | + internal static double PercentageToValue(double percentage, double minValue, double maxValue) |
| 142 | + { |
| 143 | + double convertedValue = percentage * (maxValue - minValue) / 100.0; |
| 144 | + |
| 145 | + // Ensure the converted value stays within the specified range |
| 146 | + if (convertedValue < minValue) |
| 147 | + convertedValue = minValue; |
| 148 | + else if (convertedValue > maxValue) |
| 149 | + convertedValue = maxValue; |
| 150 | + |
| 151 | + return convertedValue; |
| 152 | + } |
| 153 | + |
| 154 | + /// <summary> |
| 155 | + /// Calculates the total angle needed to accommodate a gap between two strokes around a circle. |
| 156 | + /// </summary> |
| 157 | + /// <param name="thickness">The Thickness radius to measure.</param> |
| 158 | + /// <param name="radius">The radius of the rings.</param> |
| 159 | + /// <returns>The gap angle (sum of angles for the larger and smaller strokes).</returns> |
| 160 | + internal static double GapThicknessToAngle(double radius, double thickness) |
| 161 | + { |
| 162 | + if (radius > 0 && thickness > 0) |
| 163 | + { |
| 164 | + // Calculate the maximum number of circles |
| 165 | + double n = Math.PI * (radius / thickness); |
| 166 | + |
| 167 | + // Calculate the angle between each small circle |
| 168 | + double angle = 360.0 / n; |
| 169 | + |
| 170 | + return angle; |
| 171 | + } |
| 172 | + |
| 173 | + return 0; |
| 174 | + } |
| 175 | + |
| 176 | + internal static double GetInterpolatedAngle(double startAngle, double endAngle, double valueAngle) |
| 177 | + { |
| 178 | + // Linear interpolation formula (lerp): GetInterpolatedAngle = (startAngle + valueAngle) * (endAngle - startAngle) |
| 179 | + return (startAngle + valueAngle) * (endAngle - startAngle); |
| 180 | + } |
| 181 | + |
| 182 | + internal static bool IsFullCircle(double MinAngle, double MaxAngle) |
| 183 | + { |
| 184 | + // Calculate the absolute difference between angles |
| 185 | + double angleDifference = Math.Abs(MaxAngle - MinAngle); |
| 186 | + |
| 187 | + // Check if the angle difference is equal to 360 degrees |
| 188 | + //return angleDifference == 360; |
| 189 | + |
| 190 | + // Changed to this as suggested by Marcel |
| 191 | + return Math.Abs(angleDifference - 360) < Double.Epsilon; |
| 192 | + } |
| 193 | + |
| 194 | + internal static double CalculateInterpolatedValue(double startValue, double value, double endValue, double startOutput, double endOutput, bool useEasing) |
| 195 | + { |
| 196 | + // Ensure that value is within the range [startValue, endValue] |
| 197 | + value = Math.Max(startValue, Math.Min(endValue, value)); |
| 198 | + |
| 199 | + // Calculate the interpolation factor (t) between 0 and 1 |
| 200 | + var t = (value - startValue) / (endValue - startValue); |
| 201 | + |
| 202 | + double interpolatedOutput; |
| 203 | + |
| 204 | + if (useEasing) |
| 205 | + { |
| 206 | + // Apply an easing function (e.g., quadratic ease-in-out) |
| 207 | + //var easedT = EaseInOutFunction(t); |
| 208 | + var easedT = EaseOutCubic(t); |
| 209 | + |
| 210 | + // Interpolate the thickness |
| 211 | + interpolatedOutput = startOutput + easedT * (endOutput - startOutput); |
| 212 | + } |
| 213 | + else |
| 214 | + { |
| 215 | + // Interpolate the thickness |
| 216 | + interpolatedOutput = startOutput + t * (endOutput - startOutput); |
| 217 | + } |
| 218 | + |
| 219 | + return interpolatedOutput; |
| 220 | + } |
| 221 | + |
| 222 | + internal static double EasingInOutFunction(double t) |
| 223 | + { |
| 224 | + return t < 0.5 ? 2 * t * t : 1 - Math.Pow(-2 * t + 2, 2) / 2; |
| 225 | + } |
| 226 | + |
| 227 | + internal static double EaseOutCubic(double t) |
| 228 | + { |
| 229 | + return 1.0 - Math.Pow(1.0 - t, 3.0); |
| 230 | + } |
| 231 | + } |
| 232 | +} |
0 commit comments