Graphical Matrix Representation

This program was made with the idea to graphically represents numerical data stored inside three dimensional matrix.

Inside this program, three dimensional matrix M(x,y,z) used for memorizing data, with it's coordinates, corresponds to orthogonal 3D colored point space, visually presented to the user. Values stored at selected matrix coordinates are values of colors of points at observed space.

At the picture above is shown graph of three math functions at the same XYZ orthogonal coordinate space. Circle in orange, Sphere in red and some interesting 3D function in grey color. Values of X, Y and Z oordinates for all three math functions are calculated for selected different range and color value of point for that coordinates is memorized at the same three dimensional matrix.

Program consists of two classes. Main class that is used for filling three dimensional matrix with numerical values and passing that matrix to second class Draw Matrix, used for graphical presentation to user.Program has built in WASD+Arrows controls so that user can easelly rotate and zoom graph in any direction for better visibility.

Important Notice :

Program was made as Windows Form application at IDE SharpDevelop C# ver. 4.0 and Microsoft .Netframework ver. 2.0. Full solution can be downloaded at links below. Graphical presentation and graphics processor usage inside the program, relies on Microsoft DirectX, so it is necessary to have Microsoft DirectX SDK installed if reprogramming is intended.

Download program

Download open source code

This program is recommended to C# beginners that needs answer to question :

" How to simply create 3D scene, draw 3D points, lines and text and control scene zoom and rotation with keyboard. "

Here is open source program code of two major classes of program:

Main class

/************************************************************************

* Program Licence : *

* *

* Copyright 2015 , Perić Željko *

* (periczeljkosmederevo@yahoo.com) *

* *

* According to it's main purpose , this program is licensed *

* under the therms of 'Free Software' licence agreement. *

* *

* If You do not know what those therms applies to *

* please read explanation at the following link : *

* (http://www.gnu.org/philosophy/free-sw.html.en) *

* *

* Since it is Free Software this program has no warranty of any kind. *

************************************************************************

* Ethical Notice : *

* *

* It is not ethical to change program code signed by it's author *

* and then to redistribute it under the same author name , *

* especially if it is incorrect. *

* *

* It is recommended that if You make improvement in program code , *

* to make remarks of it and then to sign it with Your own name , *

* for further redistribution as new major version of program. *

* *

* Author name and references of old program code version should be *

* kept , for tracking history of program development. *

* *

* For any further information please contact code author at his email. *

************************************************************************/

/************************************

* List Of Revisions *

************************************

* *

* *

* *

************************************/

/*******************************************************************************

* Program name : Graphical Matrix Representation *

* Program ver. : 1.0 *

* Created by : SharpDevelop *

* Code author : Perić Željko *

* Code language : C# *

* Date created : 7.11.2016 - 1.1.2017 *

* Time created : 10:56 *

* *

* *

* Program *

* Description : Program for graphical representation of 3D matrix values. *

* *

* This class stores sets of four number values inside one dimensional table. *

* One set of values are stored inside one row of table *

* as semicolon separated values. *

* *

* 1;2;1;255 *

* 1;2;2;150 *

* 2;2;1;0 *

* 2;2;2;180 *

* -;-;-;- *

* -;-;-;- *

* *

* Those values represent in graphical sense X, Y and Z coordinate values, *

* and value of color of point at given coordinates. *

* *

* After that make call to Draw Matrix class for 3D graphical presentation *

* of stored values. *

* *

* *

* All the best, *

* Author *

* *

*******************************************************************************/

using System;

using System.Drawing;

using System.Windows.Forms;

namespace GMR

{

public partial class MainForm : Form

{

public MainForm()

{

//

// The InitializeComponent() call

// is required for Windows Forms designer support.

//

InitializeComponent();

}

void DrawClick(object sender, EventArgs e)

{

// Declare table for storing x, y and z values of math function

DataGridView Data = new DataGridView();

Data.Columns.Add("Column 1", "Values");

//

// Math functions

//

// Declare variable radians

const float radians = (float) Math.PI/180;

#region - Circle -

double circle_radius = 0.5;

double z_ofset = 1.0;

for(double angle=0;angle<360;angle+=2)

{

double x = circle_radius*Math.Sin(angle*radians);

double y = circle_radius*Math.Cos(angle*radians);

double z = 0 + z_ofset;

Data.Rows.Add(x.ToString() + ";" +

y.ToString() + ";" +

z.ToString() + ";" +

Color.Orange.ToArgb());

}

#endregion

#region - Sphere -

double sphere_radius = 0.3;

z_ofset = 0.7;

for(double azimuth=0;azimuth<360;azimuth+=12)

{

for(double elevation=0;elevation<180;elevation+=6)

{

double x = sphere_radius*

Math.Cos(azimuth*radians)*

Math.Sin(elevation*radians);

double y = sphere_radius*

Math.Sin(azimuth*radians)*

Math.Sin(elevation*radians);

double z = sphere_radius*

Math.Cos(elevation*radians) +

z_ofset;

Data.Rows.Add(x.ToString() + ";" +

y.ToString() + ";" +

z.ToString() + ";" +

Color.Red.ToArgb());

}

}

#endregion

#region - Some interesting 3D functions -

// Math function x range and calculation step

for ( decimal x = -1.0M; x < 1.0M; x += 0.05M )

{

// Math function y range and calculation step

for ( decimal y = -1.0M; y < 1.0M; y += 0.05M )

{

// Math function z value

// decimal z = (decimal)Math.Pow((double)x,9) +

// (decimal)Math.Pow((double)y,7);

// decimal z = (decimal)Math.Sin(5*(Math.Pow((double)x,4)+

// Math.Pow((double)y,4)))/2;

decimal z = (decimal)Math.Cos(

(double)(Math.Abs(x)+Math.Abs(y)))*

(Math.Abs(x)+Math.Abs(y));

Data.Rows.Add(x.ToString() + ";" +

y.ToString() + ";" +

z.ToString() + ";" +

Color.Gray.ToArgb());

}

}

#endregion

//

// Call Draw Matrix Class

//

Draw_Matrix GMR = new Draw_Matrix(Data);

GMR.Show();

}

}

}

Second class :

/************************************************************************

* Program Licence : *

* *

* Copyright 2015 , Perić Željko *

* (periczeljkosmederevo@yahoo.com) *

* *

* According to it's main purpose , this program is licensed *

* under the therms of 'Free Software' licence agreement. *

* *

* If You do not know what those therms applies to *

* please read explanation at the following link : *

* (http://www.gnu.org/philosophy/free-sw.html.en) *

* *

* Since it is Free Software this program has no warranty of any kind. *

************************************************************************

* Ethical Notice : *

* *

* It is not ethical to change program code signed by it's author *

* and then to redistribute it under the same author name , *

* especially if it is incorrect. *

* *

* It is recommended that if You make improvement in program code , *

* to make remarks of it and then to sign it with Your own name , *

* for further redistribution as new major version of program. *

* *

* Author name and references of old program code version should be *

* kept , for tracking history of program development. *

* *

* For any further information please contact code author at his email. *

************************************************************************/

/************************************

* List Of Revisions *

************************************

* *

* *

* *

************************************/

/*******************************************************************************

* Program name : Graphical Matrix Representation *

* Program ver. : 1.0 *

* Created by : SharpDevelop *

* Code author : Perić Željko *

* Code language : C# *

* Date created : 7.11.2016 - 1.1.2017 *

* Time created : 10:56 *

* *

* *

* Program *

* Description : Program for graphical representation of 3D matrix values. *

* *

* This class is developed to receive 3D matrix values that are stored in *

* one dimensional data table, and to show those values as colored points *

* inside 3D orthogonal coordinate system. *

* *

* *

* All the best, *

* Author *

* *

******************************************************************************/

using System;

using System.Drawing;

using System.Windows.Forms;

using Microsoft.DirectX;

using Microsoft.DirectX.Direct3D;

namespace GMR

{

public partial class Draw_Matrix : Form

{

#region - Global Variables -

Microsoft.DirectX.Direct3D.Device device;

PresentParameters presentParams;

Microsoft.DirectX.Direct3D.Mesh mesh_x;

Microsoft.DirectX.Direct3D.Mesh mesh_y;

Microsoft.DirectX.Direct3D.Mesh mesh_z;

int World = 0;

// rotation parameters

const float rad = (float) Math.PI/180;

int step = 1;

int angleX_D = 0;

int angleY_D = 0;

int angleZ_D = 0;

float angleX_R = 0.0f;

float angleY_R = 0.0f;

float angleZ_R = 0.0f;

float camera_look_x = 0;

float camera_look_y = 0;

float camera_look_z = 0;

float camera_x = 0.0f;

float camera_y = 0.0f;

float camera_z = 5.0f;

// zoom

float zoom = 4;

CustomVertex.PositionColored[] points_x;

float x_max = 0.0f;

float x_min = 0.0f;

float y_max = 0.0f;

float y_min = 0.0f;

float z_max = 0.0f;

float z_min = 0.0f;

CustomVertex.PositionColored[] axes;

bool x = false;

bool a = false;

bool s = false;

bool d = false;

bool w = false;

bool left = false;

bool right = false;

bool up = false;

bool down = false;

bool step_p = false;

bool step_m = false;

//

//

//

#endregion

public Draw_Matrix(DataGridView Matrix_Data)

{

//

// The InitializeComponent() call

// is required for Windows Forms designer support.

//

InitializeComponent();

this.SetStyle(ControlStyles.AllPaintingInWmPaint |

ControlStyles.DoubleBuffer, true);

Initialize_Device();

Initialize_Camera();

Initialize_Vertex(Matrix_Data);

Initialize_Text();

}

#region - Initialization -

void Initialize_Device()

{

presentParams = new PresentParameters();

presentParams.Windowed = true;

presentParams.SwapEffect = SwapEffect.Copy;

device = new Device(0, DeviceType.Hardware, Panel,

CreateFlags.HardwareVertexProcessing, presentParams);

device.RenderState.Lighting = false;

device.RenderState.FillMode = FillMode.Solid;

device.RenderState.CullMode = Cull.None;

}

void Initialize_Camera()

{

device.Transform.Projection =

Matrix.PerspectiveFovRH((float)Math.PI/zoom, Panel.Width/Panel.Height, 1f, 150f);

device.Transform.View = Matrix.LookAtRH(new Vector3(camera_x,

camera_y,

camera_z),

new Vector3(camera_look_x,

camera_look_y,

camera_look_z),

new Vector3(0.0f,

1.0f,

0.0f)

);

}

void Initialize_Vertex(DataGridView Data)

{

//

// Convert matrix data to 3d vertex points

//

World = Data.Rows.Count-1;

points_x = new CustomVertex.PositionColored[World];

int p = 0;

int q = 0;

for (p = 0; p < World; p++ )

{

// Matrix

string [] Matrix = Data[q,p].Value.ToString().Split(';');

// Matrix coordinates

float x = float.Parse(Matrix[0]);

float y = float.Parse(Matrix[1]);

float z = float.Parse(Matrix[2]);

// Matrix value

Int32 v = Int32.Parse(Matrix[3]);

if(x_max<x) x_max=x;

if(x_min>x) x_min=x;

if(y_max<y) y_max=y;

if(y_min>y) y_min=y;

if(z_max<z) z_max=z;

if(z_min>z) z_min=z;

points_x[p] = new CustomVertex.PositionColored(x ,

y,

z,

v

);

}

//

// Orthogonal Axes vertex declaration

//

axes = new CustomVertex.PositionColored[6];

// X

axes[0] = new CustomVertex.PositionColored(x_min,0,0, Color.Blue.ToArgb());

axes[1] = new CustomVertex.PositionColored(x_max,0,0, Color.Blue.ToArgb());

// Y

axes[2] = new CustomVertex.PositionColored(0,y_min,0, Color.Green.ToArgb());

axes[3] = new CustomVertex.PositionColored(0,y_max,0, Color.Green.ToArgb());

// Z

axes[4] = new CustomVertex.PositionColored(0,0,z_min, Color.Purple.ToArgb());

axes[5] = new CustomVertex.PositionColored(0,0,z_max, Color.Purple.ToArgb());

//

//

//

//

//

//

}

void Initialize_Text()

{

System.Drawing.Font font = new System.Drawing.Font("Arial", 14.0f, FontStyle.Regular);

mesh_x = Mesh.TextFromFont(device, font, "> x", 0.01f, 0.1f);

mesh_y = Mesh.TextFromFont(device, font, "> y", 0.01f, 0.1f);

mesh_z = Mesh.TextFromFont(device, font, "> z", 0.01f, 0.1f);

}

#endregion

void Redraw()

{

device.Clear(ClearFlags.Target, Color.Black , 1.0f, 0);

device.BeginScene();

device.VertexFormat = CustomVertex.PositionColored.Format;

// Camera fild of view definition

device.Transform.Projection =

Matrix.PerspectiveFovRH((float)Math.PI/zoom,

Panel.Width/Panel.Height,

1f,

150f);

// Camera reposition

device.Transform.View = Matrix.LookAtRH(new Vector3(camera_x,

camera_y,

camera_z),

new Vector3(camera_look_x,

camera_look_y,

camera_look_z),

new Vector3(0.0f,

1.0f,

0.0f)

);

// Scene transformations

device.Transform.World =

Matrix.RotationZ(angleZ_R)*

Matrix.RotationY(angleY_R)*

Matrix.RotationX(angleX_R);

// Draw matrix values

device.DrawUserPrimitives(PrimitiveType.PointList, World, points_x);

// Draw axes

device.DrawUserPrimitives(PrimitiveType.LineList, 3, axes);

device.Transform.World =

Matrix.Translation(10*x_max,-0.3f,0.05f)*

Matrix.Scaling(0.1f,0.1f,0.1f)*

Matrix.RotationZ(angleZ_R)*

Matrix.RotationY(angleY_R)*

Matrix.RotationX(angleX_R);

mesh_x.DrawSubset(0);

device.Transform.World =

Matrix.RotationZ(90*rad)*

Matrix.Translation(0.3f,10*y_max,0.05f)*

Matrix.Scaling(0.1f,0.1f,0.1f)*

Matrix.RotationZ(angleZ_R)*

Matrix.RotationY(angleY_R)*

Matrix.RotationX(angleX_R);

mesh_y.DrawSubset(0);

device.Transform.World =

Matrix.RotationZ(90*rad)*

Matrix.RotationX(90*rad)*

Matrix.Translation(0.3f,-0.05f,10*z_max)*

Matrix.Scaling(0.1f,0.1f,0.1f)*

Matrix.RotationZ(angleZ_R)*

Matrix.RotationY(angleY_R)*

Matrix.RotationX(angleX_R);

mesh_z.DrawSubset(0);

//

//

//

device.EndScene();

device.Present();

}

void Reset()

{

angleX_D = 0;

angleY_D = 0;

angleZ_D = 0;

x=!x;

}

void Recalculate()

{

if(x)

Reset();

#region - speed -

if(step_p)

step++;

if(step_m)

step--;

if(step==0)

step = 1;

#endregion

#region - rotation -

if(left)

angleY_D-=step;

if(right)

angleY_D+=step;

if(up)

angleX_D-=step;

if(down)

angleX_D+=step;

if(a)

angleZ_D-=step;

if(d)

angleZ_D+=step;

//

// World rotation

//

if(angleX_D >= 360)

angleX_D = 0;

if(angleX_D <= -360)

angleX_D = -0;

if(angleY_D >= 360)

angleY_D = 0;

if(angleY_D <= -360)

angleY_D = 0;

if(angleZ_D >= 360)

angleZ_D = 0;

if(angleZ_D <= -360)

angleZ_D = 0;

angleX_R = angleX_D * rad;

angleY_R = angleY_D * rad;

angleZ_R = angleZ_D * rad;

//

//

//

#endregion

#region - move -

if(s)

{

camera_z+=0.1f * step;

if(camera_z>150.0f) camera_z=150f;

}

if(w)

{

camera_z-=0.1f * step;

if(camera_z<-150.0f) camera_z=-150.0f;

}

#endregion

}

#region - Keyboard Event Handler -

protected override void OnKeyDown(KeyEventArgs e)

{

base.OnKeyDown(e);

#region - exit -

if(e.KeyCode == Keys.Escape)

x = !x;

#endregion

#region - speed -

if(e.KeyCode == Keys.Add || e.KeyCode == Keys.Oemplus)

step_p = true;

if(e.KeyCode == Keys.Subtract || e.KeyCode == Keys.OemMinus)

step_m = true;

if(step_p)

step++;

if(step_m)

step--;

if(step==0)

step = 1;

#endregion

#region - rotation -

if(e.KeyCode == Keys.Left)

{

left = true;

}

if(e.KeyCode == Keys.Right)

{

right = true;

}

if(e.KeyCode == Keys.Up)

{

up = true;

}

if(e.KeyCode == Keys.Down)

{

down = true;

}

if(e.KeyCode == Keys.A)

{

a = true;

}

if(e.KeyCode == Keys.D)

{

d = true;

}

//

//

//

#endregion

#region - move -

if(e.KeyValue == (char)Keys.W)

{

w = true;

}

if(e.KeyValue == (char)Keys.S)

{

s = true;

}

#endregion

}

protected override void OnKeyUp(KeyEventArgs e)

{

base.OnKeyUp(e);

#region - speed -

if(e.KeyCode == Keys.Add || e.KeyCode == Keys.Oemplus)

step_p = false;

if(e.KeyCode == Keys.Subtract || e.KeyCode == Keys.OemMinus)

step_m = false;

#endregion

#region - rotation -

if(e.KeyCode == Keys.Left)

{

left = false;

}

if(e.KeyCode == Keys.Right)

{

right = false;

}

if(e.KeyCode == Keys.Up)

{

up = false;

}

if(e.KeyCode == Keys.Down)

{

down = false;

}

if(e.KeyCode == Keys.A)

{

a = false;

}

if(e.KeyCode == Keys.D)

{

d = false;

}

#endregion

#region - zoom -

if(e.KeyValue == (char)Keys.W)

{

w = false;

}

if(e.KeyValue == (char)Keys.S)

{

s = false;

}

#endregion

}

#endregion

#region - Mouse Event Handler -

protected override void OnMouseWheel(MouseEventArgs e)

{

base.OnMouseWheel(e);

#region - zoom -

if(e.Delta<0)

zoom -= 0.1f * step;

else

zoom += 0.1f * step;

if(zoom>10.0f) zoom=10.0f;

else if(zoom<1.0f) zoom=1.0f;

#endregion

}

#endregion

#region - Panel Events -

void PanelPaint(object sender, PaintEventArgs e)

{

Recalculate();

Redraw();

}

void PanelSizeChanged(object sender, EventArgs e)

{

Initialize_Device();

Initialize_Camera();

Initialize_Text();

Recalculate();

Redraw();

if(this.Size==this.MaximumSize)

this.Text= " " +

" " +

"Graphical Matrix Representation";

else

this.Text=" " +

"Graphical Matrix Representation";

Refresh();

}

#endregion

#region - Timer tick event handler -

void Timer1Tick(object sender, EventArgs e)

{

Recalculate();

Redraw();

}

#endregion

}

}

All the best,

Author