65.9K
CodeProject 正在变化。 阅读更多。
Home

使用 WebMatrix 制作的 ASP.NET Web Pages 网站

starIconstarIconstarIconstarIconstarIcon

5.00/5 (1投票)

2012年11月1日

CPOL

4分钟阅读

viewsIcon

18841

downloadIcon

562

输入一个函数字符串和一个范围,该网站会将其转换为 f(x,y) 图。

我曾在 20 世纪 80 年代学习计算机科学,但从未在这个领域找到职业。但在大学时,我知道我喜欢计算机图形学和编译器构造。

引言

这个 ASP.NET Web Pages 网站允许您绘制 3D 中自定义的 x 和 y 函数。这个项目面向即将发现或已经发现了 WebMatrix 的新手编程爱好者。MVC 并不容易,它适用于专业程序员,但 Web Pages 却对用户友好,并且使用起来很有趣。当您了解 Razor 的基础知识以及如何执行某些操作(例如如何让 cshtml 文件生成图像或如何在文件之间传递数据)时,WebMatrix 的可能性是无限的。

背景

2006 年,我开始使用新的 Visual Studio C# Express Edition 编写 C# 代码,并编写了一个程序来绘制 3D 图形。几年后,我编写了一个 Silverlight 应用程序,绘制了 x 的一个函数。当 WebMatrix 首次发布时,我想到我可以创建一个使用 Razor 语法的 Web Pages 网站,该语法使用了我之前编写的项目的代码。所以我开始创建一个网站,访问者可以在其中输入包含 x 和 y 函数公式的文本字符串以及一个范围,然后我的网站将生成包含 3D 函数的图像。当我第一次开始使用 WebMatrix Web Pages 时,我感觉就像一个在糖果店里的孩子,而且现在仍然如此!

CoCo\R 编译器编译器

为了生成扫描器和解析器,我使用了 CoCo\R。这是一个程序,您向其提供 ATG 语言定义文件,它将其转换为 C# 源代码。这比我预期的要容易,从文本字符串创建基于堆栈的计算器的过程实际上非常简单。

以下是我 ATG 文件中的几行代码

COMPILER FunctionCalc

CHARACTERS

letter = 'A'..'Z' + 'a'..'z'.
digit = '0'..'9'.

TOKENS

VARIABLEX = 'x' | 'X'.
VARIABLEY = 'y' | 'Y'.
NUMBER = digit { digit } [ "." digit { digit } ].
SIN = "sin" | "Sin" | "SIN".
COS = "cos" | "Cos" | "COS".

PRODUCTIONS

FunctionCalc =
  Expression (. assemble.AddMnemonic(Mnemonic.Actions.end, 0.0); .) 
  .
Expression =
  Term
  { '+' Term (. assemble.AddMnemonic(Mnemonic.Actions.add, 0.0); .)
  | '-' Term (. assemble.AddMnemonic(Mnemonic.Actions.subtract, 0.0); .)
  }
  .

我将把 ATG 文件添加到源代码中。

三个组件。

有三个组件,1) 绘制 3D 对象的源,2) 将文本字符串转换为一系列指令以计算输入的 x 和 y 函数的代码。而第 3) 部分是实际的网站。

绘制 3D 图形。

我读了很多关于 C# 的书,但我没有看到任何示例代码,所以我以我认为最好的方式编写了这个模块。

public class Storage
{
    public double CenterX = 295.0;
    public double CenterY = 295.0;

    public int NumberOfVectors = 0;
    public int NumberOfVertices = 0;
    public int NumberOfFaces = 0;

    public int MAXNumberOfVectors = 0;
    public int MAXNumberOfVertices = 0;
    public int MAXNumberOfFaces = 0;

    public Vector[] StoreVectors;
    public int[] StoreVerticesFrom;
    public int[] StoreVerticesTo;
    public Point2D[] StorePoints;
    public double[] StoreDistanceToEyePerPoint;

    public Face[] StoreFaces;
    public double[] StoreFaceDistances;
    public double[] StoreSortedFacesValue;
    public int[] StoreSortedFacesKey;

我为矩阵和向量的乘法创建了运算符,它们都是我源代码中的类类型。

public class myMatrix
{
    public double a11, a12, a13, a14, a21, a22, a23, a24, a31, a32, a33, a34, a41, a42, a43, a44;

public class Vector
{
    public double v1, v2, v3, v4;

    public Vector(double v1, double v2, double v3, double v4)
    {
        this.v1 = v1;
        this.v2 = v2;
        this.v3 = v3;
        this.v4 = v4;
    }

计算和绘制函数

public class myImage
{
    public static myMatrix P;
    public static double sizeObject = 100.0;
    public static Vector Eye = new Vector(120, 135, 175, 1.0);
    public static string fstring = "cos(x)*sin(y)*pi";
    public static int raster = 20;
    public static double xmin = -3.14;
    public static double xmax = 3.14;

    public myImage(Graphics g, Vector vantagepoint, String fxystring, 
       double range, int resolution, double scale, Function.SolidType st)
    {
        Eye = vantagepoint;
        fstring = fxystring;
        xmin = -range;
        xmax = +range;
        sizeObject = scale;
        raster = resolution;
        string errorstring = "";

        g.FillRectangle(Brushes.Black, new Rectangle(0, 0, 590, 590));
        
        Execute ex = new Execute(10000, 5000, fstring);

        if (!ex.parsingerror)
        {
            P = new myMatrix(Eye);

            Function F = new Function(ex, raster, xmin, xmax, sizeObject, Eye, out errorstring);

            if (errorstring == "") { F.DrawSolid(P, g, Color.Blue, st); }
            else g.DrawString("Computing Error:" + '\n' + errorstring, new Font("Times New Roman", 30), Brushes.Red, 20, 20);
        }
        else g.DrawString("Parsing Error" + '\n' + "check formula", new Font("Times New Roman", 30), Brushes.Red, 20, 20);
    }
}

翻译器。

通过稍微更改 CoCo\R 生成的代码,就可以相对容易地创建一个 C# 模块,将包含函数的字符串翻译成一系列指令以计算函数。我编写了几个类来生成程序以处理基于堆栈的计算器的计算。灵感来自于我第一次拥有 Commodore 64 计算机时读到的一本书。

public class Mnemonic
{
    public enum Actions
    {
        sin, cos, tan, add, subtract, multiply, divide, negate, number, variablex,
        variabley, e, pi, abs, acos, asin, atan, cosh, exp, log, sinh, sqrt,
        tanh, pow, end
    }

    public Actions action;
    public double argument;

    public Mnemonic(Actions action, double argument)
    {
        this.action = action;
        this.argument = argument;
    }

    public void AddMnemonic(Actions action, double argument)
    {
        this.action = action;
        this.argument = argument;
    }
}

然后我编写了几个方法来执行翻译器生成的程序。

public double FunctionExecute(double x, double y, out string errorString)
{
    int programcounter = 0;
    Mnemonic m = assemble.GetMnemonic(programcounter);
    errorString = "";

    double Loperand, Roperand, Result;

    while (m.action != Mnemonic.Actions.end)
    {
        try
        {
            switch (m.action)
            {
                case Mnemonic.Actions.sin: Loperand = stack.Pop(); Result = Math.Sin(Loperand); TestResult(Result, "Sin"); stack.Push(Result); break;
                case Mnemonic.Actions.cos: Loperand = stack.Pop(); Result = Math.Cos(Loperand); TestResult(Result, "Cos"); stack.Push(Result); break;
                case Mnemonic.Actions.tan: Loperand = stack.Pop(); Result = Math.Tan(Loperand); TestResult(Result, "Tan"); stack.Push(Result); break;
                case Mnemonic.Actions.add: Roperand = stack.Pop(); Loperand = stack.Pop(); Result = Loperand + Roperand; ; TestResult(Result, "Add"); stack.Push(Result); break;
                case Mnemonic.Actions.subtract: Roperand = stack.Pop(); Loperand = stack.Pop(); Result = Loperand - Roperand; TestResult(Result, "Subtract"); stack.Push(Result); break;
                case Mnemonic.Actions.multiply: Roperand = stack.Pop(); Loperand = stack.Pop(); Result = Loperand * Roperand; TestResult(Result, "Multiply"); stack.Push(Result); break;
                case Mnemonic.Actions.divide: Roperand = stack.Pop(); Loperand = stack.Pop(); Result = Loperand / Roperand; TestResult(Result, "Divide"); stack.Push(Result); break;
                case Mnemonic.Actions.negate: Loperand = stack.Pop(); Result = -Loperand; TestResult(Result, "Negate"); stack.Push(Result); break;
                case Mnemonic.Actions.variablex: stack.Push(x); break;
                case Mnemonic.Actions.variabley: stack.Push(y); break;
                case Mnemonic.Actions.number: stack.Push(m.argument); break;
                case Mnemonic.Actions.e: stack.Push(Math.E); break;
                case Mnemonic.Actions.pi: stack.Push(Math.PI); break;
                case Mnemonic.Actions.abs: Loperand = stack.Pop(); Result = Math.Abs(Loperand); TestResult(Result, "Abs"); stack.Push(Result); break;
                case Mnemonic.Actions.acos: Loperand = stack.Pop(); Result = Math.Acos(Loperand); TestResult(Result, "Acos"); stack.Push(Result); break;
                case Mnemonic.Actions.asin: Loperand = stack.Pop(); Result = Math.Asin(Loperand); TestResult(Result, "Asin"); stack.Push(Result); break;
                case Mnemonic.Actions.atan: Loperand = stack.Pop(); Result = Math.Atan(Loperand); TestResult(Result, "Atan"); stack.Push(Result); break;
                case Mnemonic.Actions.cosh: Loperand = stack.Pop(); Result = Math.Cosh(Loperand); TestResult(Result, "Cosh"); stack.Push(Result); break;
                case Mnemonic.Actions.exp: Loperand = stack.Pop(); Result = Math.Exp(Loperand); TestResult(Result, "Exp"); stack.Push(Result); break;
                case Mnemonic.Actions.log: Loperand = stack.Pop(); Result = Math.Log(Loperand); TestResult(Result, "Log"); stack.Push(Result); break;
                case Mnemonic.Actions.sinh: Loperand = stack.Pop(); Result = Math.Sinh(Loperand); TestResult(Result, "Sinh"); stack.Push(Result); break;
                case Mnemonic.Actions.sqrt: Loperand = stack.Pop(); Result = Math.Sqrt(Loperand); TestResult(Result, "Sqrt"); stack.Push(Result); break;
                case Mnemonic.Actions.tanh: Loperand = stack.Pop(); Result = Math.Tanh(Loperand); TestResult(Result, "Tanh"); stack.Push(Result); break;
                case Mnemonic.Actions.pow: Roperand = stack.Pop(); Loperand = stack.Pop(); Result = Math.Pow(Loperand, Roperand); stack.Push(Result); break;
                default: throw new Exception("default in Function Execute");
            }
        }
        catch (ArithmeticException aex)
        {
            errorString = aex.Message;
            return (0.0);
        }
        catch (ArgumentOutOfRangeException aor)
        {
            errorString = aor.Message;
            return (0.0);
        }
        m = assemble.GetMnemonic(++programcounter);
        if (programcounter > _memorySize)
        {
            throw new Exception("Program Counter out of bounds");
        }
    }
    return (stack.Pop());
}

网站。

我从互联网上免费下载了网站的模板,网址:http://www.freecsstemplates.org/。它很漂亮,并且很容易集成到网站中。此模板就像一个框架,首先您拥有下载的模板网站和示例内容,然后您只需用您自己的内容替换示例内容即可。下一个代码片段是 Image.cshtml 文件,它生成包含 3D 函数的图形的 jpg 文件。

@using System.Drawing.Drawing2D;
@using System.Drawing.Imaging;
@using System.Globalization;
@using _3DFxy1_110909;

@{
    Bitmap bitmap = new Bitmap(600, 600);
    Graphics g = Graphics.FromImage(bitmap);
    Vector vantagepoint = new Vector((double)AppState["EyeX"], (double)AppState["EyeY"], (double)AppState["EyeZ"], 1.0);
    String fxystring = AppState["fstring"].ToString();
    double range = (double)AppState["range"];
    int raster = (int)AppState["raster"];
    double scale = (double)AppState["scale"];
   
    Function.SolidType st = Function.SolidType.Intelligent;
   
    string ststr = AppState["solidtype"].ToString();
    if (ststr == "White") { st = Function.SolidType.White; }
    if (ststr == "Random") { st = Function.SolidType.Random; }
    if (ststr == "Intelligent") { st = Function.SolidType.Intelligent; }
   
    myImage img = new myImage(g,vantagepoint,fxystring,range,raster,scale, st);
   
    Response.ContentType = "image/jpeg";
    Response.AddHeader("content-disposition", "inline; filename=test.jpg");  
    bitmap.Save(Response.OutputStream, System.Drawing.Imaging.ImageFormat.Jpeg);
   
    g.Dispose();
    bitmap.Dispose();
}

从 _AppStart.cshtml,这些是在应用程序启动时加载到变量中的默认设置

@{
    AppState["EyeX"] = 120.0;
    AppState["EyeY"] = 135.0;
    AppState["EyeZ"] = 175.0;
    AppState["vp"] = 1;
    
    AppState["fstring"] = "cos(x)*sin(y) * pi";
    AppState["range"] = 3.14;
    
    AppState["raster"] = 20;
    AppState["scale"] = 100.0;
    
    AppState["solidtype"] = "Intelligent";
}

在 Default.cshtml 中,您可以通过网站输入变量

@if (IsPost) {
    {AppState["fstring"] = Request["finput"].ToString();}
    try {AppState["range"] = Math.Abs(double.Parse(Request["domain"]));}
    catch {AppState["range"] = 3.14; <h3>You entered an illegal value for Domain, will enter the default value.</h3>}
    try{AppState["scale"] = Math.Abs(double.Parse(Request["scale"]));}
    catch { AppState["scale"] = 100.0; <h3>You entered an illegal value for Scale, will enter the default value.</h3>}
    {AppState["raster"] = int.Parse(Request["resolution"]);}
    {AppState["solidtype"] = Request["solidtype"].ToString();}
    {AppState["vp"] = int.Parse(Request["vantagepoint"]);}
}

接下来是这行代码,它从上面列出的 Image.cshtml 文件插入一个 jpg 图像

<img src="@Href("~/Image.cshtml")" alt="Fxy" />

这里有两个截图,一个带有输入,另一个带有结果

有三种渲染模式,这种模式(智能)生成一个像温度图一样的图像。

关注点

我非常喜欢使用 WebMatrix 制作这个网站。 使用 Razor 语法的 ASP.NET Web Pages 使得构建具有您想要的功能和外观的网站变得非常容易。 很容易理解。 并且很有趣!

历史

这是我为 Code Project 网站撰写的第一篇文章。

© . All rights reserved.