Click here to Skip to main content
Click here to Skip to main content

Plotting User-Defined R2 in R Functions Using C#

, 9 Apr 2013
Rate this:
Please Sign up or sign in to vote.
Plotting user defined R2 in R functions using C#

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)

Screenshot - main.png

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.

X,Y,Z Axis and a subdomain in R2
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); // at this point we have x,y and 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;
     }

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);
// note you must have write access to the folder ***

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">
    // Rotation aboout X axis
    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;
    }
    // Rotation aboout Y axis
    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;
    }
    // Rotation aboout Z axis
    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;
    }
    // The z=f(x,y) function with tricky tag to be replaced
    protected double stFunction(double x, double y)
    {
        return (@EXPRESSION);
    }
    // Save file helper
    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);//mp.eval(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++;
    }
    // output the image
    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">
    // Read file helper
    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;
    }
    // Save file helper
    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">

        <!--#include file="~/template.aspx"-->
        <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;">

                        &nbsp;</td>
                    <td style="width: 1px; height: 18px;">
                    </td>
                    <td style="width: 20%; height: 18px;">
                        &nbsp;</td>

                    <td rowspan="1" style="width: 30%; height: 18px;"
                        valign="top">
                        &nbsp;</td>
                </tr>
                <tr>
                    <td style="height: 1px; text-align: center;" colspan="3">
                        &nbsp;
                        <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>&lt;x&lt;
                        <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>&lt;y&lt;
                        <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" />
                        &nbsp; &nbsp; &nbsp;
                        <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>

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

License

This article, along with any associated source code and files, is licensed under The GNU General Public License (GPLv3)

Share

About the Author

andalmeida
Engineer IBM
Brazil Brazil
Senior Analyst
 
Founder of TIHunter Vagas de TI
 
Linkedin Profile
Follow on   LinkedIn

Comments and Discussions

 
GeneralMy vote of 5 Pinmembermanoj kumar choubey26-Feb-12 21:44 
GeneralWoa PinmemberL8N8Hack16-Sep-07 17:30 
GeneralNeat! PinmemberJay Gatsby20-Aug-07 14:56 
GeneralCool [modified] Pinmembersk8er_boy28723-Jul-07 20:43 
AnswerRe: Cool Pinmemberandalmeida24-Jul-07 2:37 

General General    News News    Suggestion Suggestion    Question Question    Bug Bug    Answer Answer    Joke Joke    Rant Rant    Admin Admin   

Use Ctrl+Left/Right to switch messages, Ctrl+Up/Down to switch threads, Ctrl+Shift+Left/Right to switch pages.

| Advertise | Privacy | Mobile
Web02 | 2.8.140827.1 | Last Updated 9 Apr 2013
Article Copyright 2007 by andalmeida
Everything else Copyright © CodeProject, 1999-2014
Terms of Service
Layout: fixed | fluid