diff --git a/src/CalcManager/CalcManager.vcxproj b/src/CalcManager/CalcManager.vcxproj index 00803dca..a0ee84ed 100644 --- a/src/CalcManager/CalcManager.vcxproj +++ b/src/CalcManager/CalcManager.vcxproj @@ -45,7 +45,7 @@ true Windows Store 10.0 - 10.0.18970.0 + 10.0.19019.0 10.0.17134.0 diff --git a/src/CalcViewModel/CalcViewModel.vcxproj b/src/CalcViewModel/CalcViewModel.vcxproj index 5ca5e036..f506dff2 100644 --- a/src/CalcViewModel/CalcViewModel.vcxproj +++ b/src/CalcViewModel/CalcViewModel.vcxproj @@ -42,7 +42,7 @@ 14.0 true Windows Store - 10.0.18970.0 + 10.0.19019.0 10.0.17134.0 10.0 @@ -351,6 +351,7 @@ + diff --git a/src/CalcViewModel/CalcViewModel.vcxproj.filters b/src/CalcViewModel/CalcViewModel.vcxproj.filters index 3251ab94..3414655e 100644 --- a/src/CalcViewModel/CalcViewModel.vcxproj.filters +++ b/src/CalcViewModel/CalcViewModel.vcxproj.filters @@ -220,6 +220,9 @@ DataLoaders + + Common + diff --git a/src/CalcViewModel/GraphingCalculator/EquationViewModel.cpp b/src/CalcViewModel/GraphingCalculator/EquationViewModel.cpp index c09ff768..ae9b63f9 100644 --- a/src/CalcViewModel/GraphingCalculator/EquationViewModel.cpp +++ b/src/CalcViewModel/GraphingCalculator/EquationViewModel.cpp @@ -1,14 +1,324 @@ +// Copyright (c) Microsoft Corporation. All rights reserved. +// Licensed under the MIT License. + #include "pch.h" #include "EquationViewModel.h" +#include "CalcViewModel\Common\LocalizationSettings.h" +#include "CalcViewModel\GraphingCalculatorEnums.h" +using namespace CalculatorApp::Common; +using namespace Graphing; +using namespace Platform; +using namespace Platform::Collections; +using namespace std; using namespace Windows::UI; using namespace Windows::UI::Xaml; +using namespace Windows::Foundation::Collections; namespace CalculatorApp::ViewModel { - EquationViewModel::EquationViewModel() - : m_LineColor{ nullptr }, m_KeyGraphFeaturesVisibility{ ::Visibility::Collapsed } - , m_Expression{ "" } + GridDisplayItems::GridDisplayItems() + : m_Expression{ "" } + , m_Direction{ "" } { } + + KeyGraphFeaturesItem::KeyGraphFeaturesItem() + : m_Title{ "" } + , m_DisplayItems{ ref new Vector() } + , m_GridItems{ ref new Vector() } + , m_IsText{ false } + { + } + + EquationViewModel::EquationViewModel() + : m_LineColor{ nullptr } + , m_Expression{ "" } + , m_IsAnalysisUpdated{ false } + , m_Domain{ "" } + , m_Range{ "" } + , m_XIntercept{ "" } + , m_YIntercept{ "" } + , m_Parity{ -1 } + , m_PeriodicityDirection{ -1 } + , m_PeriodicityExpression{ "" } + , m_Minima{ ref new Vector() } + , m_Maxima{ ref new Vector() } + , m_InflectionPoints{ ref new Vector() } + , m_Monotonicity{ ref new Map() } + , m_VerticalAsymptotes{ ref new Vector() } + , m_HorizontalAsymptotes{ ref new Vector() } + , m_ObliqueAsymptotes{ ref new Vector() } + , m_TooComplexFeatures{ -1 } + , m_AnalysisError{ 0 } + , m_AnalysisErrorVisible{ false } + , m_KeyGraphFeaturesItems{ ref new Vector() } + , m_resourceLoader{ Windows::ApplicationModel::Resources::ResourceLoader::GetForCurrentView() } + { + } + + void EquationViewModel::OnPropertyChanged(String ^ propertyName) + { + if (propertyName == L"IsAnalysisUpdated") + { + OnIsAnalysisUpdatedChanged(); + } + } + + void EquationViewModel::OnIsAnalysisUpdatedChanged() + { + if (IsAnalysisUpdated) + { + if (AnalysisError != 0) + { + AnalysisErrorVisible = true; + if (AnalysisError == static_cast(AnalysisErrorType::AnalysisCouldNotBePerformed)) + { + AnalysisErrorString = m_resourceLoader->GetString(L"KGFAnalysisCouldNotBePerformed"); + } + else if (AnalysisError == static_cast(AnalysisErrorType::AnalysisNotSupported)) + { + AnalysisErrorString = m_resourceLoader->GetString(L"KGFAnalysisNotSupported"); + } + return; + } + KeyGraphFeaturesItems->Clear(); + SetKeyGraphFeaturesItems(m_resourceLoader->GetString(L"Domain"), Domain, m_resourceLoader->GetString(L"KGFDomainNone")); + SetKeyGraphFeaturesItems(m_resourceLoader->GetString(L"Range"), Range, m_resourceLoader->GetString(L"KGFRangeNone")); + SetKeyGraphFeaturesItems(m_resourceLoader->GetString(L"XIntercept"), XIntercept, m_resourceLoader->GetString(L"KGFXInterceptNone")); + SetKeyGraphFeaturesItems(m_resourceLoader->GetString(L"YIntercept"), YIntercept, m_resourceLoader->GetString(L"KGFYInterceptNone")); + SetKeyGraphFeaturesItems(m_resourceLoader->GetString(L"Minima"), Minima, m_resourceLoader->GetString(L"KGFMinimaNone")); + SetKeyGraphFeaturesItems(m_resourceLoader->GetString(L"Maxima"), Maxima, m_resourceLoader->GetString(L"KGFMaximaNone")); + SetKeyGraphFeaturesItems( + m_resourceLoader->GetString(L"InflectionPoints"), InflectionPoints, m_resourceLoader->GetString(L"KGFInflectionPointsNone")); + SetKeyGraphFeaturesItems( + m_resourceLoader->GetString(L"VerticalAsymptotes"), VerticalAsymptotes, m_resourceLoader->GetString(L"KGFVerticalAsymptotesNone")); + SetKeyGraphFeaturesItems( + m_resourceLoader->GetString(L"HorizontalAsymptotes"), HorizontalAsymptotes, m_resourceLoader->GetString(L"KGFHorizontalAsymptotesNone")); + SetKeyGraphFeaturesItems( + m_resourceLoader->GetString(L"ObliqueAsymptotes"), ObliqueAsymptotes, m_resourceLoader->GetString(L"KGFObliqueAsymptotesNone")); + SetParityStringProperty(); + SetPeriodicityStringProperty(); + SetMonotoncityStringProperty(); + SetTooComplexFeaturesErrorProperty(); + + AnalysisErrorVisible = false; + IsAnalysisUpdated = false; + } + } + + void EquationViewModel::SetKeyGraphFeaturesItems(String ^ title, String ^ expression, String ^ errorString) + { + KeyGraphFeaturesItem ^ item = ref new KeyGraphFeaturesItem(); + item->Title = title; + if (expression != L"") + { + item->DisplayItems->Append(expression); + item->IsText = false; + } + else + { + item->DisplayItems->Append(errorString); + item->IsText = true; + } + KeyGraphFeaturesItems->Append(item); + } + + void EquationViewModel::SetKeyGraphFeaturesItems(String ^ title, IObservableVector ^ expressionVector, String ^ errorString) + { + KeyGraphFeaturesItem ^ item = ref new KeyGraphFeaturesItem(); + item->Title = title; + if (expressionVector->Size != 0) + { + for (auto expression : expressionVector) + { + item->DisplayItems->Append(expression); + } + item->IsText = false; + } + else + { + item->DisplayItems->Append(errorString); + item->IsText = true; + } + KeyGraphFeaturesItems->Append(item); + } + + void EquationViewModel::SetParityStringProperty() + { + KeyGraphFeaturesItem ^ parityItem = ref new KeyGraphFeaturesItem(); + parityItem->Title = m_resourceLoader->GetString(L"Parity"); + switch (Parity) + { + case 0: + parityItem->DisplayItems->Append(m_resourceLoader->GetString(L"KGFParityUnknown")); + break; + case 1: + parityItem->DisplayItems->Append(m_resourceLoader->GetString(L"KGFParityOdd")); + break; + case 2: + parityItem->DisplayItems->Append(m_resourceLoader->GetString(L"KGFParityEven")); + break; + case 3: + parityItem->DisplayItems->Append(m_resourceLoader->GetString(L"KGFParityNeither")); + break; + default: + parityItem->DisplayItems->Append(m_resourceLoader->GetString(L"KGFParityUnknown")); + + } + parityItem->IsText = true; + + KeyGraphFeaturesItems->Append(parityItem); + } + + void EquationViewModel::SetPeriodicityStringProperty() + { + KeyGraphFeaturesItem ^ periodicityItem = ref new KeyGraphFeaturesItem(); + periodicityItem->Title = m_resourceLoader->GetString(L"Periodicity"); + switch (PeriodicityDirection) + { + case 0: + // Periodicity is not supported or is too complex to calculate. + // Return out of this function without adding periodicity to KeyGraphFeatureItems. + // SetTooComplexFeaturesErrorProperty will set the too complex error when periodicity is supported and unknown + return; + case 1: + if (PeriodicityExpression == L"") + { + periodicityItem->DisplayItems->Append(m_resourceLoader->GetString(L"KGFPeriodicityUnknown")); + periodicityItem->IsText = true; + } + else + { + periodicityItem->DisplayItems->Append(PeriodicityExpression); + periodicityItem->IsText = false; + } + break; + case 2: + periodicityItem->DisplayItems->Append(m_resourceLoader->GetString(L"KGFPeriodicityNotPeriodic")); + periodicityItem->IsText = false; + break; + default: + periodicityItem->DisplayItems->Append(m_resourceLoader->GetString(L"KGFPeriodicityError")); + periodicityItem->IsText = true; + } + + KeyGraphFeaturesItems->Append(periodicityItem); + } + + void EquationViewModel::SetMonotoncityStringProperty() + { + KeyGraphFeaturesItem ^ monotonicityItem = ref new KeyGraphFeaturesItem(); + monotonicityItem->Title = m_resourceLoader->GetString(L"Monotonicity"); + if (Monotonicity->Size != 0) + { + for (auto item : Monotonicity) + { + GridDisplayItems ^ gridItem = ref new GridDisplayItems(); + gridItem->Expression = item->Key; + + auto monotonicityType = item->Value->Data(); + switch (*monotonicityType) + { + case '0': + gridItem->Direction = m_resourceLoader->GetString(L"KGFMonotonicityUnknown"); + break; + case '1': + gridItem->Direction = m_resourceLoader->GetString(L"KGFMonotonicityIncreasing"); + break; + case '2': + gridItem->Direction = m_resourceLoader->GetString(L"KGFMonotonicityDecreasing"); + break; + case '3': + gridItem->Direction = m_resourceLoader->GetString(L"KGFMonotonicityConstant"); + break; + default: + gridItem->Direction = m_resourceLoader->GetString(L"KGFMonotonicityError"); + break; + } + + monotonicityItem->GridItems->Append(gridItem); + } + monotonicityItem->IsText = false; + } + else + { + monotonicityItem->DisplayItems->Append(m_resourceLoader->GetString(L"KGFMonotonicityError")); + monotonicityItem->IsText = true; + } + + KeyGraphFeaturesItems->Append(monotonicityItem); + } + + void EquationViewModel::SetTooComplexFeaturesErrorProperty() + { + if (TooComplexFeatures <= 0) + { + return; + } + + Platform::String ^ separator = ref new String(LocalizationSettings::GetInstance().GetListSeparator().c_str()); + + wstring error; + if ((TooComplexFeatures & KeyGraphFeaturesFlag::Domain) == KeyGraphFeaturesFlag::Domain) + { + error.append((m_resourceLoader->GetString(L"Domain") + separator + L" ")->Data()); + } + if ((TooComplexFeatures & KeyGraphFeaturesFlag::Range) == KeyGraphFeaturesFlag::Range) + { + error.append((m_resourceLoader->GetString(L"Range") + separator + L" ")->Data()); + } + if ((TooComplexFeatures & KeyGraphFeaturesFlag::Zeros) == KeyGraphFeaturesFlag::Zeros) + { + error.append((m_resourceLoader->GetString(L"XIntercept") + separator + L" ")->Data()); + } + if ((TooComplexFeatures & KeyGraphFeaturesFlag::YIntercept) == KeyGraphFeaturesFlag::YIntercept) + { + error.append((m_resourceLoader->GetString(L"YIntercept") + separator + L" ")->Data()); + } + if ((TooComplexFeatures & KeyGraphFeaturesFlag::Parity) == KeyGraphFeaturesFlag::Parity) + { + error.append((m_resourceLoader->GetString(L"Parity") + separator + L" ")->Data()); + } + if ((TooComplexFeatures & KeyGraphFeaturesFlag::Periodicity) == KeyGraphFeaturesFlag::Periodicity) + { + error.append((m_resourceLoader->GetString(L"Periodicity") + separator + L" ")->Data()); + } + if ((TooComplexFeatures & KeyGraphFeaturesFlag::Minima) == KeyGraphFeaturesFlag::Minima) + { + error.append((m_resourceLoader->GetString(L"Minima") + separator + L" ")->Data()); + } + if ((TooComplexFeatures & KeyGraphFeaturesFlag::Maxima) == KeyGraphFeaturesFlag::Maxima) + { + error.append((m_resourceLoader->GetString(L"Maxima") + separator + L" ")->Data()); + } + if ((TooComplexFeatures & KeyGraphFeaturesFlag::InflectionPoints) == KeyGraphFeaturesFlag::InflectionPoints) + { + error.append((m_resourceLoader->GetString(L"InflectionPoints") + separator + L" ")->Data()); + } + if ((TooComplexFeatures & KeyGraphFeaturesFlag::VerticalAsymptotes) == KeyGraphFeaturesFlag::VerticalAsymptotes) + { + error.append((m_resourceLoader->GetString(L"VerticalAsymptotes") + separator + L" ")->Data()); + } + if ((TooComplexFeatures & KeyGraphFeaturesFlag::HorizontalAsymptotes) == KeyGraphFeaturesFlag::HorizontalAsymptotes) + { + error.append((m_resourceLoader->GetString(L"HorizontalAsymptotes") + separator + L" ")->Data()); + } + if ((TooComplexFeatures & KeyGraphFeaturesFlag::ObliqueAsymptotes) == KeyGraphFeaturesFlag::ObliqueAsymptotes) + { + error.append((m_resourceLoader->GetString(L"ObliqueAsymptotes") + separator + L" ")->Data()); + } + if ((TooComplexFeatures & KeyGraphFeaturesFlag::MonotoneIntervals) == KeyGraphFeaturesFlag::MonotoneIntervals) + { + error.append((m_resourceLoader->GetString(L"Monotonicity") + separator + L" ")->Data()); + } + + KeyGraphFeaturesItem ^ tooComplexItem = ref new KeyGraphFeaturesItem(); + tooComplexItem->DisplayItems->Append(m_resourceLoader->GetString(L"KGFTooComplexFeaturesError")); + tooComplexItem->DisplayItems->Append(ref new String(error.substr(0, (error.length() - (separator->Length() + 1))).c_str())); + tooComplexItem->IsText = true; + + KeyGraphFeaturesItems->Append(tooComplexItem); + } + } diff --git a/src/CalcViewModel/GraphingCalculator/EquationViewModel.h b/src/CalcViewModel/GraphingCalculator/EquationViewModel.h index ce0d37e9..8f7a0db0 100644 --- a/src/CalcViewModel/GraphingCalculator/EquationViewModel.h +++ b/src/CalcViewModel/GraphingCalculator/EquationViewModel.h @@ -1,17 +1,96 @@ +// Copyright (c) Microsoft Corporation. All rights reserved. +// Licensed under the MIT License. + #pragma once #include "../Common/Utils.h" namespace CalculatorApp::ViewModel { - public ref class EquationViewModel sealed : public Windows::UI::Xaml::Data::INotifyPropertyChanged +public + ref class GridDisplayItems sealed : public Windows::UI::Xaml::Data::INotifyPropertyChanged + { + public: + GridDisplayItems(); + + OBSERVABLE_OBJECT(); + OBSERVABLE_PROPERTY_RW(Platform::String ^, Expression); + OBSERVABLE_PROPERTY_RW(Platform::String ^, Direction); + }; + +public + ref class KeyGraphFeaturesItem sealed : public Windows::UI::Xaml::Data::INotifyPropertyChanged + { + public: + KeyGraphFeaturesItem(); + + OBSERVABLE_OBJECT(); + OBSERVABLE_PROPERTY_RW(Platform::String ^, Title); + OBSERVABLE_PROPERTY_RW(Windows::Foundation::Collections::IObservableVector ^, DisplayItems); + OBSERVABLE_PROPERTY_RW(Windows::Foundation::Collections::IObservableVector ^, GridItems); + OBSERVABLE_PROPERTY_RW(bool, IsText); + }; + + +public + ref class EquationViewModel sealed : public Windows::UI::Xaml::Data::INotifyPropertyChanged { public: EquationViewModel(); - OBSERVABLE_OBJECT(); - OBSERVABLE_PROPERTY_RW(Platform::String^, Expression); + OBSERVABLE_OBJECT_CALLBACK(OnPropertyChanged); + OBSERVABLE_PROPERTY_RW(Platform::String ^, Expression); OBSERVABLE_PROPERTY_RW(Windows::UI::Xaml::Media::SolidColorBrush ^, LineColor); - OBSERVABLE_PROPERTY_RW(Windows::UI::Xaml::Visibility, KeyGraphFeaturesVisibility); + + // Key Graph Features + OBSERVABLE_PROPERTY_RW_ALWAYS_NOTIFY(bool, IsAnalysisUpdated); + OBSERVABLE_PROPERTY_RW(Platform::String ^, Domain); + OBSERVABLE_PROPERTY_RW(Platform::String ^, Range); + OBSERVABLE_PROPERTY_RW(Platform::String ^, XIntercept); + OBSERVABLE_PROPERTY_RW(Platform::String ^, YIntercept); + OBSERVABLE_PROPERTY_RW(int, Parity); + OBSERVABLE_PROPERTY_RW(int, PeriodicityDirection); + OBSERVABLE_PROPERTY_RW(Platform::String ^, PeriodicityExpression); + OBSERVABLE_PROPERTY_RW(Windows::Foundation::Collections::IObservableVector ^, Minima); + OBSERVABLE_PROPERTY_RW(Windows::Foundation::Collections::IObservableVector ^, Maxima); + OBSERVABLE_PROPERTY_RW(Windows::Foundation::Collections::IObservableVector ^, InflectionPoints); + OBSERVABLE_PROPERTY_RW(Windows::Foundation::Collections::IObservableVector ^, VerticalAsymptotes); + OBSERVABLE_PROPERTY_RW(Windows::Foundation::Collections::IObservableVector ^, HorizontalAsymptotes); + OBSERVABLE_PROPERTY_RW(Windows::Foundation::Collections::IObservableVector ^, ObliqueAsymptotes); + OBSERVABLE_PROPERTY_RW(int, TooComplexFeatures); + OBSERVABLE_PROPERTY_RW(int, AnalysisError); + OBSERVABLE_PROPERTY_R(Platform::String ^, AnalysisErrorString); + OBSERVABLE_PROPERTY_R(bool, AnalysisErrorVisible); + OBSERVABLE_PROPERTY_R(Windows::Foundation::Collections::IObservableVector ^, KeyGraphFeaturesItems) + + property Windows::Foundation::Collections::IObservableMap ^ Monotonicity + { + Windows::Foundation::Collections::IObservableMap ^ get() + { + return m_Monotonicity; + } + void set(Windows::Foundation::Collections::IObservableMap ^ value) + { + if (m_Monotonicity != value) + { + m_Monotonicity = value; + } + } + } + + private: + void OnPropertyChanged(Platform::String ^ propertyName); + void SetParityStringProperty(); + void SetPeriodicityStringProperty(); + void SetKeyGraphFeaturesItems(Platform::String ^ title, Platform::String ^ expression, Platform::String ^ errorString); + void SetKeyGraphFeaturesItems(Platform::String ^ title, Windows::Foundation::Collections::IObservableVector ^ expressionVector, + Platform::String ^ errorString); + void SetMonotoncityStringProperty(); + void SetTooComplexFeaturesErrorProperty(); + void OnIsAnalysisUpdatedChanged(); + + Windows::Foundation::Collections::IObservableMap ^ m_Monotonicity; + Windows::ApplicationModel::Resources::ResourceLoader ^ m_resourceLoader; }; + } diff --git a/src/CalcViewModel/GraphingCalculator/GraphingCalculatorViewModel.cpp b/src/CalcViewModel/GraphingCalculator/GraphingCalculatorViewModel.cpp index 984678a2..07b6fc13 100644 --- a/src/CalcViewModel/GraphingCalculator/GraphingCalculatorViewModel.cpp +++ b/src/CalcViewModel/GraphingCalculator/GraphingCalculatorViewModel.cpp @@ -1,3 +1,6 @@ +// Copyright (c) Microsoft Corporation. All rights reserved. +// Licensed under the MIT License. + #include "pch.h" #include "GraphingCalculatorViewModel.h" diff --git a/src/CalcViewModel/GraphingCalculator/GraphingCalculatorViewModel.h b/src/CalcViewModel/GraphingCalculator/GraphingCalculatorViewModel.h index 2c45f077..18a60543 100644 --- a/src/CalcViewModel/GraphingCalculator/GraphingCalculatorViewModel.h +++ b/src/CalcViewModel/GraphingCalculator/GraphingCalculatorViewModel.h @@ -1,3 +1,6 @@ +// Copyright (c) Microsoft Corporation. All rights reserved. +// Licensed under the MIT License. + #pragma once #include "../Common/Utils.h" @@ -5,28 +8,29 @@ namespace CalculatorApp::ViewModel { - public value struct VariableChangedEventArgs sealed +public + value struct VariableChangedEventArgs sealed { - Platform::String^ variableName; + Platform::String ^ variableName; double newValue; }; - [Windows::UI::Xaml::Data::Bindable] - public ref class VariableViewModel sealed : public Windows::UI::Xaml::Data::INotifyPropertyChanged + [Windows::UI::Xaml::Data::Bindable] public ref class VariableViewModel sealed : public Windows::UI::Xaml::Data::INotifyPropertyChanged { public: - VariableViewModel(Platform::String^ name, double value) : - m_Name(name), - m_Value(value), - m_SliderSettingsVisible(false), - m_Min(0.0), - m_Step(0.1), - m_Max(2.0) - { } + VariableViewModel(Platform::String ^ name, double value) + : m_Name(name) + , m_Value(value) + , m_SliderSettingsVisible(false) + , m_Min(0.0) + , m_Step(0.1) + , m_Max(2.0) + { + } OBSERVABLE_OBJECT_CALLBACK(OnPropertyChanged); - OBSERVABLE_PROPERTY_R(Platform::String^, Name); + OBSERVABLE_PROPERTY_R(Platform::String ^, Name); // TODO: Consider removing this work around and manually set the textbox text. OBSERVABLE_PROPERTY_RW_ALWAYS_NOTIFY(double, Value); @@ -35,7 +39,7 @@ namespace CalculatorApp::ViewModel OBSERVABLE_PROPERTY_RW_ALWAYS_NOTIFY(double, Max); OBSERVABLE_PROPERTY_RW(bool, SliderSettingsVisible); - event Windows::Foundation::EventHandler^ VariableUpdated; + event Windows::Foundation::EventHandler ^ VariableUpdated; void SetValue(double value) { @@ -52,7 +56,7 @@ namespace CalculatorApp::ViewModel } private: - void OnPropertyChanged(Platform::String^ propertyName) + void OnPropertyChanged(Platform::String ^ propertyName) { if (propertyName == "Value") { @@ -61,23 +65,23 @@ namespace CalculatorApp::ViewModel } }; - [Windows::UI::Xaml::Data::Bindable] - public ref class GraphingCalculatorViewModel sealed : public Windows::UI::Xaml::Data::INotifyPropertyChanged + [Windows::UI::Xaml::Data::Bindable] public ref class GraphingCalculatorViewModel sealed : public Windows::UI::Xaml::Data::INotifyPropertyChanged { public: GraphingCalculatorViewModel(); OBSERVABLE_OBJECT(); OBSERVABLE_PROPERTY_R(bool, IsDecimalEnabled); - OBSERVABLE_PROPERTY_R(Windows::Foundation::Collections::IObservableVector< EquationViewModel^ >^, Equations); - OBSERVABLE_PROPERTY_R(Windows::Foundation::Collections::IObservableVector< VariableViewModel^ >^, Variables); + OBSERVABLE_PROPERTY_R(Windows::Foundation::Collections::IObservableVector ^, Equations); + OBSERVABLE_PROPERTY_R(Windows::Foundation::Collections::IObservableVector ^, Variables); COMMAND_FOR_METHOD(ButtonPressed, GraphingCalculatorViewModel::OnButtonPressed); - event Windows::Foundation::EventHandler^ VariableUpdated; + event Windows::Foundation::EventHandler ^ VariableUpdated; + + void UpdateVariables(Windows::Foundation::Collections::IMap ^ variables); - void UpdateVariables(Windows::Foundation::Collections::IMap^ variables); private: - void OnButtonPressed(Platform::Object^ parameter); + void OnButtonPressed(Platform::Object ^ parameter); }; } diff --git a/src/CalcViewModel/GraphingCalculatorEnums.h b/src/CalcViewModel/GraphingCalculatorEnums.h new file mode 100644 index 00000000..5cf136a5 --- /dev/null +++ b/src/CalcViewModel/GraphingCalculatorEnums.h @@ -0,0 +1,28 @@ +#pragma once + +namespace CalculatorApp +{ + enum KeyGraphFeaturesFlag + { + Domain = 1, + Range = 2, + Parity = 4, + Periodicity = 8, + Zeros = 16, + YIntercept = 32, + Minima = 64, + Maxima = 128, + InflectionPoints = 256, + VerticalAsymptotes = 512, + HorizontalAsymptotes = 1024, + ObliqueAsymptotes = 2048, + MonotoneIntervals = 4096 + }; + + enum AnalysisErrorType + { + NoError, + AnalysisCouldNotBePerformed, + AnalysisNotSupported + }; +} diff --git a/src/Calculator/App.xaml b/src/Calculator/App.xaml index 25e5bbfb..5f0219b2 100644 --- a/src/Calculator/App.xaml +++ b/src/Calculator/App.xaml @@ -1140,6 +1140,244 @@ + + + + - - - @@ -1479,7 +1477,6 @@ - @@ -1521,19 +1518,19 @@ - + - + @@ -192,7 +206,9 @@ - - + - + + + - - - + + - - - - - - - - + + - - - - - - - - + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/src/Calculator/Views/GraphingCalculator/KeyGraphFeaturesPanel.xaml.cpp b/src/Calculator/Views/GraphingCalculator/KeyGraphFeaturesPanel.xaml.cpp new file mode 100644 index 00000000..2f8d5535 --- /dev/null +++ b/src/Calculator/Views/GraphingCalculator/KeyGraphFeaturesPanel.xaml.cpp @@ -0,0 +1,53 @@ +// Copyright (c) Microsoft Corporation. All rights reserved. +// Licensed under the MIT License. + +#include "pch.h" +#include "KeyGraphFeaturesPanel.xaml.h" +#include "Controls/MathRichEditBox.h" +#include "CalcViewModel/GraphingCalculatorEnums.h" + +using namespace CalculatorApp; +using namespace CalculatorApp::ViewModel; +using namespace Platform; +using namespace Windows::UI; +using namespace Windows::UI::Xaml; +using namespace Windows::UI::Xaml::Controls; + +KeyGraphFeaturesPanel::KeyGraphFeaturesPanel() + +{ + + InitializeComponent(); +} + +void KeyGraphFeaturesPanel::OnPropertyChanged(String ^ propertyName) +{ + if (propertyName == L"ViewModel") + { + if (ViewModel == nullptr) + { + return; + } + + SetEquationTextBoxProperties(); + } +} + +void KeyGraphFeaturesPanel::EquationButtonClicked(Object ^ sender, RoutedEventArgs ^ e) +{ + KeyGraphFeaturesClosed(this, ref new RoutedEventArgs()); +} + +void KeyGraphFeaturesPanel::EquationInputTextBox_Loaded(Object ^ sender, RoutedEventArgs ^ e) +{ + if (ViewModel != nullptr) + { + SetEquationTextBoxProperties(); + } +} + +void KeyGraphFeaturesPanel::SetEquationTextBoxProperties() +{ + EquationInputTextBox->SetEquationText(ViewModel->Expression); + EquationInputTextBox->EquationColor = ViewModel->LineColor; +} diff --git a/src/Calculator/Views/GraphingCalculator/KeyGraphFeaturesPanel.xaml.h b/src/Calculator/Views/GraphingCalculator/KeyGraphFeaturesPanel.xaml.h new file mode 100644 index 00000000..daf15ba2 --- /dev/null +++ b/src/Calculator/Views/GraphingCalculator/KeyGraphFeaturesPanel.xaml.h @@ -0,0 +1,31 @@ +// Copyright (c) Microsoft Corporation. All rights reserved. +// Licensed under the MIT License. + +#pragma once + +#include "Views\GraphingCalculator\KeyGraphFeaturesPanel.g.h" +#include "CalcViewModel\GraphingCalculator\EquationViewModel.h" +#include "Controls/MathRichEditBox.h" +#include "Controls/EquationTextBox.h" + +namespace CalculatorApp +{ +public + ref class KeyGraphFeaturesPanel sealed : public Windows::UI::Xaml::Data::INotifyPropertyChanged + { + public: + KeyGraphFeaturesPanel(); + + OBSERVABLE_OBJECT_CALLBACK(OnPropertyChanged); + OBSERVABLE_PROPERTY_RW_ALWAYS_NOTIFY(CalculatorApp::ViewModel::EquationViewModel ^, ViewModel); + + event Windows::UI::Xaml::RoutedEventHandler ^ KeyGraphFeaturesClosed; + + private: + + void OnPropertyChanged(Platform::String ^ propertyName); + void EquationButtonClicked(Platform::Object ^ sender, Windows::UI::Xaml::RoutedEventArgs ^ e); + void SetEquationTextBoxProperties(); + void EquationInputTextBox_Loaded(Platform::Object ^ sender, Windows::UI::Xaml::RoutedEventArgs ^ e); + }; +} diff --git a/src/CalculatorUnitTests/CalculatorUnitTests.vcxproj b/src/CalculatorUnitTests/CalculatorUnitTests.vcxproj index 95094643..5fadb811 100644 --- a/src/CalculatorUnitTests/CalculatorUnitTests.vcxproj +++ b/src/CalculatorUnitTests/CalculatorUnitTests.vcxproj @@ -7,7 +7,7 @@ 15.0 true Windows Store - 10.0.18970.0 + 10.0.19019.0 10.0.17134.0 10.0 15.0 diff --git a/src/GraphControl/Control/Equation.cpp b/src/GraphControl/Control/Equation.cpp index 945949a2..2825290d 100644 --- a/src/GraphControl/Control/Equation.cpp +++ b/src/GraphControl/Control/Equation.cpp @@ -3,6 +3,7 @@ #include "pch.h" #include "Equation.h" +using namespace winrt::Windows::Foundation::Collections; using namespace Platform; using namespace std; @@ -16,16 +17,84 @@ namespace GraphControl // Remove mml: formatting specific to RichEditBox control, which is not understood by the graph engine. static constexpr wstring_view s_mathPrefix = L"mml:"; - DependencyProperty^ Equation::s_expressionProperty; + DependencyProperty ^ Equation::s_expressionProperty; static constexpr auto s_propertyName_Expression = L"Expression"; - DependencyProperty^ Equation::s_lineColorProperty; + DependencyProperty ^ Equation::s_lineColorProperty; static constexpr auto s_propertyName_LineColor = L"LineColor"; + DependencyProperty ^ Equation::s_isAnalysisUpdatedProperty; + static constexpr auto s_propertyName_IsAnalysisUpdated = L"IsAnalysisUpdated"; + + DependencyProperty ^ Equation::s_xInterceptProperty; + static constexpr auto s_propertyName_XIntercept = L"XIntercept"; + + DependencyProperty ^ Equation::s_yInterceptProperty; + static constexpr auto s_propertyName_YIntercept = L"YIntercept"; + + DependencyProperty ^ Equation::s_parityProperty; + static constexpr auto s_propertyName_Parity = L"Parity"; + + DependencyProperty ^ Equation::s_periodicityDirectionProperty; + static constexpr auto s_propertyName_PeriodicityDirection = L"PeriodicityDirection"; + + DependencyProperty ^ Equation::s_periodicityExpressionProperty; + static constexpr auto s_propertyName_PeriodicityExpression = L"PeriodicityExpression"; + + DependencyProperty ^ Equation::s_minimaProperty; + static constexpr auto s_propertyName_Minima = L"Minima"; + + DependencyProperty ^ Equation::s_maximaProperty; + static constexpr auto s_propertyName_Maxima = L"Maxima"; + + DependencyProperty ^ Equation::s_domainProperty; + static constexpr auto s_propertyName_Domain = L"Domain"; + + DependencyProperty ^ Equation::s_rangeProperty; + static constexpr auto s_propertyName_Range = L"Range"; + + DependencyProperty ^ Equation::s_inflectionPointsProperty; + static constexpr auto s_propertyName_InflectionPoints = L"InflectionPoints"; + + DependencyProperty ^ Equation::s_monotonicityProperty; + static constexpr auto s_propertyName_Monotonicity = L"Monotonicity"; + + DependencyProperty ^ Equation::s_verticalAsymptotesProperty; + static constexpr auto s_propertyName_VerticalAsymptotes = L"VerticalAsymptotes"; + + DependencyProperty ^ Equation::s_horizontalAsymptotesProperty; + static constexpr auto s_propertyName_HorizontalAsymptotes = L"HorizontalAsymptotes"; + + DependencyProperty ^ Equation::s_obliqueAsymptotesProperty; + static constexpr auto s_propertyName_ObliqueAsymptotes = L"ObliqueAsymptotes"; + + DependencyProperty ^ Equation::s_tooComplexFeaturesProperty; + static constexpr auto s_propertyName_TooComplexFeatures = L"TooComplexFeatures"; + + DependencyProperty ^ Equation::s_analysisErrorProperty; + static constexpr auto s_propertyName_AnalysisError = L"AnalysisError"; + namespace EquationProperties { - String^ Expression = StringReference(s_propertyName_Expression); - String^ LineColor = StringReference(s_propertyName_LineColor); + String ^ Expression = StringReference(s_propertyName_Expression); + String ^ LineColor = StringReference(s_propertyName_LineColor); + String ^ IsAnalysisUpdated = StringReference(s_propertyName_IsAnalysisUpdated); + String ^ XIntercept = StringReference(s_propertyName_XIntercept); + String ^ YIntercept = StringReference(s_propertyName_YIntercept); + String ^ Parity = StringReference(s_propertyName_Parity); + String ^ PeriodicityDirection = StringReference(s_propertyName_PeriodicityDirection); + String ^ PeriodicityExpression = StringReference(s_propertyName_PeriodicityExpression); + String ^ Minima = StringReference(s_propertyName_Minima); + String ^ Maxima = StringReference(s_propertyName_Maxima); + String ^ Domain = StringReference(s_propertyName_Domain); + String ^ Range = StringReference(s_propertyName_Range); + String ^ InflectionPoints = StringReference(s_propertyName_InflectionPoints); + String ^ Monotonicity = StringReference(s_propertyName_Monotonicity); + String ^ VerticalAsymptotes = StringReference(s_propertyName_VerticalAsymptotes); + String ^ HorizontalAsymptotes = StringReference(s_propertyName_HorizontalAsymptotes); + String ^ ObliqueAsymptotes = StringReference(s_propertyName_ObliqueAsymptotes); + String ^ TooComplexFeatures = StringReference(s_propertyName_TooComplexFeatures); + String ^ AnalysisError = StringReference(s_propertyName_AnalysisError); } void Equation::RegisterDependencyProperties() @@ -36,9 +105,7 @@ namespace GraphControl EquationProperties::Expression, String::typeid, Equation::typeid, - ref new PropertyMetadata( - nullptr, - ref new PropertyChangedCallback(&Equation::OnCustomDependencyPropertyChanged))); + ref new PropertyMetadata(nullptr, ref new PropertyChangedCallback(&Equation::OnCustomDependencyPropertyChanged))); } if (!s_lineColorProperty) @@ -50,17 +117,167 @@ namespace GraphControl EquationProperties::LineColor, SolidColorBrush::typeid, Equation::typeid, - ref new PropertyMetadata( - nullptr, - ref new PropertyChangedCallback(&Equation::OnCustomDependencyPropertyChanged))); + ref new PropertyMetadata(nullptr, ref new PropertyChangedCallback(&Equation::OnCustomDependencyPropertyChanged))); + } + + if (!s_isAnalysisUpdatedProperty) + { + s_isAnalysisUpdatedProperty = DependencyProperty::Register( + EquationProperties::IsAnalysisUpdated, + bool ::typeid, + Equation::typeid, + ref new PropertyMetadata(nullptr, ref new PropertyChangedCallback(&Equation::OnCustomDependencyPropertyChanged))); + } + + if (!s_xInterceptProperty) + { + s_xInterceptProperty = DependencyProperty::Register( + EquationProperties::XIntercept, + String::typeid, + Equation::typeid, + ref new PropertyMetadata(nullptr, ref new PropertyChangedCallback(&Equation::OnCustomDependencyPropertyChanged))); + } + + if (!s_yInterceptProperty) + { + s_yInterceptProperty = DependencyProperty::Register( + EquationProperties::YIntercept, + String::typeid, + Equation::typeid, + ref new PropertyMetadata(nullptr, ref new PropertyChangedCallback(&Equation::OnCustomDependencyPropertyChanged))); + } + + if (!s_parityProperty) + { + s_parityProperty = DependencyProperty::Register( + EquationProperties::Parity, + int ::typeid, + Equation::typeid, + ref new PropertyMetadata(nullptr, ref new PropertyChangedCallback(&Equation::OnCustomDependencyPropertyChanged))); + } + + if (!s_periodicityDirectionProperty) + { + s_periodicityDirectionProperty = DependencyProperty::Register( + EquationProperties::PeriodicityDirection, + int ::typeid, + Equation::typeid, + ref new PropertyMetadata(nullptr, ref new PropertyChangedCallback(&Equation::OnCustomDependencyPropertyChanged))); + } + + if (!s_periodicityExpressionProperty) + { + s_periodicityExpressionProperty = DependencyProperty::Register( + EquationProperties::PeriodicityExpression, + String::typeid, + Equation::typeid, + ref new PropertyMetadata(nullptr, ref new PropertyChangedCallback(&Equation::OnCustomDependencyPropertyChanged))); + } + + if (!s_minimaProperty) + { + s_minimaProperty = DependencyProperty::Register( + EquationProperties::Minima, + IObservableVector::typeid, + Equation::typeid, + ref new PropertyMetadata(nullptr, ref new PropertyChangedCallback(&Equation::OnCustomDependencyPropertyChanged))); + } + + if (!s_maximaProperty) + { + s_maximaProperty = DependencyProperty::Register( + EquationProperties::Maxima, + IObservableVector::typeid, + Equation::typeid, + ref new PropertyMetadata(nullptr, ref new PropertyChangedCallback(&Equation::OnCustomDependencyPropertyChanged))); + } + + if (!s_domainProperty) + { + s_domainProperty = DependencyProperty::Register( + EquationProperties::Domain, + String::typeid, + Equation::typeid, + ref new PropertyMetadata(nullptr, ref new PropertyChangedCallback(&Equation::OnCustomDependencyPropertyChanged))); + } + + if (!s_rangeProperty) + { + s_rangeProperty = DependencyProperty::Register( + EquationProperties::Range, + String::typeid, + Equation::typeid, + ref new PropertyMetadata(nullptr, ref new PropertyChangedCallback(&Equation::OnCustomDependencyPropertyChanged))); + } + + if (!s_inflectionPointsProperty) + { + s_inflectionPointsProperty = DependencyProperty::Register( + EquationProperties::InflectionPoints, + IObservableVector::typeid, + Equation::typeid, + ref new PropertyMetadata(nullptr, ref new PropertyChangedCallback(&Equation::OnCustomDependencyPropertyChanged))); + } + + if (!s_monotonicityProperty) + { + s_monotonicityProperty = DependencyProperty::Register( + EquationProperties::Monotonicity, + IObservableMap::typeid, + Equation::typeid, + ref new PropertyMetadata(nullptr, ref new PropertyChangedCallback(&Equation::OnCustomDependencyPropertyChanged))); + } + + if (!s_verticalAsymptotesProperty) + { + s_verticalAsymptotesProperty = DependencyProperty::Register( + EquationProperties::VerticalAsymptotes, + IObservableVector::typeid, + Equation::typeid, + ref new PropertyMetadata(nullptr, ref new PropertyChangedCallback(&Equation::OnCustomDependencyPropertyChanged))); + } + + if (!s_horizontalAsymptotesProperty) + { + s_horizontalAsymptotesProperty = DependencyProperty::Register( + EquationProperties::HorizontalAsymptotes, + IObservableVector::typeid, + Equation::typeid, + ref new PropertyMetadata(nullptr, ref new PropertyChangedCallback(&Equation::OnCustomDependencyPropertyChanged))); + } + + if (!s_obliqueAsymptotesProperty) + { + s_obliqueAsymptotesProperty = DependencyProperty::Register( + EquationProperties::ObliqueAsymptotes, + IObservableVector::typeid, + Equation::typeid, + ref new PropertyMetadata(nullptr, ref new PropertyChangedCallback(&Equation::OnCustomDependencyPropertyChanged))); + } + if (!s_tooComplexFeaturesProperty) + { + s_tooComplexFeaturesProperty = DependencyProperty::Register( + EquationProperties::TooComplexFeatures, + int ::typeid, + Equation::typeid, + ref new PropertyMetadata(nullptr, ref new PropertyChangedCallback(&Equation::OnCustomDependencyPropertyChanged))); + } + + if (!s_analysisErrorProperty) + { + s_analysisErrorProperty = DependencyProperty::Register( + EquationProperties::AnalysisError, + int ::typeid, + Equation::typeid, + ref new PropertyMetadata(nullptr, ref new PropertyChangedCallback(&Equation::OnCustomDependencyPropertyChanged))); } } - void Equation::OnCustomDependencyPropertyChanged(DependencyObject^ obj, DependencyPropertyChangedEventArgs^ args) + void Equation::OnCustomDependencyPropertyChanged(DependencyObject ^ obj, DependencyPropertyChangedEventArgs ^ args) { - if (auto eq = static_cast(obj)) + if (auto eq = static_cast(obj)) { - String^ propertyName = nullptr; + String ^ propertyName = nullptr; if (args->Property == s_expressionProperty) { propertyName = EquationProperties::Expression; @@ -69,6 +286,74 @@ namespace GraphControl { propertyName = EquationProperties::LineColor; } + else if (args->Property == s_isAnalysisUpdatedProperty) + { + propertyName = EquationProperties::IsAnalysisUpdated; + } + else if (args->Property == s_xInterceptProperty) + { + propertyName = EquationProperties::XIntercept; + } + else if (args->Property == s_yInterceptProperty) + { + propertyName = EquationProperties::YIntercept; + } + else if (args->Property == s_parityProperty) + { + propertyName = EquationProperties::Parity; + } + else if (args->Property == s_periodicityDirectionProperty) + { + propertyName = EquationProperties::PeriodicityDirection; + } + else if (args->Property == s_periodicityExpressionProperty) + { + propertyName = EquationProperties::PeriodicityExpression; + } + else if (args->Property == s_minimaProperty) + { + propertyName = EquationProperties::Minima; + } + else if (args->Property == s_maximaProperty) + { + propertyName = EquationProperties::Maxima; + } + else if (args->Property == s_domainProperty) + { + propertyName = EquationProperties::Domain; + } + else if (args->Property == s_rangeProperty) + { + propertyName = EquationProperties::Range; + } + else if (args->Property == s_inflectionPointsProperty) + { + propertyName = EquationProperties::InflectionPoints; + } + else if (args->Property == s_monotonicityProperty) + { + propertyName = EquationProperties::Monotonicity; + } + else if (args->Property == s_verticalAsymptotesProperty) + { + propertyName = EquationProperties::VerticalAsymptotes; + } + else if (args->Property == s_horizontalAsymptotesProperty) + { + propertyName = EquationProperties::HorizontalAsymptotes; + } + else if (args->Property == s_obliqueAsymptotesProperty) + { + propertyName = EquationProperties::ObliqueAsymptotes; + } + else if (args->Property == s_tooComplexFeaturesProperty) + { + propertyName = EquationProperties::TooComplexFeatures; + } + else if (args->Property == s_analysisErrorProperty) + { + propertyName = EquationProperties::AnalysisError; + } eq->PropertyChanged(eq, propertyName); } @@ -77,10 +362,7 @@ namespace GraphControl wstring Equation::GetRequest() { wstringstream ss{}; - ss << GetRequestHeader() - << GetExpression() - << GetLineColor() - << L""; + ss << GetRequestHeader() << GetExpression() << GetLineColor() << L""; return ss.str(); } diff --git a/src/GraphControl/Control/Equation.h b/src/GraphControl/Control/Equation.h index 1247b42d..b575a2f8 100644 --- a/src/GraphControl/Control/Equation.h +++ b/src/GraphControl/Control/Equation.h @@ -17,6 +17,7 @@ namespace GraphControl [Windows::UI::Xaml::Data::Bindable] public ref class Equation sealed : public Windows::UI::Xaml::FrameworkElement { public: + Equation() { } @@ -60,17 +61,373 @@ namespace GraphControl } void set(Windows::UI::Xaml::Media::SolidColorBrush^ value) { - if (value == nullptr || LineColor == nullptr || (value->Color.A != LineColor->Color.A) || (value->Color.R != LineColor->Color.R) || (value->Color.G != LineColor->Color.G) - || (value->Color.B != LineColor->Color.B)) - { - SetValue(s_lineColorProperty, value); - } + if (value == nullptr || LineColor == nullptr || (value->Color.A != LineColor->Color.A) || (value->Color.R != LineColor->Color.R) + || (value->Color.G != LineColor->Color.G) || (value->Color.B != LineColor->Color.B)) + SetValue(s_lineColorProperty, value); } } #pragma endregion - internal: - event PropertyChangedEventHandler^ PropertyChanged; +#pragma region Key Graph Features + + #pragma region bool IsAnalysisUpdated DependencyProperty + static property Windows::UI::Xaml::DependencyProperty^ IsAnalysisUpdatedProperty + { + Windows::UI::Xaml::DependencyProperty^ get() + { + return s_isAnalysisUpdatedProperty; + } + } + property bool IsAnalysisUpdated + { + bool get() + { + return static_cast(GetValue(s_isAnalysisUpdatedProperty)); + } + void set(bool value) + { + SetValue(s_isAnalysisUpdatedProperty, value); + } + } +#pragma endregion +#pragma region Platform::String ^ XIntercept DependencyProperty + static property Windows::UI::Xaml::DependencyProperty^ XInterceptProperty + { + Windows::UI::Xaml::DependencyProperty^ get() + { + return s_xInterceptProperty; + } + } + property Platform::String^ XIntercept + { + Platform::String^ get() + { + return static_cast(GetValue(s_xInterceptProperty)); + } + void set(Platform::String^ value) + { + SetValue(s_xInterceptProperty, value); + } + } +#pragma endregion + +#pragma region Platform::String ^ YIntercept DependencyProperty + static property Windows::UI::Xaml::DependencyProperty^ YInterceptProperty + { + Windows::UI::Xaml::DependencyProperty^ get() + { + return s_yInterceptProperty; + } + } + property Platform::String^ YIntercept + { + Platform::String^ get() + { + return static_cast(GetValue(s_yInterceptProperty)); + } + void set(Platform::String^ value) + { + SetValue(s_yInterceptProperty, value); + } + } +#pragma endregion + +#pragma region int Parity DependencyProperty + static property Windows::UI::Xaml::DependencyProperty^ ParityProperty + { + Windows::UI::Xaml::DependencyProperty^ get() + { + return s_parityProperty; + } + } + property int Parity + { + int get() + { + return static_cast(GetValue(s_parityProperty)); + } + void set(int value) + { + SetValue(s_parityProperty, value); + } + } +#pragma endregion + +#pragma region int Periodicity DependencyProperty + static property Windows::UI::Xaml::DependencyProperty^ PeriodicityDirectionProperty + { + Windows::UI::Xaml::DependencyProperty^ get() + { + return s_periodicityDirectionProperty; + } + } + property int PeriodicityDirection + { + int get() + { + return static_cast(GetValue(s_periodicityDirectionProperty)); + } + void set(int value) + { + SetValue(s_periodicityDirectionProperty, value); + } + } +#pragma endregion + + #pragma region Platform::String ^ PeriodicityExpression DependencyProperty + static property Windows::UI::Xaml::DependencyProperty^ PeriodicityExpressionProperty + { + Windows::UI::Xaml::DependencyProperty^ get() + { + return s_periodicityExpressionProperty; + } + } + property Platform::String ^ PeriodicityExpression + { + Platform::String ^ get() + { + return static_cast(GetValue(s_periodicityExpressionProperty)); + } + void set(Platform::String ^ value) + { + SetValue(s_periodicityExpressionProperty, value); + } + } +#pragma endregion + +#pragma region Windows::Foundation::Collections::IVector < Platform::String ^ > ^ Minima DependencyProperty + static property Windows::UI::Xaml::DependencyProperty^ MinimaProperty + { + Windows::UI::Xaml::DependencyProperty^ get() + { + return s_minimaProperty; + } + } + property Windows::Foundation::Collections::IVector ^ Minima + { + Windows::Foundation::Collections::IVector ^ get() + { + return static_cast ^>(GetValue(s_minimaProperty)); + } + void set(Windows::Foundation::Collections::IVector ^ value) + { + SetValue(s_minimaProperty, value); + } + } +#pragma endregion + +#pragma region Windows::Foundation::Collections::IVector < Platform::String ^ > ^ Maxima DependencyProperty + static property Windows::UI::Xaml::DependencyProperty^ MaximaProperty + { + Windows::UI::Xaml::DependencyProperty^ get() + { + return s_maximaProperty; + } + } + property Windows::Foundation::Collections::IVector ^ Maxima + { + Windows::Foundation::Collections::IVector ^ get() + { + return static_cast ^>(GetValue(s_maximaProperty)); + } + void set(Windows::Foundation::Collections::IVector ^ value) + { + SetValue(s_maximaProperty, value); + } + } +#pragma endregion + +#pragma region Platform::String ^ Domain DependencyProperty + static property Windows::UI::Xaml::DependencyProperty^ DomainProperty + { + Windows::UI::Xaml::DependencyProperty^ get() + { + return s_domainProperty; + } + } + property Platform::String^ Domain + { + Platform::String^ get() + { + return static_cast(GetValue(s_domainProperty)); + } + void set(Platform::String^ value) + { + SetValue(s_domainProperty, value); + } + } +#pragma endregion + +#pragma region Platform::String ^ Range DependencyProperty + static property Windows::UI::Xaml::DependencyProperty^ RangeProperty + { + Windows::UI::Xaml::DependencyProperty^ get() + { + return s_rangeProperty; + } + } + property Platform::String^ Range + { + Platform::String^ get() + { + return static_cast(GetValue(s_rangeProperty)); + } + void set(Platform::String^ value) + { + SetValue(s_rangeProperty, value); + } + } +#pragma endregion + +#pragma region Windows::Foundation::Collections::IVector < Platform::String ^ > ^ InflectionPoints DependencyProperty + static property Windows::UI::Xaml::DependencyProperty^ InflectionPointsProperty + { + Windows::UI::Xaml::DependencyProperty^ get() + { + return s_inflectionPointsProperty; + } + } + property Windows::Foundation::Collections::IVector ^ InflectionPoints + { + Windows::Foundation::Collections::IVector ^ get() + { + return static_cast ^>(GetValue(s_inflectionPointsProperty)); + } + void set(Windows::Foundation::Collections::IVector ^ value) + { + SetValue(s_inflectionPointsProperty, value); + } + } +#pragma endregion + +#pragma region Windows::Foundation::Collections::IObservableMap < Platform::String ^, Platform::String ^ > ^ Monotonicity DependencyProperty + static property Windows::UI::Xaml::DependencyProperty^ MonotonicityProperty + { + Windows::UI::Xaml::DependencyProperty^ get() + { + return s_monotonicityProperty; + } + } + property Windows::Foundation::Collections::IObservableMap ^ Monotonicity + { + Windows::Foundation::Collections::IObservableMap ^ get() + { + return static_cast ^>(GetValue(s_monotonicityProperty)); + } + void set(Windows::Foundation::Collections::IObservableMap ^ value) + { + SetValue(s_monotonicityProperty, value); + } + } +#pragma endregion + +#pragma region Windows::Foundation::Collections::IVector < Platform::String ^ > ^ VerticalAsymptotes DependencyProperty + static property Windows::UI::Xaml::DependencyProperty^ VerticalAsymptotesProperty + { + Windows::UI::Xaml::DependencyProperty^ get() + { + return s_verticalAsymptotesProperty; + } + } + property Windows::Foundation::Collections::IVector ^ VerticalAsymptotes + { + Windows::Foundation::Collections::IVector ^ get() + { + return static_cast ^>(GetValue(s_verticalAsymptotesProperty)); + } + void set(Windows::Foundation::Collections::IVector ^ value) + { + SetValue(s_verticalAsymptotesProperty, value); + } + } +#pragma endregion + +#pragma region Windows::Foundation::Collections::IVector < Platform::String ^ > ^ HorizontalAsymptotes DependencyProperty + static property Windows::UI::Xaml::DependencyProperty^ HorizontalAsymptotesProperty + { + Windows::UI::Xaml::DependencyProperty^ get() + { + return s_horizontalAsymptotesProperty; + } + } + property Windows::Foundation::Collections::IVector ^ HorizontalAsymptotes + { + Windows::Foundation::Collections::IVector ^ get() + { + return static_cast ^>(GetValue(s_horizontalAsymptotesProperty)); + } + void set(Windows::Foundation::Collections::IVector ^ value) + { + SetValue(s_horizontalAsymptotesProperty, value); + } + } +#pragma endregion + +#pragma region Windows::Foundation::Collections::IVector < Platform::String ^ > ^ ObliqueAsymptotes DependencyProperty + static property Windows::UI::Xaml::DependencyProperty^ ObliqueAsymptotesProperty + { + Windows::UI::Xaml::DependencyProperty^ get() + { + return s_obliqueAsymptotesProperty; + } + } + property Windows::Foundation::Collections::IVector ^ ObliqueAsymptotes + { + Windows::Foundation::Collections::IVector ^ get() + { + return static_cast ^>(GetValue(s_obliqueAsymptotesProperty)); + } + void set(Windows::Foundation::Collections::IVector ^ value) + { + SetValue(s_obliqueAsymptotesProperty, value); + } + } +#pragma endregion + +#pragma region int TooComplexFeatures DependencyProperty + static property Windows::UI::Xaml::DependencyProperty^ TooComplexFeaturesProperty + { + Windows::UI::Xaml::DependencyProperty^ get() + { + return s_tooComplexFeaturesProperty; + } + } + property int TooComplexFeatures + { + int get() + { + return static_cast(GetValue(s_tooComplexFeaturesProperty)); + } + void set(int value) + { + SetValue(s_tooComplexFeaturesProperty, value); + } + } +#pragma endregion + +#pragma region int AnalysisError DependencyProperty + static property Windows::UI::Xaml::DependencyProperty ^ AnalysisErrorProperty + { + Windows::UI::Xaml::DependencyProperty ^ get() + { + return s_analysisErrorProperty; + } + } + property int AnalysisError + { + int get() + { + return static_cast(GetValue(s_analysisErrorProperty)); + } + void set(int value) + { + SetValue(s_analysisErrorProperty, value); + } + } + +#pragma endregion + + internal : event PropertyChangedEventHandler ^ PropertyChanged; std::wstring GetRequest(); @@ -84,5 +441,22 @@ namespace GraphControl private: static Windows::UI::Xaml::DependencyProperty ^ s_expressionProperty; static Windows::UI::Xaml::DependencyProperty ^ s_lineColorProperty; + static Windows::UI::Xaml::DependencyProperty ^ s_isAnalysisUpdatedProperty; + static Windows::UI::Xaml::DependencyProperty ^ s_xInterceptProperty; + static Windows::UI::Xaml::DependencyProperty ^ s_yInterceptProperty; + static Windows::UI::Xaml::DependencyProperty ^ s_parityProperty; + static Windows::UI::Xaml::DependencyProperty ^ s_periodicityDirectionProperty; + static Windows::UI::Xaml::DependencyProperty ^ s_periodicityExpressionProperty; + static Windows::UI::Xaml::DependencyProperty ^ s_minimaProperty; + static Windows::UI::Xaml::DependencyProperty ^ s_maximaProperty; + static Windows::UI::Xaml::DependencyProperty ^ s_domainProperty; + static Windows::UI::Xaml::DependencyProperty ^ s_rangeProperty; + static Windows::UI::Xaml::DependencyProperty ^ s_inflectionPointsProperty; + static Windows::UI::Xaml::DependencyProperty ^ s_monotonicityProperty; + static Windows::UI::Xaml::DependencyProperty ^ s_verticalAsymptotesProperty; + static Windows::UI::Xaml::DependencyProperty ^ s_horizontalAsymptotesProperty; + static Windows::UI::Xaml::DependencyProperty ^ s_obliqueAsymptotesProperty; + static Windows::UI::Xaml::DependencyProperty ^ s_tooComplexFeaturesProperty; + static Windows::UI::Xaml::DependencyProperty ^ s_analysisErrorProperty; }; } diff --git a/src/GraphControl/Control/EquationCollection.h b/src/GraphControl/Control/EquationCollection.h index 5d2e2d12..3001b087 100644 --- a/src/GraphControl/Control/EquationCollection.h +++ b/src/GraphControl/Control/EquationCollection.h @@ -8,6 +8,7 @@ namespace GraphControl { delegate void EquationChangedEventHandler(); + delegate void VisibilityChangedEventHandler(Equation ^ sender); public ref class EquationCollection sealed : public Windows::Foundation::Collections::IObservableVector @@ -151,16 +152,16 @@ public private: void OnEquationPropertyChanged(GraphControl::Equation ^, Platform::String ^ propertyName) { - if (propertyName == L"LineColor") + if (propertyName == EquationProperties::LineColor) { EquationStyleChanged(); } - else + else if (propertyName == EquationProperties::Expression) { EquationChanged(); } } - + private: Platform::Collections::Vector ^ m_vector; std::vector m_tokens; diff --git a/src/GraphControl/Control/Grapher.cpp b/src/GraphControl/Control/Grapher.cpp index 4ddb3503..74d959f2 100644 --- a/src/GraphControl/Control/Grapher.cpp +++ b/src/GraphControl/Control/Grapher.cpp @@ -3,6 +3,8 @@ #include "pch.h" #include "Grapher.h" +#include "IBitmap.h" +#include "../../CalcViewModel/GraphingCalculatorEnums.h" using namespace Graphing; using namespace GraphControl; @@ -37,6 +39,9 @@ namespace constexpr auto s_X = L"x"; constexpr auto s_Y = L"y"; + constexpr auto s_getGraphOpeningTags = L"show2d"; + constexpr auto s_getGraphClosingTags = L""; + // Helper function for converting a pointer position to a position that the graphing engine will understand. // posX/posY are the pointer position elements and width,height are the dimensions of the graph surface. // The graphing engine interprets x,y position between the range [-1, 1]. @@ -61,6 +66,8 @@ namespace GraphControl , m_Moving{ false } { m_solver->ParsingOptions().SetFormatType(FormatType::MathML); + m_solver->FormatOptions().SetFormatType(FormatType::MathML); + m_solver->FormatOptions().SetMathMLPrefix(wstring(L"mml")); DefaultStyleKey = StringReference(s_defaultStyleKey); @@ -380,7 +387,7 @@ namespace GraphControl if (!validEqs.empty()) { wstringstream ss{}; - ss << L"show2d"; + ss << s_getGraphOpeningTags; int numValidEquations = 0; for (Equation ^ eq : validEqs) @@ -393,7 +400,7 @@ namespace GraphControl ss << eq->GetRequest(); } - ss << L""; + ss << s_getGraphClosingTags; wstring request = ss.str(); unique_ptr graphExpression; @@ -407,6 +414,7 @@ namespace GraphControl m_renderMain->Graph = m_graph; UpdateVariables(); + UpdateKeyGraphFeatures(); } } } @@ -420,6 +428,7 @@ namespace GraphControl m_renderMain->Graph = m_graph; UpdateVariables(); + UpdateKeyGraphFeatures(); } } } @@ -436,6 +445,105 @@ namespace GraphControl } } + shared_ptr Grapher::GetGraph(GraphControl::Equation ^ equation) + { + std::shared_ptr graph = m_solver->CreateGrapher(); + + wstringstream ss{}; + ss << s_getGraphOpeningTags; + ss << equation->GetRequest(); + ss << s_getGraphClosingTags; + + wstring request = ss.str(); + unique_ptr graphExpression; + if (graphExpression = m_solver->ParseInput(request)) + { + if (graph->TryInitialize(graphExpression.get())) + { + return graph; + } + } + + return nullptr; + } + + void Grapher::UpdateKeyGraphFeatures() + { + auto equations = GetValidEquations(); + for (auto equation : equations) + { + equation->IsAnalysisUpdated = false; + + if (auto graph = GetGraph(equation)) + { + if (auto analyzer = graph->GetAnalyzer()) + { + if (analyzer->CanFunctionAnalysisBePerformed()) + { + if (S_OK + == analyzer->PerformFunctionAnalysis( + (Graphing::Analyzer::NativeAnalysisType)Graphing::Analyzer::PerformAnalysisType::PerformAnalysisType_All)) + { + Graphing::IGraphFunctionAnalysisData functionAnalysisData = m_solver->Analyze(analyzer.get()); + { + equation->XIntercept = ref new String(functionAnalysisData.Zeros.c_str()); + equation->YIntercept = ref new String(functionAnalysisData.YIntercept.c_str()); + equation->Domain = ref new String(functionAnalysisData.Domain.c_str()); + equation->Range = ref new String(functionAnalysisData.Range.c_str()); + equation->Parity = functionAnalysisData.Parity; + equation->PeriodicityDirection = functionAnalysisData.PeriodicityDirection; + equation->PeriodicityExpression = ref new String(functionAnalysisData.PeriodicityExpression.c_str()); + equation->Minima = ConvertWStringVector(functionAnalysisData.Minima); + equation->Maxima = ConvertWStringVector(functionAnalysisData.Maxima); + equation->InflectionPoints = ConvertWStringVector(functionAnalysisData.InflectionPoints); + equation->Monotonicity = ConvertWStringIntMap(functionAnalysisData.MonotoneIntervals); + equation->VerticalAsymptotes = ConvertWStringVector(functionAnalysisData.VerticalAsymptotes); + equation->HorizontalAsymptotes = ConvertWStringVector(functionAnalysisData.HorizontalAsymptotes); + equation->ObliqueAsymptotes = ConvertWStringVector(functionAnalysisData.ObliqueAsymptotes); + equation->TooComplexFeatures = functionAnalysisData.TooComplexFeatures; + equation->AnalysisError = CalculatorApp::AnalysisErrorType::NoError; + equation->IsAnalysisUpdated = true; + continue; + } + } + } + else + { + equation->AnalysisError = CalculatorApp::AnalysisErrorType::AnalysisNotSupported; + equation->IsAnalysisUpdated = true; + continue; + } + } + } + + equation->AnalysisError = CalculatorApp::AnalysisErrorType::AnalysisCouldNotBePerformed; + equation->IsAnalysisUpdated = true; + } + } + IObservableVector ^ Grapher::ConvertWStringVector(vector inVector) + { + Vector ^ outVector = ref new Vector(); + + for (auto v : inVector) + { + outVector->Append(ref new String(v.c_str())); + } + + return outVector; + } + + IObservableMap ^ Grapher::ConvertWStringIntMap(map inMap) + { + Map ^ outMap = ref new Map(); + ; + for (auto m : inMap) + { + outMap->Insert(ref new String(m.first.c_str()), m.second.ToString()); + } + + return outMap; + } + void Grapher::UpdateVariables() { auto updatedVariables = ref new Map(); diff --git a/src/GraphControl/Control/Grapher.h b/src/GraphControl/Control/Grapher.h index 8d383d86..9bf8ce4d 100644 --- a/src/GraphControl/Control/Grapher.h +++ b/src/GraphControl/Control/Grapher.h @@ -7,6 +7,7 @@ #include "DirectX/RenderMain.h" #include "Equation.h" #include "EquationCollection.h" +#include "IGraphAnalyzer.h" #include "IMathSolver.h" #include "Common.h" @@ -162,7 +163,7 @@ public } } - property Windows::Foundation::Point TraceLocation + property Windows::Foundation::Point TraceLocation { Windows::Foundation::Point get() { @@ -170,7 +171,6 @@ public } } - property Windows::Foundation::Point ActiveTraceCursorPosition { Windows::Foundation::Point get() @@ -228,7 +228,9 @@ public void UpdateGraphOptions(Graphing::IGraphingOptions& options, const std::vector& validEqs); std::vector GetValidEquations(); void SetGraphArgs(); + std::shared_ptr GetGraph(GraphControl::Equation ^ equation); void UpdateVariables(); + void UpdateKeyGraphFeatures(); void OnForceProportionalAxesChanged(Windows::UI::Xaml::DependencyPropertyChangedEventArgs ^ args); @@ -247,6 +249,8 @@ public void HandleTracingMovementTick(Object ^ sender, Object ^ e); void HandleKey(bool keyDown, Windows::System::VirtualKey key); + Windows::Foundation::Collections::IObservableVector ^ ConvertWStringVector(std::vector inVector); + Windows::Foundation::Collections::IObservableMap ^ ConvertWStringIntMap(std::map inMap); private: DX::RenderMain ^ m_renderMain = nullptr; @@ -283,7 +287,7 @@ public bool m_KeysPressed[5]; bool m_Moving; - Windows::UI::Xaml::DispatcherTimer ^ m_TracingTrackingTimer; + Windows::UI::Xaml::DispatcherTimer ^ m_TracingTrackingTimer; public: Windows::Storage::Streams::RandomAccessStreamReference ^ GetGraphBitmapStream(); diff --git a/src/GraphControl/GraphControl.vcxproj b/src/GraphControl/GraphControl.vcxproj index 68f21c41..d9c0042e 100644 --- a/src/GraphControl/GraphControl.vcxproj +++ b/src/GraphControl/GraphControl.vcxproj @@ -42,8 +42,8 @@ 14.0 true Windows Store - 10.0.18970.0 - 10.0.18362.0 + 10.0.19019.0 + 10.0.17134.0 10.0 diff --git a/src/GraphControl/GraphControl.vcxproj.filters b/src/GraphControl/GraphControl.vcxproj.filters index 0112c1e5..00b889e9 100644 --- a/src/GraphControl/GraphControl.vcxproj.filters +++ b/src/GraphControl/GraphControl.vcxproj.filters @@ -74,4 +74,10 @@ + + + + + + \ No newline at end of file diff --git a/src/GraphingInterfaces/Common.h b/src/GraphingInterfaces/Common.h index 808591dd..37514c29 100644 --- a/src/GraphingInterfaces/Common.h +++ b/src/GraphingInterfaces/Common.h @@ -2,7 +2,6 @@ #include #include - #ifndef GRAPHINGAPI #ifdef GRAPHING_ENGINE_IMPL #define GRAPHINGAPI __declspec(dllexport) diff --git a/src/GraphingInterfaces/GraphingEnums.h b/src/GraphingInterfaces/GraphingEnums.h index 47139ad8..81bfbebe 100644 --- a/src/GraphingInterfaces/GraphingEnums.h +++ b/src/GraphingInterfaces/GraphingEnums.h @@ -384,4 +384,189 @@ namespace Graphing DashDotDot }; } + + namespace Analyzer { + + // Graph Analyzer Messages + enum GraphAnalyzerMessage + { + // "No data" + GraphAnalyzerMessage_None = 0, + + // "No zeros" + GraphAnalyzerMessage_NoZeros = 1, + + // "No y-intercept" + GraphAnalyzerMessage_NoYIntercept = 2, + + // "No minima" + GraphAnalyzerMessage_NoMinima = 3, + + // "No maxima" + GraphAnalyzerMessage_NoMaxima = 4, + + // "No inflection points" + GraphAnalyzerMessage_NoInflectionPoints = 5, + + // "No vertical asymptotes" + GraphAnalyzerMessage_NoVerticalAsymptotes = 6, + + // "No horizontal asymptotes" + GraphAnalyzerMessage_NoHorizontalAsymptotes = 7, + + // "No oblique asymptotes" + GraphAnalyzerMessage_NoObliqueAsymptotes = 8, + + // "Not able to calculate" + GraphAnalyzerMessage_NotAbleToCalculate = 9, + + // "Not able to mark all graph features" + GraphAnalyzerMessage_NotAbleToMarkAllGraphFeatures = 10, + + // These features are too complex for {APPLICATION_NAME} to calculate + GraphAnalyzerMessage_TheseFeaturesAreTooComplexToCalculate = 11, + + // "This feature is too complex for {APPLICATION_NAME} to calculate" + GraphAnalyzerMessage_ThisFeatureIsTooComplexToCalculate = 12 + }; + + // define which data should be filled into result object + enum AnalysisType + { + // fill domain data + AnalysisType_Domain = 0, + + // fill range data + AnalysisType_Range = 1, + + // fill parity data + AnalysisType_Parity = 2, + + // fill zeros + AnalysisType_Zeros = 3, + + // fill interception with y axis + AnalysisType_YIntercept = 4, + + // fill minima + AnalysisType_Minima = 5, + + // fill maxima + AnalysisType_Maxima = 6, + + // fill inflection points + AnalysisType_InflectionPoints = 7, + + // fill vertical asymptotes + AnalysisType_VerticalAsymptotes = 8, + + // fill horizontal asymptotes + AnalysisType_HorizontalAsymptotes = 9, + + // fill oblique asymptotes + AnalysisType_ObliqueAsymptotes = 10, + + // fill monotonicity + AnalysisType_Monotonicity = 11, + + // fill period + AnalysisType_Period = 12 + }; + + // define which additional data should be calculated + enum class PerformAnalysisType + { + // Calculate nothing + //PerformAnalysisType_None = 0x0, + + // Calculate domain data + PerformAnalysisType_Domain = 0x01, + + // Calculate range data + PerformAnalysisType_Range = 0x02, + + // Calculate parity data + PerformAnalysisType_Parity = 0x04, + + // Calculate zeros and interception with y axis + PerformAnalysisType_InterceptionPointsWithXAndYAxis = 0x08, + + // Calculate Extrema and inflection points + PerformAnalysisType_CriticalPoints = 0x10, + + // Calculate asymptotes + PerformAnalysisType_Asymptotes = 0x20, + + // Calculate monotonicity + PerformAnalysisType_Monotonicity = 0x40, + + // Calculate period + PerformAnalysisType_Period = 0x80, + + // Calculate all additional data + PerformAnalysisType_All = 0xFF + }; + + // function parity for function analysis + enum class FunctionParityType + { + // parity not calculated or not possible to calculate + FunctionParityType_Unknown = 0, + + // parity is odd + FunctionParityType_Odd = 1, + + // parity is even + FunctionParityType_Even = 2, + + // function is not odd nor even + FunctionParityType_None = 3 + }; + + // monotonicity direction for function analysis + enum class FunctionMonotonicityType + { + // unknown or not calculated + FunctionMonotonicityType_Unknown = 0, + + // ascending monotonicity on interval + FunctionMonotonicityType_Ascending = 1, + + // descending monotonicity on interval + FunctionMonotonicityType_Descending = 2, + + // constant monotonicity on interval + FunctionMonotonicityType_Constant = 3 + }; + + // asymptote description for function analysis + enum class AsymptoteType + { + // unknown or not calculated + AsymptoteType_Unknown = 0, + + // when x goes to positive infinity + AsymptoteType_PositiveInfinity = 1, + + // when x goes to negative infinity + AsymptoteType_NegativeInfinity = 2, + + // when x goes to positive or negative infinity + AsymptoteType_AnyInfinity = 3 + }; + + // function periodicity for function analysis + enum class FunctionPeriodicityType + { + // periodicity not calculated or not possible to calculate + FunctionPeriodicityType_Unknown = 0, + + // parity is odd + FunctionPeriodicityType_Periodic = 1, + + // parity is even + FunctionPeriodicityType_NotPeriodic = 2 + }; + + } } diff --git a/src/GraphingInterfaces/IBitmap.h b/src/GraphingInterfaces/IBitmap.h index cda8f5bb..46ba34a2 100644 --- a/src/GraphingInterfaces/IBitmap.h +++ b/src/GraphingInterfaces/IBitmap.h @@ -4,8 +4,8 @@ namespace Graphing { - struct IBitmap + struct IBitmap { - virtual const std::vector& GetData() const = 0; - }; + virtual const std::vector& GetData() const = 0; + }; } diff --git a/src/GraphingInterfaces/IGraph.h b/src/GraphingInterfaces/IGraph.h index a772fa62..e42fd2b4 100644 --- a/src/GraphingInterfaces/IGraph.h +++ b/src/GraphingInterfaces/IGraph.h @@ -1,6 +1,7 @@ #pragma once #include "Common.h" +#include "IGraphAnalyzer.h" #include "IGraphingOptions.h" #include "IGraphRenderer.h" #include "IEquation.h" @@ -16,12 +17,14 @@ namespace Graphing virtual IGraphingOptions& GetOptions() = 0; - virtual std::vector> GetVariables() = 0; + virtual std::vector> GetVariables() = 0; virtual void SetArgValue(std::wstring variableName, double value) = 0; - virtual std::shared_ptr< Renderer::IGraphRenderer > GetRenderer() const = 0; + virtual std::shared_ptr GetRenderer() const = 0; virtual bool TryResetSelection() = 0; + + virtual std::shared_ptr< Graphing::Analyzer::IGraphAnalyzer > GetAnalyzer() const = 0; }; } diff --git a/src/GraphingInterfaces/IGraphAnalyzer.h b/src/GraphingInterfaces/IGraphAnalyzer.h new file mode 100644 index 00000000..bfbeed06 --- /dev/null +++ b/src/GraphingInterfaces/IGraphAnalyzer.h @@ -0,0 +1,21 @@ +#pragma once + +#include "Common.h" +#include "GraphingEnums.h" +#include +#include +#include + +namespace Graphing::Analyzer +{ + typedef unsigned int NativeAnalysisType; // PerformAnalysisType + + struct IGraphAnalyzer : public NonCopyable, public NonMoveable + { + virtual ~IGraphAnalyzer() = default; + virtual bool CanFunctionAnalysisBePerformed() = 0; + virtual HRESULT PerformFunctionAnalysis(NativeAnalysisType analysisType) = 0; + virtual HRESULT GetAnalysisTypeCaption(const AnalysisType type, std::wstring& captionOut) const = 0; + virtual HRESULT GetMessage(const GraphAnalyzerMessage msg, std::wstring& msgOut) const = 0; + }; +} \ No newline at end of file diff --git a/src/GraphingInterfaces/IGraphRenderer.h b/src/GraphingInterfaces/IGraphRenderer.h index 7f28f11e..a7af01a8 100644 --- a/src/GraphingInterfaces/IGraphRenderer.h +++ b/src/GraphingInterfaces/IGraphRenderer.h @@ -1,11 +1,15 @@ #pragma once #include "Common.h" -#include "IBitmap.h" struct ID2D1Factory; struct ID2D1RenderTarget; +namespace Graphing +{ + struct IBitmap; +} + namespace Graphing::Renderer { struct IGraphRenderer : public NonCopyable, public NonMoveable diff --git a/src/GraphingInterfaces/IMathSolver.h b/src/GraphingInterfaces/IMathSolver.h index 7aabf8a2..25c7cbad 100644 --- a/src/GraphingInterfaces/IMathSolver.h +++ b/src/GraphingInterfaces/IMathSolver.h @@ -2,10 +2,30 @@ #include "Common.h" #include "IGraph.h" +#include "IGraphAnalyzer.h" #include "GraphingEnums.h" namespace Graphing { + struct IGraphFunctionAnalysisData + { + std::wstring Domain; + std::wstring Range; + int Parity; + int PeriodicityDirection; + std::wstring PeriodicityExpression; + std::wstring Zeros; + std::wstring YIntercept; + std::vector Minima; + std::vector Maxima; + std::vector InflectionPoints; + std::vector VerticalAsymptotes; + std::vector HorizontalAsymptotes; + std::vector ObliqueAsymptotes; + std::map MonotoneIntervals; + int TooComplexFeatures; // to-do: refactor to remove bitwise flag + }; + struct IParsingOptions : public NonCopyable, public NonMoveable { virtual ~IParsingOptions() = default; @@ -23,6 +43,7 @@ namespace Graphing virtual ~IFormatOptions() = default; virtual void SetFormatType(FormatType type) = 0; + virtual void SetMathMLPrefix(const std::wstring& value) = 0; }; struct IMathSolver : public NonCopyable, public NonMoveable @@ -41,5 +62,7 @@ namespace Graphing virtual std::shared_ptr CreateGrapher() = 0; virtual std::wstring Serialize(const IExpression* expression) = 0; + + virtual Graphing::IGraphFunctionAnalysisData Analyze(const Graphing::Analyzer::IGraphAnalyzer* analyzer) = 0; }; } diff --git a/src/MockGraphingImpl/MockGraphingImpl.vcxproj b/src/MockGraphingImpl/MockGraphingImpl.vcxproj index 3387a929..a797e58a 100644 --- a/src/MockGraphingImpl/MockGraphingImpl.vcxproj +++ b/src/MockGraphingImpl/MockGraphingImpl.vcxproj @@ -42,8 +42,8 @@ 14.0 true Windows Store - 10.0.18970.0 - 10.0.18362.0 + 10.0.19019.0 + 10.0.17134.0 10.0 @@ -270,6 +270,7 @@ + diff --git a/src/MockGraphingImpl/MockGraphingImpl.vcxproj.filters b/src/MockGraphingImpl/MockGraphingImpl.vcxproj.filters index 5e245269..c7366861 100644 --- a/src/MockGraphingImpl/MockGraphingImpl.vcxproj.filters +++ b/src/MockGraphingImpl/MockGraphingImpl.vcxproj.filters @@ -43,5 +43,10 @@ GraphingInterfaces + + + + GraphingInterfaces + \ No newline at end of file diff --git a/src/MockGraphingImpl/Mocks/MathSolver.h b/src/MockGraphingImpl/Mocks/MathSolver.h index 495fa316..7394c341 100644 --- a/src/MockGraphingImpl/Mocks/MathSolver.h +++ b/src/MockGraphingImpl/Mocks/MathSolver.h @@ -11,7 +11,8 @@ namespace MockGraphingImpl { public: void SetFormatType(Graphing::FormatType type) override - { } + { + } }; class EvalOptions : public Graphing::IEvalOptions @@ -22,7 +23,12 @@ namespace MockGraphingImpl { public: void SetFormatType(Graphing::FormatType type) override - { } + { + } + + void SetMathMLPrefix(const std::wstring& value) override + { + } }; class MathSolver : public Graphing::IMathSolver @@ -63,6 +69,11 @@ namespace MockGraphingImpl return std::wstring{}; } + Graphing::IGraphFunctionAnalysisData IMathSolver::Analyze(const Graphing::Analyzer::IGraphAnalyzer* analyzer) + { + return Graphing::IGraphFunctionAnalysisData{}; + } + private: MockGraphingImpl::ParsingOptions m_parsingOptions; MockGraphingImpl::EvalOptions m_evalOptions;