Introduction
This article describes very briefly (and on a basic level) how to plot user interactive 3D R2 in R surfaces using C# ASP.NET. The example enables the user to interact with the drawing in 5 aspects as below:
- function expression z = f(x,y)
- domain
- integration step
- rotation about x, y and z axis
- model (wireframe or fill)

Background
- A point in R3 is a set of 3 float values (x,y,z) which defines a position.
- R2 in R functions are expresions in the form z = f(x,y) where x and y are a subset of the function domain.
- The R2 in R domain is the R2 or better, the xy plane.

The cartesian coordinates
The objective is to get a set of z coordinates applying a generic function z=f(x,y) to a discrete domain, or better a matrix of defined x and y points as the image grid above.
How to Perform This
At first we need to define the domain. Let's choose [-1.7,1.3] for x and [-2.1,2.5] for y what means x will run from -1.7 to 1.3 and y will run from -2.1 to 2.5.
How to Run the Points
As we are working with R coordinates we have infinite points between 2 coordinates, so for this we need a step variable, which means the integration we will use to get the grid points.
Let's define our step as 0.1, and now we can show some code:
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;
}
Now with above definitions we can handle a generation of z coordinates from running the xy discrete subdomain by using the generic function z = f(x,y)
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);
}
x+=step;
}
Now the Tricky Part
We could use a MathExpressionParser
with the expression string, but here I made it more simple with the help of a template with a tag. The process is easy: read the template file, replace the tag, and write the ASPX file which shows the image.
string contents = ReadFile(Server.MapPath("./dynafuncapp.txt"));
contents = contents.Replace("@EXPRESSION", functionStr);
SaveFile(Server.MapPath("./dynacontent.aspx"), contents);
Putting Everything Together
The Template File
<%@ Page Language="c#" Debug="true" Explicit="True" %>
<%@ Import Namespace="System.Data" %>
<%@ Import Namespace="System.Data.OleDb" %>
<%@ Import Namespace="System.Data.OleDb" %>
<%@ Import Namespace="System.Drawing" %>
<%@ Import Namespace="System.Web.Mail" %>
<%@ Import Namespace="System.IO" %>
<%@ Import Namespace="Microsoft.CSharp" %>
<%@ Import Namespace="System.Drawing.Imaging" %>
<%@ Import Namespace="System.CodeDom.Compiler" %>
<%@ Import Namespace="System.Reflection" %>
<%@ Import Namespace="System.Collections" %>
<script language="C#" runat="server">
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;
}
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;
}
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)
{
double xleft = (double) Session["xleft"];
double xright = (double) Session["xright"];
double yleft = (double) Session["yleft"];
double yright = (double) Session["yright"];
double step = (double) Session["step"];
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;
while (x <= xright)
{
y = yleft;
indexY = 0;
while (y <= yright)
{
surface[indexX, indexY] = stFunction(x, y);
indexY++;
y += step;
}
x += step;
indexX++;
}
Session["surface"] = surface;
Bitmap newBitmap = new Bitmap(200, 200, PixelFormat.Format32bppArgb);
Graphics g = Graphics.FromImage(newBitmap);
Color clrBackground = Color.Black;
g.FillRectangle(new SolidBrush(clrBackground),
new Rectangle(0, 0, 200, 200));
Rectangle rect = new Rectangle(0, 0, 200, 200);
double xmin = (double)Session["xleft"];
double ymin = (double)Session["yleft"];
double xmax = (double)Session["xright"];
double ymax = (double)Session["yright"];
double eyex = (double)Session["eyex"];
double eyey = (double)Session["eyey"];
double eyez = (double)Session["eyez"];
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);
double p1x = ((xx1 - xmin) / (xmax - xmin)) * (200.0 - 0.0) + 0.0;
double p1y = ((yy1 - ymin) / (ymax - ymin)) * (200.0 - 0.0) + 0.0;
double p2x = ((xx2 - xmin) / (xmax - xmin)) * (200.0 - 0.0) + 0.0;
double p2y = ((yy2 - ymin) / (ymax - ymin)) * (200.0 - 0.0) + 0.0;
double p3x = ((xx3 - xmin) / (xmax - xmin)) * (200.0 - 0.0) + 0.0;
double p3y = ((yy3 - ymin) / (ymax - ymin)) * (200.0 - 0.0) + 0.0;
double p4x = ((xx4 - xmin) / (xmax - xmin)) * (200.0 - 0.0) + 0.0;
double p4y = ((yy4 - ymin) / (ymax - ymin)) * (200.0 - 0.0) + 0.0;
int ip1x = (int)Math.Ceiling(p1x);
int ip1y = (int)Math.Ceiling(p1y);
int iz1 = (int)Math.Abs((255.0 * zz1));
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 = (int)Session["view"];
if (view == 1)
{
Pen greenPen = new Pen(Color.FromArgb(0, iz1, 0));
g.DrawLine(greenPen, ip1x, ip1y, ip2x, ip2y);
g.DrawLine(greenPen, ip1x, ip1y, ip4x, ip4y);
g.DrawLine(greenPen, ip2x, ip2y, ip4x, ip4y);
g.DrawLine(greenPen, ip2x, ip2y, ip4x, ip4y);
g.DrawLine(greenPen, ip2x, ip2y, ip3x, ip3y);
g.DrawLine(greenPen, ip3x, ip3y, ip4x, ip4y);
greenPen.Dispose();
}
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 greenBrush = new SolidBrush(Color.FromArgb(0,
iz1, 0));
g.FillPolygon(greenBrush, 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(greenBrush, points);
greenBrush.Dispose();
}
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="<a href="http://www.w3.org/1999/xhtml">http://www.w3.org/1999/xhtml</a>">
<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>
The Main File
<%@ Page Language="c#" Debug="true" Explicit="True" %>
<%@ Import Namespace="System.Data" %>
<%@ Import Namespace="System.Data.OleDb" %>
<%@ Import Namespace="System.Data.OleDb" %>
<%@ Import Namespace="System.Drawing" %>
<%@ Import Namespace="System.Web.Mail" %>
<%@ Import Namespace="System.IO" %>
<%@ Import Namespace="Microsoft.CSharp" %>
<%@ Import Namespace="System.Drawing.Imaging" %>
<%@ Import Namespace="System.CodeDom.Compiler" %>
<%@ Import Namespace="System.Reflection" %>
<%@ Import Namespace="System.Collections" %>
<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)
{
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("./dynafuncapp.txt"));
contents = contents.Replace("@EXPRESSION", functionStr);
SaveFile(Server.MapPath("./dynacontent.aspx"), contents);
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["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["eyex"] = double.Parse(eyex.Text);
Session["eyey"] = double.Parse(eyey.Text);
Session["eyez"] = double.Parse(eyez.Text);
Session["sizex"] = sizeX;
Session["sizey"] = sizeY;
}
</script>
<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN"
"<a href="http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd">http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd</a>">
<html xmlns="<a href="http://www.w3.org/1999/xhtml">http://www.w3.org/1999/xhtml</a>">
<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">
<asp:Panel ID="PlotPanel" runat="server" Font-Names="Verdana"
Font-Size="12px" Height="285px"
Width="376px" ForeColor="DarkSlateGray" ScrollBars="Vertical"
BorderColor="Gray"
BorderStyle="Solid" BorderWidth="1px">
<table border="0" cellpadding="0" cellspacing="0" width="100%"
id="TABLE1">
<tr style="background-color: Silver">
<td style="height: 16px" colspan="3">
<strong>R2 in R dynamically generated
function</strong></td>
<td rowspan="1" style="width: 30%; height: 16px"
valign="top">
<strong></strong>
</td>
</tr>
<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="height: 1px; text-align: center;" colspan="3">
<asp:Image ID="imageFunction" runat="server"
ImageUrl="./dynacontent.aspx" /></td>
<td rowspan="8" style="width: 10%; height: 1px;"
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">
pow(x,3)-7*x*y-pow(y,4)</asp:TextBox></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">
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" />
<br />
Rotation (x,y,z)
<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.39</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>
</asp:Panel>
</form>
</body>
</html>

Sample of generated function
sin(pow(x,3)-7*x*y-pow(y,4))