Plot2D

Make graphs from C#. Many people in my environment often use high level programming languages i.e. Matlab just to be able to make graphs of their data. The possibility to graph our data is important to develop applications, the problem is that the necessary code to create a plot creating software is very complicated.

Using SharpGL we can create our 2D graphs. We are missing several options that may interest the people, but we think that this is a good way to start. The code is flexible enough (no dlls, callbacks, etc) to modify it as you need. The 2D plots have several components.

The basic component of a 2D plot is to be able to show the values of a vector in a graph. The vector can be either integer or double.

Description: C:\Users\root\Desktop\SharpGLDemos\Plot2D\SharpGLWinformsApplication4\bin\Debug\file.bmp

Description: C:\Users\root\Desktop\SharpGLDemos\Plot2D\SharpGLWinformsApplication4\bin\Debug\file3.bmp

We will have a series of data points and a series of plotting points. There are 3 cases, the case where data points> plotting points. The case where plotting points > data points and when data points=plotting points.

For each case we will need interpolation. The code for the interpolation is the following:

if (y.GetLength(0) < qPoints)

            {

                double deltaY = (y.GetLength(0) - 1.0) /(double) qPoints;

               // Console.WriteLine(deltaY);

 

                for (int i = 0; i < plotPointsY.GetLength(0); i++)

                {

                    double tempIndex = i * deltaY;

                    //Console.WriteLine(tempIndex);

                    long intPart = (long)tempIndex;

                    double fractionalPart = tempIndex - intPart;

                    double a=(1.0 - fractionalPart);

                    double b = fractionalPart;

                    double value=a*y[intPart]+b* y[intPart+1];

                    //Console.WriteLine(i + " " + intPart + " " + a + " " + b + " " + (value) + " ");

                   

                    values[i] = value;

                    double plotValue=(value-minValueY)/(maxValueY-minValueY)*2.0-1.0;

                    //Console.WriteLine(i + " " + (value) + " " + plotValue);

                    plotPointsY[i] = plotValue;

                    plotPointsX[i] = (i - 0) / ((double)qPoints - 1) * 2.0 - 1.0;

                    //Console.WriteLine(i + " " + (value) + " " + plotPointsY[i]+ " " + plotPointsX[i]);

                }

 

            }

            else if (y.GetLength(0) > qPoints)

            {

                double deltaY = (y.GetLength(0) - 1.0) / (double)(qPoints - 1);

                //Console.WriteLine(deltaY);

                for (int i = 0; i < plotPointsY.GetLength(0); i++)

                {

                    double tempIndex = i * deltaY;

                    //Console.WriteLine(tempIndex);

                    long intPart = (long)tempIndex;

                    double fractionalPart = tempIndex - intPart;

                    double a = (1.0 - fractionalPart);

                    double b = fractionalPart;

                    double value = 0;

                    if (intPart < plotPointsY.GetLength(0))

                    {

                        value = a * y[intPart] + b * y[intPart + 1];

                    }

                    else

                    {

                        value = y[intPart];

                    }

 

                    //Console.WriteLine(i + " " + intPart + " " + a + " " + b + " " + (value) + " ");

                    values[i] = value;

                    double plotValue = (value - minValueY) / (maxValueY - minValueY) * 2.0 - 1.0;

                    //Console.WriteLine(i + " " + (value) + " " + plotValue);

                    plotPointsY[i] = plotValue;

                    plotPointsX[i] = (i - 0) / ((double)qPoints - 1) * 2.0 - 1.0;

                    //Console.WriteLine(i + " " + (value) + " " + plotPointsY[i] + " " + plotPointsX[i]);

                }

            }

            else

            {

 

              

 

                for (int i = 0; i < plotPointsY.GetLength(0); i++)

                {

 

                    double value = y[i] ;

                    //Console.WriteLine(i + " " + intPart + " " + a + " " + b + " " + (value) + " ");

 

                    values[i] = value;

                    double plotValue = (value - minValueY) / (maxValueY - minValueY) * 2.0 - 1.0;

                    //Console.WriteLine(i + " " + (value) + " " + plotValue);

                    plotPointsY[i] = plotValue;

                    plotPointsX[i] = (i - 0) / ((double)qPoints - 1) * 2.0 - 1.0;

                }

 

 

            }

This code is for the case we give only a vector (a double or integer array) to plot. If we supply 2 vectors (x,y) axis it will make the plot accordingly and is similar to the 3 cases mentioned before. In open GL we will have several key components.

We will draw our graphs as lines and points as in the following manner:

void drawLines(double[] X, double[] Y)

{

    OpenGL gl = openGLControl.OpenGL;

    // disable lighting

    gl.Disable(OpenGL.GL_LIGHTING);

 

    gl.Begin(OpenGL.GL_LINES);

 

    gl.Color(colorPlotLine[0], colorPlotLine[1], colorPlotLine[2]);

 

    for (int i = 0; i < X.GetLength(0)-1; i++)

    {

        gl.Vertex(X[i], Y[i], 0.0);

        gl.Vertex(X[i+1], Y[i+1], 0.0);

    }

    gl.End();

 

   

 

    // enable lighting back

    gl.Enable(OpenGL.GL_LIGHTING);

}

To draw the text will be more difficult. First we will apply a rectangle bigger than the screen in z=0 plane. From there using Unproject we calculated the coordinates to draw over that rectangle, and fixing the movement of the geometry (our lines and text) we are able to put the labels and construct the lines.

void drawSub1()

{

    OpenGL gl = openGLControl.OpenGL;

 

    // clear buffer

    setViewportSub(0, 0, windowWidth, windowHeight, 1, 10);

    gl.ClearColor(bgColor[0], bgColor[1], bgColor[2], bgColor[3]);

    gl.Clear(OpenGL.GL_COLOR_BUFFER_BIT | OpenGL.GL_DEPTH_BUFFER_BIT | OpenGL.GL_STENCIL_BUFFER_BIT);

 

  

 

 

    gl.LoadMatrixf(getTranspose(matrixView));

 

    drawGrid(1, 0.1f);

    drawLines(plotPointsX, plotPointsY);

    drawPoints(plotPointsX, plotPointsY);

    gl.LoadMatrixf(getTranspose(matrixModelView));

 

    gl.DrawText(5, 40, 0.0f,

                0.5f, 0.0f, "Courier", 10.0f,

                CoordText);

    gl.DrawText(5, 20, 0.0f,

              0.5f, 0.0f, "Courier", 10.0f,

              FrameText);

  

 

    double[] winx = new double[1];

    double[] winy = new double[1];

    double[] winz = new double[1];

    double[] modelviewmatrixtemp = new double[16];

    gl.GetDouble(OpenGL.GL_MODELVIEW_MATRIX, modelviewmatrixtemp);

    double[] projtrixtemp = new double[16];

    gl.GetDouble(OpenGL.GL_PROJECTION_MATRIX, projtrixtemp);

    int[] viewporttemp = new int[4];

    gl.GetInteger(OpenGL.GL_VIEWPORT, viewporttemp);

 

  

            gl.Project(-1.0f + (float)21* step + 0.005f, 1.0f+0.025f, 0.0f, modelviewmatrixtemp, projtrixtemp, viewporttemp, winx, winy, winz);

 

            gl.DrawText((int)winx[0], windowHeight / 2 - 5, 0.0f,

                         0.5f, 0.0f, "Courier", 10.0f,

                        labelY);

 

            gl.Project(-1.2f - 0.0f, -1.0f + (float)0 * step - 0.01f, 0.0f, modelviewmatrixtemp, projtrixtemp, viewporttemp, winx, winy, winz);

 

            gl.DrawText(windowWidth / 2 - (labelsAxisX.GetLength(0)  / 2), (int)winy[0]-12, 0.0f,

                        0.5f, 0.0f, "Courier", 10.0f,

                        labelX);

            

            gl.Project(-1.8f + (float)0* step + 0.005f, 1.0f+0.025f, 0.0f, modelviewmatrixtemp, projtrixtemp, viewporttemp, winx, winy, winz);

 

            gl.Disable(OpenGL.GL_LIGHTING);

            gl.Color(colorPlotLine[0], colorPlotLine[1], colorPlotLine[2]);

            gl.Begin(OpenGL.GL_LINES);

            gl.Vertex(-1.8f, 0.05f, 0.0f);

            gl.Vertex(-1.5f, 0.05f, 0.0f);

            gl.End();

            gl.PointSize(3);

            gl.Color(colorPlotPoints[0], colorPlotPoints[1], colorPlotPoints[2]);

            gl.Begin(OpenGL.GL_POINTS);

            gl.Vertex(-1.8f, 0.05f, 0.0f);

            gl.Vertex(-1.5f, 0.05f, 0.0f);

            gl.End();

            gl.DrawText((int)winx[0], windowHeight / 2 - 5, 0.0f,

                         0.5f, 0.0f, "Courier", 10.0f,

                         labelPlot);

            gl.Enable(OpenGL.GL_LIGHTING);

    gl.PushMatrix();

    gl.PopMatrix();

}

 

We think that to understand this better, modify the example and see the results. There are just too many little details to explain. Try to see our past articles and also take a look at the explanation from:

Open GL Transformation from Song Ho Ahn.

http://www.songho.ca/opengl/gl_transform.html

The last point we added an effect similar to getting the information from the mouse pointer in the 3D space. Using a very similar code if one of the plotting points is pressed it will give the information in that node:

Description: C:\Users\root\Desktop\SharpGLDemos\Plot2D\SharpGLWinformsApplication4\bin\Debug\file.bmp

This is given by the following function fixed at plane z=0.

double[] GetOGLPos(int x, int y)

{

    OpenGL gl=openGLControl.OpenGL;

 

    int[] viewport=new int[4];

    double[] modelview = new double[16];

    double[] projection = new double[16];

    double winX, winY, winZ;

 

    byte[] p = new byte[4];   

 

 

    //glGetDoublev( GL_MODELVIEW_MATRIX, modelview );

    gl.GetDouble(OpenGL.GL_MODELVIEW_MATRIX,modelview);

 

    //glGetDoublev( GL_PROJECTION_MATRIX, projection );

    gl.GetDouble(OpenGL.GL_PROJECTION_MATRIX, projection);

   

    //glGetIntegerv( GL_VIEWPORT, viewport );

    gl.GetInteger(OpenGL.GL_VIEWPORT,viewport);

 

    winX = (double)x;

    winY = (double)viewport[3] - (double)y;

    //winY = -(double)y;

    //glReadPixels( x, int(winY), 1, 1, GL_DEPTH_COMPONENT, GL_FLOAT, &winZ );

 

 

    gl.ReadPixels(x, Convert.ToInt16(winY), 1, 1, OpenGL.GL_DEPTH_COMPONENT, OpenGL.GL_FLOAT, p);

    float temp = 0.0f;

 

    temp = System.BitConverter.ToSingle(p, 0);

 

 

   

    winZ = temp;

 

    double posX = 0;

    double posY = 0;

    double posZ = 0;

 

    gl.UnProject(winX, winY, winZ, modelview, projection, viewport, ref posX, ref posY, ref posZ);

 

    //Console.WriteLine(posZ);

    double[] CVector3 = gl.UnProject(winX, winY, winZ);

 

    CVector3 = new double[3] { posX , posY , posZ};

 

    return CVector3;

}

The next step is to introduce this plot2d Graphics in the overall 3d plot scene.