Feature/GraphingCalculator initial commit (#450)

Initial PR for the feature/GraphingCalculator feature branch, part of #338.

The feature incorporates a proprietary Microsoft-owned graphing engine to drive graphing experiences in the Windows Calculator app. Due to the private nature of the graphing engine, the source available in the public repo will make use of a mock graphing engine. See README.md for more details.

This PR simply serves as a base for future feature development. As such, the PR will be immediately merged. Feedback on the content of this PR, and on the feature in general, is encouraged. If there is feedback related to the content of this specific PR, please leave comments on the PR page. We will address the comments in future PRs to the feature branch.
This commit is contained in:
Daniel Belcher
2019-04-10 18:15:10 -07:00
committed by GitHub
parent 47a2741218
commit 091732aa94
65 changed files with 5190 additions and 109 deletions

View File

@@ -0,0 +1,96 @@
#pragma once
#include <memory>
#ifndef GRAPHINGAPI
#ifdef GRAPHING_ENGINE_IMPL
#define GRAPHINGAPI __declspec(dllexport)
#else
#define GRAPHINGAPI __declspec(dllimport)
#endif
#endif
namespace Graphing
{
struct NonCopyable
{
NonCopyable() = default;
virtual ~NonCopyable() = default;
NonCopyable(NonCopyable const&) = delete;
NonCopyable& operator=(NonCopyable const&) = delete;
};
struct NonMoveable
{
NonMoveable() = default;
virtual ~NonMoveable() = default;
NonMoveable(NonMoveable&&) = delete;
NonMoveable& operator=(NonMoveable&&) = delete;
};
struct IExpression
{
virtual ~IExpression() = default;
virtual unsigned int GetExpressionID() const = 0;
virtual bool IsEmptySet() const = 0;
};
struct IExpressible
{
virtual ~IExpressible() = default;
virtual std::shared_ptr< IExpression > GetExpression() const = 0;
};
class Color
{
private:
// Each color channel is given an 8 bit space in a 32 bit uint32_t.
// The format is (RRGGBBAA). As an example,
// Red is FF0000FF (4,278,190,335)
static constexpr uint8_t redChannelShift = 24;
static constexpr uint8_t greenChannelShift = 16;
static constexpr uint8_t blueChannelShift = 8;
static constexpr uint8_t alphaChannelShift = 0;
public:
uint8_t R;
uint8_t G;
uint8_t B;
uint8_t A;
Color::Color(uint8_t r, uint8_t g, uint8_t b, uint8_t a) noexcept
: R{ r }, G{ g }, B{ b }, A{ a }
{}
Color::Color(uint8_t r, uint8_t g, uint8_t b) noexcept
: Color{ r, g, b, 0xFF }
{}
Color::Color() noexcept
: Color{ 0, 0, 0 }
{}
explicit Color(uint32_t value) noexcept
: Color{
static_cast<uint8_t>(value >> redChannelShift),
static_cast<uint8_t>(value >> greenChannelShift),
static_cast<uint8_t>(value >> blueChannelShift),
static_cast<uint8_t>(value >> alphaChannelShift)
}
{
}
explicit operator uint32_t() const
{
return (A << alphaChannelShift)
| (R << redChannelShift)
| (G << greenChannelShift)
| (B << blueChannelShift);
}
};
}

View File

@@ -0,0 +1,387 @@
#pragma once
namespace Graphing
{
enum class LocalizationType
{
Unknown,
DecimalPointAndListComma,
DecimalPointAndListSemicolon,
DecimalCommaAndListSemicolon
};
enum class EquationParsingMode
{
// Solving an equation. At least one equal sign is required
SolveEquation,
// Graphing an equation. At least one equal sign is required
GraphEquation,
// Not expecting an equation. No equal sign is allowed
NonEquation,
// Accept zero or more equal signs
DoNotCare
};
enum class FormatType
{
// This format is not very human-readable, but best for machine processing and unit test.
// The meaning of an expression is precise, there is no need for parentheses, and it's easy to parse.
// While other serializers may contain little tweaks to make the UI component work as expected, this
// format doesn't change often because no real UI uses it.
// Example: Sum[1,Divide[2,x]]
Formula,
// Similar to Formula, except the variables are in the format of Var(0), Var(1), ... instead of in their names.
// Used in serialization only (CasContext.FormatOptions) but not in parsing (CasContext.ParsingOptions)
// Example: Sum[1,Divide[2,Var(0)]]
InvariantFormula,
// Similar to Formula, except the aggregates (grouping parentheses) are silently removed during serialization.
// The primary usage for this format is in internal test cases.
// When used in parsing, it's identical to Formula
// Example: Sum[1,Divide[2,x]]
FormulaWithoutAggregate,
// This format is the most human-readable one. Can be used in command line applications or application that accept
// and displays linear syntax. Also, the RichEdit wrapper returns linear syntax and it should be parsed with Linear format type.
// Example: 1+2/x
Linear,
// This format is similar to linear format, but during serialization it uses ASCII characters only (except for variable
// named specified by the user) and can round trip back to the linear parser.
//
// When used in parsing it's identical to Linear.
LinearInput,
// The standard MathML format. Note that the math engine can only parse a subset of the syntax in the MathML specification.
// Example: &lt;math&gt;&lt;mn&gt;1&lt;/mn&gt;&lt;mo&gt;+&lt;/mo&gt;&lt;mfrac&gt;&lt;mn&gt;2&lt;/mn&gt;&lt;mi&gt;x&lt;/mi&gt;&lt;/mfrac&gt;&lt;/math&gt;
MathML,
// Same as MathML, except this format type won't generate the root element &lt;math&gt; .
// Used in serialization only (CasContext.FormatOptions) but not in parsing (CasContext.ParsingOptions)
// Example: &lt;mn&gt;1&lt;/mn&gt;&lt;mo&gt;+&lt;/mo&gt;&lt;mfrac&gt;&lt;mn&gt;2&lt;/mn&gt;&lt;mi&gt;x&lt;/mi&gt;&lt;/mfrac&gt;
MathMLNoWrapper,
// This format type is for the RichEdit wrapper to render math in RichEdit.
//
// Used in serialization only (CasContext.FormatOptions) but not in parsing (CasContext.ParsingOptions)
// Example: 1 + \frac{2,x}
MathRichEdit,
// This format type is for the RichEdit wrapper to render math in RichEdit.
// It's same with MathRichEdit format with one exception: fractions are rendered
// horizontally instead of vertically. This is a better choice if the display area
// is confined with a small height.
//
// Used in serialization only (CasContext.FormatOptions) but not in parsing (CasContext.ParsingOptions)
// Example: 1 + x/(2 a)
InlineMathRichEdit,
// The most compact format. Uses binary data. Like Format, it guarantees round trip between parsing and serialization.
Binary,
// Similar to Binary, except variableIds are used instead of variable name.
InvariantBinary,
// This is the base-64 encoded Binary format
Base64,
// This is the base-64 encoded InvariantBinary format.
InvariantBase64,
// Latex format
// Example: \frac{1}{2}
Latex
};
// Specify on what number field the evaluation should be performed: Real or Complex.
enum class EvalNumberField
{
// This is invalid setting.
Invalid,
// Evaluation should be performed on Real number field
Real,
// Evaluation should be performed on Complex number field
Complex
};
// Specify the evaluation direction: Expand, Factor or Neutral (neither Expand nor Factor)
enum class EvalExpandMode
{
// Neither Expand nor Factor
Neutral,
// To expand during evaluation
Expand,
// To factor during evaluation
Factor
};
// Specify the current trigonometry unit mode: Radians, Degrees, Grads. This has effect on these trig operators:
// Sin Cos Tan Cot Sec Csc
// ASin ACos ATan ACot ASec ACsc.
// It has NO effect on hyperbolic trig operators (same behavior as Windows Calc), and any other operators.
enum class EvalTrigUnitMode
{
// Invalid value.
Invalid,
// Default trig unit. Period of sin is 2pi
Radians,
// Degrees as trig unit. Period of sin is 360 degrees
Degrees,
// Grads as trig unit. Period of sin is 400 grads
Grads
};
// Specifies the type of contextual action
enum class ContextualActionType
{
// The input didn't generate any contextual action
None,
// Solve equation
SolveEquation,
// perform comparison
Compare,
// Expand the expression
Expand,
// Perform a 2D graphing
Graph2D,
// Perform a 2D graphing on all items in the list
ListGraph2D,
// Perform 2D graphing of the two functions on both side of the equal sign or inequality sign
GraphBothSides2D,
// Perform a 3D graphing
Graph3D,
// Perform 3D graphing of the two functions on both side of the equal sign or inequality sign
GraphBothSides3D,
// Perform 2D inequality graphing
GraphInequality,
// Perform assignment
Assign,
// Factor the expression
Factor,
// Compute the derivate of the expression
Deriv,
// Compute the integral of the expression
IndefiniteIntegral,
// Perform 2D graph
Graph2DExpression,
// Perform 3D graph
Graph3DExpression,
// solve the inequality
SolveInequality,
// calculate/simplify the expression
Calculate,
// round of the number
Round,
// floor of the number
Floor,
// ceiling of the number
Ceiling,
// The bit mask for matrix related contextual action types. if (type &amp; MatrixMask)!=0 then the type is matrix related
MatrixMask,
// Compute the determinant of the matrix
MatrixDeterminant,
// Compute the inverse of the matrix
MatrixInverse,
// Compute the trace of the matrix
MatrixTrace,
// Compute the transpose of the matrix
MatrixTranspose,
// Compute the size of the matrix
MatrixSize,
// Compute the reduce of the matrix
MatrixReduce,
// The bit mask for list related contextual action types. if (type &amp; ListMask)!=0 then the type is list related
ListMask,
// Sort the list
ListSort,
// Compute the mean of the list
ListMean,
// Compute the median of the list
ListMedian,
// Compute the mode of the list
ListMode,
// Compute the LCM (least common multiplier) of the list
ListLcm,
// Compute the GCF (greatest common factor) of the list
ListGcf,
// Compute the sum of the list elements
ListSum,
// Compute the product of the list elements
ListProduct,
// Compute the max of the list elements
ListMax,
// Compute the min of the list elements
ListMin,
// Compute the variance of the list elements
ListVariance,
// Compute the standard deviation of the list elements
ListStdDev,
// Show complete (verbose) solution
ShowVerboseSolution,
// bit mask of action type. Can be used to remove the Informational flag
TypeMask, // mask to get the type
// A flag that can be added onto any type. This is informational only that explains what the straight input would do.
// No action should be performed
Informational
};
enum class MathActionCategoryType
{
Unknown,
Calculate,
Solve,
Integrate,
Differentiate,
Algebra,
Matrix,
List,
Graph
};
enum class StepSequenceType
{
None,
Text,
Expression,
NewLine,
NewStep,
Conditional,
Composite,
Goto,
Call,
Return,
Stop,
Error,
GotoTemp
};
enum class FormatVerbosityMode
{
Verbose,
Simple
};
namespace Renderer
{
// Used to indicate what action should be performed to change the range.
enum class ChangeRangeAction
{
// Zoom in on all axes by the predefined ratio
ZoomIn,
// Zoom out on all axes by the predefined ratio
ZoomOut,
// Zoom out on X axis only, leave the range of Y (and Z in 3D) unchanged
WidenX,
// Zoom in on X axis only, leave the range of Y (and Z in 3D) unchanged
ShrinkX,
// Zoom out on Y axis only, leave the range of X (and Z in 3D) unchanged
WidenY,
// Zoom in on Y axis only, leave the range of X (and Z in 3D) unchanged
ShrinkY,
// Zoom out on Z axis only, leave the range of X and Y unchanged. Apply to 3D graph only but not 2D graph.
WidenZ,
// Zoom in on Z axis only, leave the range of X and Y unchanged. Apply to 3D graph only but not 2D graph.
ShrinkZ,
// Move the view window of the graph towards the negative X axis.
MoveNegativeX,
// Move the view window of the graph towards the positive X axis.
MovePositiveX,
// Move the view window of the graph towards the negative Y axis.
MoveNegativeY,
// Move the view window of the graph towards the positive Y axis.
MovePositiveY,
// Move the view window of the graph towards the negative Z axis.
MoveNegativeZ,
// Move the view window of the graph towards the positive Z axis.
MovePositiveZ,
// Zoom in on all axes by the predefined ratio. The ratio is smaller than used in ZoomIn result in a smoother motion
SmoothZoomIn,
// Zoom out on all axes by the predefined ratio. The ratio is smaller than used in ZoomIn result in a smoother motion
SmoothZoomOut,
// Zoom in on all axes by the predefined ratio
PinchZoomIn,
// Zoom out on all axes by the predefined ratio
PinchZoomOut
};
enum class LineStyle
{
Solid,
Dot,
Dash,
DashDot,
DashDotDot
};
}
}

View File

@@ -0,0 +1,19 @@
#pragma once
#include "Common.h"
#include "IGraphingOptions.h"
#include "IGraphRenderer.h"
namespace Graphing
{
struct IGraph : public NonCopyable, public NonMoveable
{
virtual ~IGraph() = default;
virtual bool TryInitialize(const IExpression* graphingExp) = 0;
virtual IGraphingOptions& GetOptions() = 0;
virtual std::shared_ptr< Renderer::IGraphRenderer > GetRenderer() const = 0;
};
}

View File

@@ -0,0 +1,20 @@
#pragma once
#include "Common.h"
struct ID2D1Factory;
struct ID2D1RenderTarget;
namespace Graphing::Renderer
{
struct IGraphRenderer : public NonCopyable, public NonMoveable
{
virtual ~IGraphRenderer() = default;
virtual HRESULT SetGraphSize(unsigned int width, unsigned int height) = 0;
virtual HRESULT SetDpi(float dpiX, float dpiY) = 0;
virtual HRESULT DrawD2D1(ID2D1Factory* pDirect2dFactory, ID2D1RenderTarget* pRenderTarget, bool& hasSomeMissingDataOut) = 0;
virtual HRESULT GetClosePointData(float inScreenPointX, float inScreenPointY, int& formulaIdOut, float& xScreenPointOut, float& yScreenPointOut, float& xValueOut, float& yValueOut) = 0;
};
}

View File

@@ -0,0 +1,116 @@
#pragma once
#include <vector>
#include <string>
#include "Common.h"
#include "GraphingEnums.h"
namespace Graphing
{
struct IGraphingOptions : public NonCopyable, public NonMoveable
{
virtual ~IGraphingOptions() = default;
virtual void ResetMarkKeyGraphFeaturesData() = 0;
virtual bool GetMarkZeros() const = 0;
virtual void SetMarkZeros(bool value) = 0;
virtual bool GetMarkYIntercept() const = 0;
virtual void SetMarkYIntercept(bool value) = 0;
virtual bool GetMarkMinima() const = 0;
virtual void SetMarkMinima(bool value) = 0;
virtual bool GetMarkMaxima() const = 0;
virtual void SetMarkMaxima(bool value) = 0;
virtual bool GetMarkInflectionPoints() const = 0;
virtual void SetMarkInflectionPoints(bool value) = 0;
virtual bool GetMarkVerticalAsymptotes() const = 0;
virtual void SetMarkVerticalAsymptotes(bool value) = 0;
virtual bool GetMarkHorizontalAsymptotes() const = 0;
virtual void SetMarkHorizontalAsymptotes(bool value) = 0;
virtual bool GetMarkObliqueAsymptotes() const = 0;
virtual void SetMarkObliqueAsymptotes(bool value) = 0;
virtual unsigned long long GetMaxExecutionTime() const = 0;
virtual void SetMaxExecutionTime(unsigned long long value) = 0;
virtual void ResetMaxExecutionTime() = 0;
virtual std::vector<Graphing::Color> GetGraphColors() const = 0;
virtual bool SetGraphColors(const std::vector<Graphing::Color>& colors) = 0;
virtual void ResetGraphColors() = 0;
virtual Graphing::Color GetBackColor() const = 0;
virtual void SetBackColor(const Graphing::Color& value) = 0;
virtual void ResetBackColor() = 0;
virtual Graphing::Color GetZerosColor() const = 0;
virtual void SetZerosColor(const Graphing::Color& value) = 0;
virtual void ResetZerosColor() = 0;
virtual Graphing::Color GetExtremaColor() const = 0;
virtual void SetExtremaColor(const Graphing::Color& value) = 0;
virtual void ResetExtremaColor() = 0;
virtual Graphing::Color GetInflectionPointsColor() const = 0;
virtual void SetInflectionPointsColor(const Graphing::Color& value) = 0;
virtual void ResetInflectionPointsColor() = 0;
virtual Graphing::Color GetAsymptotesColor() const = 0;
virtual void SetAsymptotesColor(const Graphing::Color& value) = 0;
virtual void ResetAsymptotesColor() = 0;
virtual Graphing::Color GetAxisColor() const = 0;
virtual void SetAxisColor(const Graphing::Color& value) = 0;
virtual void ResetAxisColor() = 0;
virtual Graphing::Color GetBoxColor() const = 0;
virtual void SetBoxColor(const Graphing::Color& value) = 0;
virtual void ResetBoxColor() = 0;
virtual Graphing::Color GetFontColor() const = 0;
virtual void SetFontColor(const Graphing::Color& value) = 0;
virtual void ResetFontColor() = 0;
virtual bool GetShowAxis() const = 0;
virtual void SetShowAxis(bool value) = 0;
virtual void ResetShowAxis() = 0;
virtual bool GetShowGrid() const = 0;
virtual void SetShowGrid(bool value) = 0;
virtual void ResetShowGrid() = 0;
virtual bool GetShowBox() const = 0;
virtual void SetShowBox(bool value) = 0;
virtual void ResetShowBox() = 0;
virtual bool GetForceProportional() const = 0;
virtual void SetForceProportional(bool value) = 0;
virtual void ResetForceProportional() = 0;
virtual std::wstring GetAliasX() const = 0;
virtual void SetAliasX(const std::wstring& value) = 0;
virtual void ResetAliasX() = 0;
virtual std::wstring GetAliasY() const = 0;
virtual void SetAliasY(const std::wstring& value) = 0;
virtual void ResetAliasY() = 0;
virtual Graphing::Renderer::LineStyle GetLineStyle() const = 0;
virtual void SetLineStyle(Graphing::Renderer::LineStyle value) = 0;
virtual void ResetLineStyle() = 0;
virtual std::pair<double, double> GetDefaultXRange() const = 0;
virtual bool SetDefaultXRange(const std::pair<double, double>& minmax) = 0;
virtual void ResetDefaultXRange() = 0;
virtual std::pair<double, double> GetDefaultYRange() const = 0;
virtual bool SetDefaultYRange(const std::pair<double, double>& minmax) = 0;
virtual void ResetDefaultYRange() = 0;
};
}

View File

@@ -0,0 +1,45 @@
#pragma once
#include "Common.h"
#include "IGraph.h"
#include "GraphingEnums.h"
namespace Graphing
{
struct IParsingOptions : public NonCopyable, public NonMoveable
{
virtual ~IParsingOptions() = default;
virtual void SetFormatType(FormatType type) = 0;
};
struct IEvalOptions : public NonCopyable, public NonMoveable
{
virtual ~IEvalOptions() = default;
};
struct IFormatOptions : public NonCopyable, public NonMoveable
{
virtual ~IFormatOptions() = default;
virtual void SetFormatType(FormatType type) = 0;
};
struct IMathSolver : public NonCopyable, public NonMoveable
{
virtual ~IMathSolver() = default;
static GRAPHINGAPI std::unique_ptr<IMathSolver> CreateMathSolver();
virtual IParsingOptions& ParsingOptions() = 0;
virtual IEvalOptions& EvalOptions() = 0;
virtual IFormatOptions& FormatOptions() = 0;
virtual std::unique_ptr<IExpression> ParseInput(const std::wstring& input) = 0;
virtual std::shared_ptr<IGraph> CreateGrapher(const IExpression* expression) = 0;
virtual std::shared_ptr<Graphing::IGraph> CreateGrapher() = 0;
virtual std::wstring Serialize(const IExpression* expression) = 0;
};
}