Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Different units for trigonometric functions in PowerToys Run calculator plugin #36717

Open
wants to merge 4 commits into
base: main
Choose a base branch
from
Open
Show file tree
Hide file tree
Changes from 2 commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
Original file line number Diff line number Diff line change
Expand Up @@ -276,5 +276,67 @@
Assert.IsNotNull(result);
Assert.AreEqual(expectedResult, result.Result);
}

[DataTestMethod]
[DataRow("sin(90)", "sin((pi / 180) * (90))")]
[DataRow("arcsin(0.5)", "(180 / pi) * (arcsin(0.5))")]
[DataRow("sin(sin(30))", "sin((pi / 180) * (sin((pi / 180) * (30))))")]
[DataRow("cos(tan(45))", "cos((pi / 180) * (tan((pi / 180) * (45))))")]
[DataRow("arctan(sin(30))", "(180 / pi) * (arctan(sin((pi / 180) * (30))))")]
[DataRow("sin(cos(tan(30)))", "sin((pi / 180) * (cos((pi / 180) * (tan((pi / 180) * (30))))))")]
[DataRow("sin(arcsin(0.5))", "sin((pi / 180) * ((180 / pi) * (arcsin(0.5))))")]
[DataRow("sin(30) + cos(60)", "sin((pi / 180) * (30)) + cos((pi / 180) * (60))")]
[DataRow("sin(30 + 15)", "sin((pi / 180) * (30 + 15))")]
[DataRow("sin(45) * cos(45) - tan(30)", "sin((pi / 180) * (45)) * cos((pi / 180) * (45)) - tan((pi / 180) * (30))")]
[DataRow("arcsin(arccos(0.5))", "(180 / pi) * (arcsin((180 / pi) * (arccos(0.5))))")]
[DataRow("sin(sin(sin(30)))", "sin((pi / 180) * (sin((pi / 180) * (sin((pi / 180) * (30))))))")]
[DataRow("log(10)", "log(10)")]
[DataRow("sin(30) + pi", "sin((pi / 180) * (30)) + pi")]
[DataRow("sin(-30)", "sin((pi / 180) * (-30))")]
[DataRow("sin((30))", "sin((pi / 180) * ((30)))")]
[DataRow("arcsin(1) * 2", "(180 / pi) * (arcsin(1)) * 2")]
[DataRow("cos(1/2)", "cos((pi / 180) * (1/2))")]
[DataRow("sin ( 90 )", "sin ((pi / 180) * ( 90 ))")]
[DataRow("cos(arcsin(sin(45)))", "cos((pi / 180) * ((180 / pi) * (arcsin(sin((pi / 180) * (45))))))")]
public void UpdateTrigFunctions_Degrees(string input, string expectedResult)
{
// Call UpdateTrigFunctions in degrees mode
string result = CalculateHelper.UpdateTrigFunctions(input, CalculateEngine.TrigMode.Degrees);

// Assert
Assert.IsNotNull(result);
Assert.AreEqual(expectedResult, result);
}

[DataTestMethod]
[DataRow("sin(90)", "sin((pi / 200) * (90))")]
[DataRow("arcsin(0.5)", "(200 / pi) * (arcsin(0.5))")]
[DataRow("sin(sin(30))", "sin((pi / 200) * (sin((pi / 200) * (30))))")]
[DataRow("cos(tan(45))", "cos((pi / 200) * (tan((pi / 200) * (45))))")]
[DataRow("arctan(sin(30))", "(200 / pi) * (arctan(sin((pi / 200) * (30))))")]
[DataRow("sin(cos(tan(30)))", "sin((pi / 200) * (cos((pi / 200) * (tan((pi / 200) * (30))))))")]
[DataRow("sin(arcsin(0.5))", "sin((pi / 200) * ((200 / pi) * (arcsin(0.5))))")]
[DataRow("sin(30) + cos(60)", "sin((pi / 200) * (30)) + cos((pi / 200) * (60))")]
[DataRow("sin(30 + 15)", "sin((pi / 200) * (30 + 15))")]
[DataRow("sin(45) * cos(45) - tan(30)", "sin((pi / 200) * (45)) * cos((pi / 200) * (45)) - tan((pi / 200) * (30))")]
[DataRow("arcsin(arccos(0.5))", "(200 / pi) * (arcsin((200 / pi) * (arccos(0.5))))")]
[DataRow("sin(sin(sin(30)))", "sin((pi / 200) * (sin((pi / 200) * (sin((pi / 200) * (30))))))")]
[DataRow("log(10)", "log(10)")]
[DataRow("sin(30) + pi", "sin((pi / 200) * (30)) + pi")]
[DataRow("sin(-30)", "sin((pi / 200) * (-30))")]
[DataRow("sin((30))", "sin((pi / 200) * ((30)))")]
[DataRow("arcsin(1) * 2", "(200 / pi) * (arcsin(1)) * 2")]
[DataRow("cos(1/2)", "cos((pi / 200) * (1/2))")]
[DataRow("sin ( 90 )", "sin ((pi / 200) * ( 90 ))")]
[DataRow("cos(arcsin(sin(45)))", "cos((pi / 200) * ((200 / pi) * (arcsin(sin((pi / 200) * (45))))))")]
public void UpdateTrigFunctions_Gradians(string input, string expectedResult)

Check warning on line 332 in src/modules/launcher/Plugins/Microsoft.PowerToys.Run.Plugin.Calculator.UnitTest/ExtendedCalculatorParserTests.cs

View workflow job for this annotation

GitHub Actions / Check Spelling

`Gradians` is not a recognized word. (unrecognized-spelling)
{
// Call UpdateTrigFunctions in gradians mode

Check warning on line 334 in src/modules/launcher/Plugins/Microsoft.PowerToys.Run.Plugin.Calculator.UnitTest/ExtendedCalculatorParserTests.cs

View workflow job for this annotation

GitHub Actions / Check Spelling

`gradians` is not a recognized word. (unrecognized-spelling)
string result = CalculateHelper.UpdateTrigFunctions(input, CalculateEngine.TrigMode.Gradians);

Check warning on line 335 in src/modules/launcher/Plugins/Microsoft.PowerToys.Run.Plugin.Calculator.UnitTest/ExtendedCalculatorParserTests.cs

View workflow job for this annotation

GitHub Actions / Check Spelling

`Gradians` is not a recognized word. (unrecognized-spelling)

// Assert
Assert.IsNotNull(result);
Assert.AreEqual(expectedResult, result);
}
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -23,6 +23,13 @@

public const int RoundingDigits = 10;

public enum TrigMode
{
Radians,
Degrees,
Gradians,

Check warning on line 30 in src/modules/launcher/Plugins/Microsoft.PowerToys.Run.Plugin.Calculator/CalculateEngine.cs

View workflow job for this annotation

GitHub Actions / Check Spelling

`Gradians` is not a recognized word. (unrecognized-spelling)
}

/// <summary>
/// Interpret
/// </summary>
Expand Down Expand Up @@ -52,6 +59,9 @@

input = CalculateHelper.FixHumanMultiplicationExpressions(input);

// Modify trig functions depending on angle unit setting
input = CalculateHelper.UpdateTrigFunctions(input, Main.GetTrigMode());

var result = _magesEngine.Interpret(input);

// This could happen for some incorrect queries, like pi(2)
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -25,6 +25,11 @@
@")+$",
RegexOptions.Compiled);

private const string DegToRad = "(pi / 180) * ";
private const string GradToRad = "(pi / 200) * ";
private const string RadToDeg = "(180 / pi) * ";
private const string RadToGrad = "(200 / pi) * ";

public static bool InputValid(string input)
{
if (string.IsNullOrWhiteSpace(input))
Expand Down Expand Up @@ -204,5 +209,86 @@

return output;
}

// Gets the index of the closing bracket of a function
private static int FindClosingBracketIndex(string input, int start)
{
int bracketCount = 0; // Set count to zero
for (int i = start; i < input.Length; i++)
{
if (input[i] == '(')
{
bracketCount++;
}
else if (input[i] == ')')
{
bracketCount--;
if (bracketCount == 0)
{
return i;
}
}
}

return -1; // Unmatched brackets
}

private static string ModifyTrigFunction(string input, string function, string modification)
{
// Get the RegEx pattern to match, depending on whether the function is inverse or normal
string pattern = function.StartsWith("arc", StringComparison.Ordinal) ? string.Empty : @"(?<!c)";
pattern += $@"{function}\s*\(";

int index = 0; // Index for match to ensure that the same match is not found twice

Regex regex = new Regex(pattern);
Match match;

while ((match = regex.Match(input, index)).Success)
{
index = match.Index + match.Groups[0].Length + modification.Length; // Get the next index to look from for further matches

int endIndex = FindClosingBracketIndex(input, match.Index + match.Groups[0].Length - 1); // Find the index of the closing bracket of the function

// If no valid bracket index was found, try the next match
if (endIndex == -1)
{
continue;
}

string argument = input.Substring(match.Index + match.Groups[0].Length, endIndex - (match.Index + match.Groups[0].Length)); // Extract the argument between the brackets
string replaced = function.StartsWith("arc", StringComparison.Ordinal) ? $"{modification}({match.Groups[0].Value}{argument}))" : $"{match.Groups[0].Value}{modification}({argument}))"; // The string to substitute in, handles differing formats of inverse functions

input = input.Remove(match.Index, endIndex - match.Index + 1); // Remove the match from the input
input = input.Insert(match.Index, replaced); // Substitute with the new string
}

return input;
}

public static string UpdateTrigFunctions(string input, CalculateEngine.TrigMode mode)
{
string modifiedInput = input;
if (mode == CalculateEngine.TrigMode.Degrees)
{
modifiedInput = ModifyTrigFunction(modifiedInput, "sin", DegToRad);
modifiedInput = ModifyTrigFunction(modifiedInput, "cos", DegToRad);
modifiedInput = ModifyTrigFunction(modifiedInput, "tan", DegToRad);
modifiedInput = ModifyTrigFunction(modifiedInput, "arcsin", RadToDeg);
modifiedInput = ModifyTrigFunction(modifiedInput, "arccos", RadToDeg);
modifiedInput = ModifyTrigFunction(modifiedInput, "arctan", RadToDeg);
}
else if (mode == CalculateEngine.TrigMode.Gradians)

Check warning on line 281 in src/modules/launcher/Plugins/Microsoft.PowerToys.Run.Plugin.Calculator/CalculateHelper.cs

View workflow job for this annotation

GitHub Actions / Check Spelling

`Gradians` is not a recognized word. (unrecognized-spelling)
{
modifiedInput = ModifyTrigFunction(modifiedInput, "sin", GradToRad);
modifiedInput = ModifyTrigFunction(modifiedInput, "cos", GradToRad);
modifiedInput = ModifyTrigFunction(modifiedInput, "tan", GradToRad);
modifiedInput = ModifyTrigFunction(modifiedInput, "arcsin", RadToGrad);
modifiedInput = ModifyTrigFunction(modifiedInput, "arccos", RadToGrad);
modifiedInput = ModifyTrigFunction(modifiedInput, "arctan", RadToGrad);
}

return modifiedInput;
}
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -21,6 +21,7 @@
private const string InputUseEnglishFormat = nameof(InputUseEnglishFormat);
private const string OutputUseEnglishFormat = nameof(OutputUseEnglishFormat);
private const string ReplaceInput = nameof(ReplaceInput);
private const string TrigMode = nameof(TrigMode);

private static readonly CalculateEngine CalculateEngine = new CalculateEngine();

Expand All @@ -31,6 +32,7 @@
private bool _inputUseEnglishFormat;
private bool _outputUseEnglishFormat;
private bool _replaceInput;
private static CalculateEngine.TrigMode _trigMode;

public string Name => Resources.wox_plugin_calculator_plugin_name;

Expand Down Expand Up @@ -67,6 +69,20 @@
DisplayDescription = Resources.wox_plugin_calculator_replace_input_description,
Value = true,
},
new PluginAdditionalOption
{
Key = TrigMode,
DisplayLabel = Resources.wox_plugin_calculator_trig_unit_mode,
DisplayDescription = Resources.wox_plugin_calculator_trig_unit_mode_description,
PluginOptionType = PluginAdditionalOption.AdditionalOptionType.Combobox,
ComboBoxValue = (int)CalculateEngine.TrigMode.Radians,
ComboBoxItems =
[
new KeyValuePair<string, string>(Resources.wox_plugin_calculator_trig_unit_radians, "0"),
new KeyValuePair<string, string>(Resources.wox_plugin_calculator_trig_unit_degrees, "1"),
new KeyValuePair<string, string>(Resources.wox_plugin_calculator_trig_unit_gradians, "2"),

Check warning on line 83 in src/modules/launcher/Plugins/Microsoft.PowerToys.Run.Plugin.Calculator/Main.cs

View workflow job for this annotation

GitHub Actions / Check Spelling

`gradians` is not a recognized word. (unrecognized-spelling)
],
},
};

public List<Result> Query(Query query)
Expand Down Expand Up @@ -183,6 +199,7 @@
var inputUseEnglishFormat = false;
var outputUseEnglishFormat = false;
var replaceInput = true;
var trigMode = CalculateEngine.TrigMode.Radians;

if (settings != null && settings.AdditionalOptions != null)
{
Expand All @@ -194,11 +211,20 @@

var optionReplaceInput = settings.AdditionalOptions.FirstOrDefault(x => x.Key == ReplaceInput);
replaceInput = optionReplaceInput?.Value ?? replaceInput;

var optionTrigMode = settings.AdditionalOptions.FirstOrDefault(x => x.Key == TrigMode);
trigMode = (CalculateEngine.TrigMode)int.Parse(optionTrigMode.ComboBoxValue.ToString(CultureInfo.InvariantCulture), CultureInfo.InvariantCulture);
}

_inputUseEnglishFormat = inputUseEnglishFormat;
_outputUseEnglishFormat = outputUseEnglishFormat;
_replaceInput = replaceInput;
_trigMode = trigMode;
}

public static CalculateEngine.TrigMode GetTrigMode()
{
return _trigMode;
}

public void Dispose()
Expand Down

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

Original file line number Diff line number Diff line change
Expand Up @@ -167,4 +167,24 @@
<data name="wox_plugin_calculator_replace_input_description" xml:space="preserve">
<value>When using direct activation, appending '=' to the expression will replace the input with the calculated result (e.g. '=5*3-2=' will change the query to '=13').</value>
</data>
<data name="wox_plugin_calculator_trig_unit_mode" xml:space="preserve">
<value>Trigonometry Unit</value>
<comment>Title text for trig unit mode.</comment>
</data>
<data name="wox_plugin_calculator_trig_unit_mode_description" xml:space="preserve">
<value>Specifies the angle unit to use for trigonometry operations.</value>
OldUser101 marked this conversation as resolved.
Show resolved Hide resolved
<comment>Description text for trig mode setting.</comment>
</data>
<data name="wox_plugin_calculator_trig_unit_radians" xml:space="preserve">
<value>Radians</value>
<comment>Text for angle unit.</comment>
</data>
<data name="wox_plugin_calculator_trig_unit_degrees" xml:space="preserve">
<value>Degrees</value>
<comment>Text to use for angle unit.</comment>
</data>
<data name="wox_plugin_calculator_trig_unit_gradians" xml:space="preserve">

Check warning on line 186 in src/modules/launcher/Plugins/Microsoft.PowerToys.Run.Plugin.Calculator/Properties/Resources.resx

View workflow job for this annotation

GitHub Actions / Check Spelling

`gradians` is not a recognized word. (unrecognized-spelling)
<value>Gradians</value>
<comment>Text for angle unit.</comment>
</data>
</root>
Loading