目录
介绍
本文非常简要地(在基本层面上)介绍了如何使用C# ASP.NET在R图面中绘制用户交互式3D R2。该示例使用户能够在以下5个方面与绘图进行交互:
- 函数表达式z = f(x,y)
- 领域
- 集成步骤
- 绕X、Y和Z轴旋转
- 模型(线框或填充)
背景
- R3中的点是一组3个浮点值(x,y,z)用于定义位置。
- R函数中的R2是z = f(x,y)形式的表达式,其中x和y是函数域的子集。
- R域中的R2是R2或更好的XY平面。
笛卡尔坐标
目标是获得一组z坐标,将通用函数z=f(x,y)应用于离散域,或者更好地将定义的x和y点的矩阵应用于上面的图像网格。
如何执行计算
首先,我们需要定义领域。让我们选择[-1.7,1.3]作为x,选择[-2.1,2.5]作为y,这意味着x将从-1.7运行到1.3,y将从-2.1运行到2.5。
如何获取积分数据
当我们使用R(实数)坐标时,我们在2个点坐标之间有无限个点,因此为此,我们创建了一个非常小的变量,我们称之为“步长”,这意味着我们将使用积分通过“步长”在2个坐标之间行走来获得网格点。
例如,如果我们将步骤定义为0.1,则代码将如下所示:
double x0 = -1.7, x1 = 1.3, y0 = -2.1, y1 = 2.5;
double step = 0.1;
double x=x0;
while(x<=x1)
{
//...
y=y0;
while(y<=y1)
{
//...
y+=step;
}
x+=step;
}
基于上述定义,我们可以使用通用函数z = f(x,y)来处理运行XY离散子域的z坐标计算。
double x0=-1.7, x1=1.3, y0=-2.1, y1=2.5;
double step = 0.1;
double x=x0;
double z;
while(x<=x1)
{
//...
y=y0;
while(y<=y1)
{
//...
y+=step;
z = function(x,y); // at this point we have x,y
// and calculate the z coordinates
// all we need now is to keep this information in a data structure
// to plot the whole data in a next step
}
x+=step;
}
棘手的部分
我们可以使用带有字符串表达式的MathExpressionParser,但在这里,我借助放置替换标签的模板使其更简单。
这个过程很简单:
- 读取模板txt文件,
- 替换标签,
- 并编写显示图像的ASPX文件。
- 注意:您必须对将写入文件的文件夹具有写入权限***
string contents = ReadFile(Server.MapPath("./dynafuncapp.txt"));
contents = contents.Replace("@EXPRESSION", functionStr);
SaveFile(Server.MapPath("./dynacontent.aspx"), contents);
// note you must have write access to the folder ***
把所有东西放在一起
特别说明:命名更好的类、变量和函数,它使注释代码变得不必要或至少是多余的。
Pen thePen =
new Pen(Color.FromArgb(ix1, iy1, iz1)); // creates a pen or something else? :-)
模板文件
<%@ Page Language="c#" Debug="true" Explicit="True" %>
<%@ Import Namespace="System.IO" %>
<%@ Import Namespace="System.Drawing" %>
<%@ Import Namespace="System.Drawing.Imaging" %>
<%@ Import Namespace="System.Globalization" %>
<script language="C#" runat="server">
// Rotate a 3d Point around X axis given by angl in radians
void RotX(ref double cy, ref double cz, double angle)
{
double y = cy * System.Math.Cos(angle) - cz * System.Math.Sin(angle);
double z = cy * System.Math.Sin(angle) + cz * System.Math.Cos(angle);
cy = y;
cz = z;
}
// Rotate a 3d Point around Y axis given by angl in radians
void RotY(ref double cx, ref double cz, double angle)
{
double x = cx * System.Math.Cos(angle) - cz * System.Math.Sin(angle);
double z = cx * System.Math.Sin(angle) + cz * System.Math.Cos(angle);
cx = x;
cz = z;
}
// Rotate a 3d Point around Z axis given by angl in radians
void RotZ(ref double cy, ref double cx, double angle)
{
double x = cx * System.Math.Cos(angle) - cy * System.Math.Sin(angle);
double y = cx * System.Math.Sin(angle) + cy * System.Math.Cos(angle);
cx = x;
cy = y;
}
protected double stFunction(double x, double y)
{
return (@EXPRESSION);
}
public void SaveFile(string filepath, string outputstr)
{
System.IO.FileStream file = new System.IO.FileStream
(filepath, System.IO.FileMode.Create, System.IO.FileAccess.Write);
System.IO.StreamWriter writer = new System.IO.StreamWriter(file);
writer.Write(outputstr);
writer.Flush();
writer.Close();
file.Close();
}
private void Page_Load(object sender, System.EventArgs e)
{
System.Globalization.CultureInfo customCulture =
(System.Globalization.CultureInfo)System.Threading.Thread.CurrentThread.
CurrentCulture.Clone();
customCulture.NumberFormat.NumberDecimalSeparator = ".";
System.Threading.Thread.CurrentThread.CurrentCulture = customCulture;
int screenSize = Session["screenSize"] !=null ?(int) Session["screenSize"] :200;
double xleft = Session["xleft"] !=null ?(double) Session["xleft"] :-2;
double xright = Session["xright"] !=null ?(double) Session["xright"] :2;
double yleft = Session["yleft"] !=null ?(double) Session["yleft"] :-2;
double yright = Session["yright"] !=null ?(double) Session["yright"] :2;
double step = Session["step"] !=null ?(double) Session["step"] :0.05;
if (Math.Abs(step) < 1.0E-5)
{
Response.Write("Integration is 0");
return;
}
int maxcount = 1000000;
int sizeX = (int)Math.Ceiling(((xright - xleft) / step)) + 1;
int sizeY = (int)Math.Ceiling(((yright - yleft) / step)) + 1;
int size = sizeX * sizeY;
if (size > maxcount)
{
Response.Write("Overflow");
return;
}
double[,] surface = new double[sizeX, sizeY];
double x = xleft;
double y;
int indexX = 0;
int indexY = 0;
double zmin=+1.0E10, zmax=-1.0E10;
while (x <= xright)
{
y = yleft;
indexY = 0;
while (y <= yright)
{
surface[indexX, indexY] = stFunction(x, y);//mp.eval(x, y);
if (zmin > surface[indexX, indexY]) zmin = surface[indexX, indexY];
if (zmax < surface[indexX, indexY]) zmax = surface[indexX, indexY];
indexY++;
y += step;
}
x += step;
indexX++;
}
if (Math.Abs(zmin)<1.0E-5) zmin = 0;
if (Math.Abs(zmax)<1.0E-5) zmax = 0;
Session["surface"] = surface;
Bitmap newBitmap = new Bitmap(screenSize, screenSize, PixelFormat.Format32bppArgb);
Graphics g = Graphics.FromImage(newBitmap);
Pen blackPen = new Pen(Color.Black);
Color clrBackground = Color.Black;
g.FillRectangle(new SolidBrush(clrBackground),
new Rectangle(0, 0, screenSize, screenSize));
Rectangle rect = new Rectangle(0, 0, screenSize, screenSize);
double xmin = Session["xleft"] !=null ?(double)Session["xleft"]:-2;
double ymin = Session["yleft"] !=null ?(double)Session["yleft"]:-2;
double xmax = Session["xright"]!=null ?(double)Session["xright"]:2;
double ymax = Session["yright"]!=null ?(double)Session["yright"]:2;
double eyex = Session["eyex"] !=null ?(double)Session["eyex"]:0;
double eyey = Session["eyey"] !=null ?(double)Session["eyey"]:0;
double eyez = Session["eyez"] !=null ?(double)Session["eyez"]:100;
int idx = 0;
x = xmin;
while ((x < xmax) && (idx < sizeX - 1))
{
y = ymin;
int idy = 0;
while ((y < ymax) && (idy < sizeY - 2) && (idx < sizeX - 1))
{
double z1 = surface[idx, idy];
double z2 = surface[idx + 1, idy];
double z3 = surface[idx + 1, idy + 1];
double z4 = surface[idx, idy + 1];
double xx1 = x, yy1 = y, zz1 = z1;
double xx2 = x + step, yy2 = y, zz2 = z2;
double xx3 = x + step, yy3 = y + step, zz3 = z3;
double xx4 = x, yy4 = y + step, zz4 = z4;
RotX(ref yy1, ref zz1, eyex);
RotY(ref xx1, ref zz1, eyey);
RotZ(ref xx1, ref yy1, eyez);
RotX(ref yy2, ref zz2, eyex);
RotY(ref xx2, ref zz2, eyey);
RotZ(ref xx2, ref yy2, eyez);
RotX(ref yy3, ref zz3, eyex);
RotY(ref xx3, ref zz3, eyey);
RotZ(ref xx3, ref yy3, eyez);
RotX(ref yy4, ref zz4, eyex);
RotY(ref xx4, ref zz4, eyey);
RotZ(ref xx4, ref yy4, eyez);
//x = (100.0 * x) / z1;
//y = (100.0 * y) / z1;
double p1x = ((xx1 - xmin) / (xmax - xmin)) * (screenSize - 0.0) + 0.0;
double p1y = ((yy1 - ymin) / (ymax - ymin)) * (screenSize - 0.0) + 0.0;
double p2x = ((xx2 - xmin) / (xmax - xmin)) * (screenSize - 0.0) + 0.0;
double p2y = ((yy2 - ymin) / (ymax - ymin)) * (screenSize - 0.0) + 0.0;
double p3x = ((xx3 - xmin) / (xmax - xmin)) * (screenSize - 0.0) + 0.0;
double p3y = ((yy3 - ymin) / (ymax - ymin)) * (screenSize - 0.0) + 0.0;
double p4x = ((xx4 - xmin) / (xmax - xmin)) * (screenSize - 0.0) + 0.0;
double p4y = ((yy4 - ymin) / (ymax - ymin)) * (screenSize - 0.0) + 0.0;
int ip1x = (int)Math.Ceiling(p1x);
int ip1y = (int)Math.Ceiling(p1y);
double colorFactorX = (xx1-xmin)/(xmax-xmin);
int ix1 = (int)Math.Abs((255.0 * colorFactorX));
if (ix1 < 0) ix1 = 0;
if (ix1 > 255) ix1 = 255;
double colorFactorY = (yy1-ymin)/(ymax-ymin);
int iy1 = (int)Math.Abs((255.0 * colorFactorY));
if (iy1 < 0) iy1 = 0;
if (iy1 > 255) iy1 = 255;
double colorFactorZ = (zz1-zmin)/(zmax-zmin);
int iz1 = (int)Math.Abs((255.0 * colorFactorZ));
if (iz1 < 0) iz1 = 0;
if (iz1 > 255) iz1 = 255;
int ip2x = (int)Math.Ceiling(p2x);
int ip2y = (int)Math.Ceiling(p2y);
int ip3x = (int)Math.Ceiling(p3x);
int ip3y = (int)Math.Ceiling(p3y);
int ip4x = (int)Math.Ceiling(p4x);
int ip4y = (int)Math.Ceiling(p4y);
int view = Session["view"]!=null?(int)Session["view"]:1;
if (view == 1)
{
Pen thePen = new Pen(Color.FromArgb(ix1, iy1, iz1));
g.DrawLine(thePen, ip1x, ip1y, ip2x, ip2y);
g.DrawLine(thePen, ip1x, ip1y, ip4x, ip4y);
g.DrawLine(thePen, ip2x, ip2y, ip4x, ip4y);
g.DrawLine(thePen, ip2x, ip2y, ip4x, ip4y);
g.DrawLine(thePen, ip2x, ip2y, ip3x, ip3y);
g.DrawLine(thePen, ip3x, ip3y, ip4x, ip4y);
}
else
if (view == 2)
{
Point[] points = new Point[3];
points[0].X = ip1x;
points[0].Y = ip1y;
points[1].X = ip2x;
points[1].Y = ip2y;
points[2].X = ip4x;
points[2].Y = ip4y;
Brush theBrush = new SolidBrush(Color.FromArgb(ix1, iy1, iz1));
g.FillPolygon(theBrush, points);
points = new Point[3];
points[0].X = ip2x;
points[0].Y = ip2y;
points[1].X = ip4x;
points[1].Y = ip4y;
points[2].X = ip3x;
points[2].Y = ip3y;
g.FillPolygon(theBrush, points);
}
idy++;
y += step;
}
x += step;
idx++;
}
MemoryStream tempStream = new MemoryStream();
newBitmap.Save(tempStream, ImageFormat.Png);
Response.ClearContent();
Response.ContentType = "image/png";
Response.BinaryWrite(tempStream.ToArray());
Response.Flush();
}
</script>
<html xmlns="http://www.w3.org/1999/xhtml">
<head><title>Dynafunc</title>
</head>
<body style="padding-right: 0px; padding-left: 0px; padding-bottom: 0px; margin: 0px;
padding-top: 0px; text-align: center;">
<form id="form1" runat="server">
</form>
</body>
</html>
主文件
<%@ Page Language="c#" Debug="true" Explicit="True" %>
<%@ Import Namespace="System.IO" %>
<%@ Import Namespace="System.Drawing" %>
<%@ Import Namespace="System.Drawing.Imaging" %>
<%@ Import Namespace="System.Globalization" %>
<script language="C#" runat="server">
public string ReadFile(string filepath)
{
System.IO.FileStream file = new System.IO.FileStream
(filepath, System.IO.FileMode.Open, System.IO.FileAccess.Read);
System.IO.StreamReader reader = new System.IO.StreamReader(file);
string contents = reader.ReadToEnd();
reader.Close();
file.Close();
return contents;
}
public void SaveFile(string filepath, string outputstr)
{
System.IO.FileStream file = new System.IO.FileStream
(filepath, System.IO.FileMode.Create, System.IO.FileAccess.Write);
System.IO.StreamWriter writer = new System.IO.StreamWriter(file);
writer.Write(outputstr);
writer.Flush();
writer.Close();
file.Close();
}
private void Page_Load(object sender, System.EventArgs e)
{
System.Globalization.CultureInfo customCulture =
(System.Globalization.CultureInfo)System.Threading.Thread.
CurrentThread.CurrentCulture.Clone();
customCulture.NumberFormat.NumberDecimalSeparator = ".";
System.Threading.Thread.CurrentThread.CurrentCulture = customCulture;
outputTxt.Text = "";
String functionStr = function.Text;
functionStr = functionStr.Replace("sin", "Math.Sin");
functionStr = functionStr.Replace("cos", "Math.Cos");
functionStr = functionStr.Replace("cos", "Math.Cos");
functionStr = functionStr.Replace("sqrt", "Math.Sqrt");
functionStr = functionStr.Replace("sinh", "Math.Sinh");
functionStr = functionStr.Replace("acos", "Math.Acos");
functionStr = functionStr.Replace("cosh", "Math.Cosh");
functionStr = functionStr.Replace("abs", "Math.Abs");
functionStr = functionStr.Replace("asin", "Math.Asin");
functionStr = functionStr.Replace("ceiling", "Math.Ceiling");
functionStr = functionStr.Replace("exp", "Math.Exp");
functionStr = functionStr.Replace("floor", "Math.Floor");
functionStr = functionStr.Replace("log", "Math.Log");
functionStr = functionStr.Replace("log10", "Math.Log10");
functionStr = functionStr.Replace("pi", "Math.PI");
functionStr = functionStr.Replace("pow", "Math.Pow");
functionStr = functionStr.Replace("tan", "Math.Tan");
functionStr = functionStr.Replace("tanh", "Math.Tanh");
functionStr = functionStr.Replace("round", "Math.Round");
string contents = ReadFile(Server.MapPath("./templates/template.txt"));
contents = contents.Replace("@EXPRESSION", functionStr);
SaveFile(Server.MapPath("./images/dynacontent.aspx"), contents);
int iscreenSize = int.Parse(screenSize.Text);
double xleft = double.Parse(xmin.Text);
double xright = double.Parse(xmax.Text);
double yleft = double.Parse(ymin.Text);
double yright = double.Parse(ymax.Text);
double step = double.Parse(integ.Text);
if (Math.Abs(step) < 1.0E-5)
{
Response.Write("Integration is 0");
return;
}
int maxcount = 1000000;
int sizeX = (int)Math.Ceiling(((xright - xleft) / step)) + 1;
int sizeY = (int)Math.Ceiling(((yright - yleft) / step)) + 1;
int size = sizeX * sizeY;
outputTxt.Text += "Grid size = " + size.ToString() + " points";
if (size > maxcount)
{
Response.Write("Overflow");
return;
}
outputTxt.Text += "<br>[" + sizeX.ToString() +
"," + sizeY.ToString() + "]";
Session["screenSize"] = iscreenSize;
Session["xleft"] = xleft;
Session["yleft"] = yleft;
Session["xright"] = xright;
Session["yright"] = yright;
Session["step"] = step;
if (view1.Checked)
Session["view"] = (int)1;
if (view2.Checked)
Session["view"] = (int)2;
Session["sizex"] = sizeX;
Session["sizey"] = sizeY;
Session["eyex"] = double.Parse(eyex.Text);
Session["eyey"] = double.Parse(eyey.Text);
Session["eyez"] = double.Parse(eyez.Text);
}
</script>
<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN"
"http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd">
<html xmlns="http://www.w3.org/1999/xhtml">
<head id="Head1" runat="server">
<title>Dynafunc</title>
</head>
<body style="padding-right: 0px; padding-left: 0px; padding-bottom: 0px;
margin: 0px; padding-top: 0px; text-align: center;">
<form id="form1" runat="server">
<h1>R2 in R dynamically generated function</h1>
<asp:Panel ID="PlotPanel" runat="server" Font-Names="Verdana"
Font-Size="12px" Height="100%"
Style="margin-left: auto; margin-right: auto"
Width="90%" ForeColor="DarkSlateGray"
ScrollBars="Vertical" BorderColor="Gray"
BorderStyle="Solid" BorderWidth="1px">
<table border="0" cellpadding="0"
cellspacing="0" width="100%" id="TABLE1">
<tr>
<td>
<table>
<tr>
<td style="width: 20%; height: 18px;"> </td>
<td style="width: 1px; height: 18px;"></td>
<td style="width: 20%; height: 18px;"> </td>
<td rowspan="1" style="width: 30%; height: 18px;"
valign="top"> </td>
</tr>
<tr>
<td style="width: 20%; height: 1px;">Function</td>
<td style="width: 1px; height: 26px;"></td>
<td style="width: 100px; height: 26px;" align="left">
<asp:TextBox ID="function" runat="server"
Width="300px" Height="16px" Font-Names="Verdana"
Font-Size="12px" ForeColor="DarkGreen">
sin(pow(x,3)+x*y-pow(y,3))</asp:TextBox>
<!-- Ex
pow(x,3)-7*x*y-pow(y,4)
sin(pow(x,3)+x*y-pow(y,3))
-->
</td>
</tr>
<tr>
<td style="width: 20%; height: 1px;">Domain</td>
<td style="width: 1px; height: 1px;"></td>
<td style="width: 20%;" align="left">
<asp:TextBox ID="xmin" runat="server"
Width="32px" Font-Names="Verdana" Font-Size="12px"
ForeColor="DarkGreen">-2</asp:TextBox>
<x<<asp:TextBox ID="xmax" runat="server"
Width="32px" Font-Names="Verdana"
Font-Size="12px" ForeColor="DarkGreen">2
</asp:TextBox>
<asp:TextBox ID="ymin" runat="server"
Width="32px" Font-Names="Verdana" Font-Size="12px"
ForeColor="DarkGreen">-2</asp:TextBox>
<y<<asp:TextBox ID="ymax" runat="server"
Width="32px" Font-Names="Verdana"
Font-Size="12px" ForeColor="DarkGreen">2
</asp:TextBox></td>
</tr>
<tr>
<td style="width: 20%; height: 1px;">Integration</td>
<td style="width: 1px; height: 16px;"></td>
<td style="width: 20%;" align="left">
<asp:TextBox ID="integ" runat="server"
Width="40px" Font-Names="Verdana" Font-Size="12px"
ForeColor="DarkGreen">0.05</asp:TextBox></td>
</tr>
<tr>
<td style="width: 20%; height: 1px;">Image Size</td>
<td style="width: 1px; height: 16px;"></td>
<td style="width: 20%;" align="left">
<asp:TextBox ID="screenSize" runat="server"
Width="32px" Font-Names="Verdana" Font-Size="12px"
ForeColor="DarkGreen">200</asp:TextBox>px</td>
</tr>
<tr>
<td style="width: 20%; height: 1px">View</td>
<td style="width: 1px; height: 16px"></td>
<td style="width: 20%; height: 16px" align="left">
<asp:RadioButton ID="view1" runat="server"
Text="Wireframe" Checked="True" GroupName="view" />
<asp:RadioButton ID="view2" runat="server"
Text="Fill" GroupName="view" />
</td>
</tr>
<tr>
<td style="width: 20%; height: 1px">Rotation (x,y,z)</td>
<td style="width: 1px; height: 16px"></td>
<td style="width: 20%; height: 16px" align="left">
<asp:TextBox ID="eyex" runat="server" Width="40px"
Font-Names="Verdana" Font-Size="12px"
ForeColor="DarkGreen">0.0</asp:TextBox>
<asp:TextBox ID="eyey" runat="server"
Width="40px" Font-Names="Verdana" Font-Size="12px"
ForeColor="DarkGreen">0.0</asp:TextBox>
<asp:TextBox ID="eyez" runat="server"
Width="40px" Font-Names="Verdana" Font-Size="12px"
ForeColor="DarkGreen">0.0</asp:TextBox>
rad</td>
</tr>
<tr>
<td style="width: 20%; height: 1px;"></td>
<td style="width: 1px"></td>
<td style="width: 20%" align="left">
<asp:Button ID="PlotBtn" runat="server"
Font-Names="Arial" Text="Plot" BackColor="White" />
</td>
</tr>
<tr>
<td style="width: 20%; height: 1px"></td>
<td style="width: 1px"></td>
<td align="left" style="width: 20%">
<asp:Label ID="outputTxt" runat="server"
Font-Names="Arial" Font-Size="X-Small"
ForeColor="MidnightBlue"
Height="28px" Text="Label" Width="100%">
</asp:Label></td>
</tr>
</table>
</td>
<td>
<table>
<tr>
<td style="height: 1px; text-align: center;"
colspan="3">
<asp:Image ID="imageFunction" runat="server"
ImageUrl="./images/dynacontent.aspx" /></td>
<td rowspan="8" style="width: 10%;
height: 1px;" valign="top"></td>
</tr>
</table>
</td>
</tr>
</table>
</asp:Panel>
</form>
</body>
</html>
https://www.codeproject.com/Articles/19706/Plotting-User-Defined-R2-in-R-Functions-Using-Csha