該軟件用于將數(shù)學(xué)表達(dá)式以圖形的形式顯示出來.軟件中定義一套簡單易學(xué)的腳本語言,用于描述數(shù)學(xué)表達(dá)式.使用時(shí)需要先要將數(shù)學(xué)表達(dá)式寫成該腳本的形式,解析腳本代碼以生成相應(yīng)的圖形.能夠生成曲線圖形和曲面圖形. 目前只能處理顯示表達(dá)式.
軟件介紹
(1)主界面
在文件夾” MathScript”中,提供了500個(gè)以上已經(jīng)寫好的數(shù)學(xué)表達(dá)式腳本文件.將數(shù)學(xué)腳本文件拖入到主界面中,即顯示其圖形.亦可以通過菜單項(xiàng)打開腳本文件.
如果圖形是一個(gè)3D圖形,那么軟件會(huì)自動(dòng)為你切換到3D顯示模式.使用鼠標(biāo)右鍵拖動(dòng),以旋轉(zhuǎn)視角.鍵盤上的WSAD,QERF,上下左右也對(duì)視角進(jìn)行控制.這個(gè)不細(xì)講了,用戶自己去體驗(yàn)吧.如果圖形是一個(gè)2D圖形,打開時(shí)為二維顯示模式,用戶可以按下鍵盤上的’O’鍵,在3D,2D間進(jìn)行切換.鼠標(biāo)滾輪可以對(duì)視口進(jìn)行縮放.
下圖為一個(gè)二維的視圖:
按下鍵盤上的’U’鍵,會(huì)在左邊顯示一套UI控件:
用于對(duì)一些顯示屬性的操作.可惜我的引擎目前不支持中文字體,所以先將就著用吧.
按下鍵盤上的’0’鍵,會(huì)在右邊顯示一個(gè)紋理選擇控件,用于設(shè)置數(shù)學(xué)曲面的紋理:
UI面板上的也可以控制紋理選擇控件.
紋理文件存放在” Texture”文件夾下,用戶可以將自己喜歡的圖像文件放入其中.軟件會(huì)自動(dòng)為你加載.用戶亦可以直接將圖像文件拖入到主界面中.對(duì)圖像格式的支持包括: dds,bmp,jpg,png,gif,tga.
當(dāng)打開一個(gè)數(shù)學(xué)圖形后,按下鍵盤上的’7’鍵,會(huì)顯示一個(gè)滑動(dòng)條控件,用于控制所顯示的圖形范圍. 控件
也可以.滑動(dòng)條上有兩個(gè)滑塊,分別表示其顯示范圍的最小與最大,如下圖:黃線處為顯的區(qū)域,綠線處為未顯示的區(qū)域.
最小滑塊與最大滑塊可以錯(cuò)開:
下圖為對(duì)曲面圖形的操作
下圖為對(duì)曲線圖形的操作:
當(dāng)打開一個(gè)數(shù)學(xué)曲面圖形后, 按下鍵盤上的’P’鍵或點(diǎn)下會(huì)在右下角顯示兩個(gè)對(duì)曲面上曲線進(jìn)行操作的控件.
如下圖所展示:
圖中綠色曲線為第一維度的曲線,紅色曲線為第二維度的曲線.
代碼與自定義擴(kuò)展
MathExpression模塊中為數(shù)學(xué)表達(dá)式及腳本解析的代碼邏輯.
(1)主要接口
文件”math_expression_parser.h”提供了對(duì)表達(dá)式的解析函數(shù)
// 設(shè)置參數(shù)值
void SetParameterValue(char c, float value);
// 清空參數(shù)值
void ClearParameterValues();
// 表達(dá)式解析
bool ParseExpression(const char* szExpression, float& rst);
// 括號(hào)內(nèi)的子表達(dá)式解析
bool ParseBracketExpression(const char* szExpression,
unsigned int& pos, float& rst,
unsigned int bracketIndex, bool endComma);
可以針求獨(dú)立表達(dá)式的結(jié)果,如:
bool sus = ParseExpression(“sin(PI*3) + 10*E*log(100)”, rst);
文件”math_script_parser.h”提供了一個(gè)對(duì)象MathScriptParser,用于對(duì)數(shù)學(xué)腳本的解析
class MathScriptParser
{
public:
...
// 加載腳本文件
bool LoadFile(const char* szFile);
// 處理內(nèi)存數(shù)據(jù)
bool ProcessMemory(const char* bufPtr, unsigned int bufSize);
...
};
(2)添加或設(shè)置常量值
開發(fā)者可以通過”const_value.h”文件中的如下函數(shù)對(duì)常量進(jìn)行添加或修改
// 添加或設(shè)置常量值
bool SetConstValue(const char* szName, float value);
(3)添加或設(shè)置函數(shù)運(yùn)算符
程序中的運(yùn)算符操作是以函數(shù)指針的方式使用,開發(fā)者可以將自己實(shí)現(xiàn)的函數(shù)設(shè)置到系統(tǒng)中.
有6種運(yùn)算符函數(shù)類型
// 單目運(yùn)算函數(shù)
typedef float (*SINGLE_OPERATOR_FUNC)(float);
// 雙目運(yùn)算函數(shù)
typedef float (*TWIN_OPERATOR_FUNC)(float, float);
// 三目運(yùn)算函數(shù)
typedef float (*THREE_OPERATOR_FUNC)(float, float, float);
// 四目運(yùn)算函數(shù)
typedef float (*FOUR_OPERATOR_FUNC)(float, float, float, float);
// 對(duì)ValueNode的運(yùn)算函數(shù)(輸入ValueNode,輸出一個(gè)浮點(diǎn)數(shù))
typedef float (*VALUENODE_TO_FLOAT_OPERATOR_FUNC)(const ValueNode*);
// 對(duì)ValueNode的運(yùn)算函數(shù)(輸入ValueNode,輸出ValueNode)
typedef void (*VALUENODE_CONVERT_OPERATOR_FUNC)(const ValueNode*, ValueNode*);
開發(fā)者可自定義運(yùn)算函數(shù)后,使用如下接口,將其添加到系統(tǒng)中.
// 添加或設(shè)置運(yùn)算函數(shù)
bool SetSingleOperator(const char* szName, SINGLE_OPERATOR_FUNC func);
bool SetTwinOperator(const char* szName, TWIN_OPERATOR_FUNC func);
bool SetThreeOperator(const char* szName, THREE_OPERATOR_FUNC func);
bool SetFourOperator(const char* szName, FOUR_OPERATOR_FUNC func);
bool SetValueNodeToFloatOperator(const char* szName, VALUENODE_TO_FLOAT_OPERATOR_FUNC func);
bool SetValueNodeConvertOperator2(const char* szName, VALUENODE_CONVERT_OPERATOR_FUNC func);
需要注意這兩個(gè)宏:
#define OPERATOR_NAME_LENGTH 24 // 操作符名的最大長度
#define MAX_FUNCTIONS_COUNT 256 // 運(yùn)算函數(shù)的最大數(shù)目
如果不滿足要求,請(qǐng)自己修改這兩個(gè)宏值
代碼中的Integraller模塊為額外添加的數(shù)學(xué)函數(shù).
在文件MathGraph.cpp中將額外的數(shù)學(xué)函數(shù)注冊(cè)到系統(tǒng)中:
void CMathGraph::SetupIntergralFunctions()
{
Why::SetTwinOperator("Trapezia", TestTrapezia);
Why::SetTwinOperator("Simpson", TestSimpson);
Why::SetTwinOperator("ATrapezia", TestATrapezia);
Why::SetTwinOperator("Romberg", TestRomberg);
Why::SetTwinOperator("ValuePq", TestValuePq);
Why::SetTwinOperator("LegdGauss", TestLegdGauss);
Why::SetSingleOperator("Gamma", YfGamma);
Why::SetTwinOperator("Gamma2", YfGamma2);
Why::SetSingleOperator("Erf", YfErf);
Why::SetThreeOperator("Beta", YfBeta);
Why::SetThreeOperator("Gass", YfGass);
Why::SetTwinOperator("Student", YfStudent);
Why::SetTwinOperator("Chii", YfChii);
Why::SetThreeOperator("Fdisp", YfFdisp);
Why::SetSingleOperator("Sinn", YfSinn);
Why::SetSingleOperator("Coss", YfCoss);
Why::SetSingleOperator("Expp", YfExpp);
}