Matrix Helper Class in C#

I've been working a bit more on my procedural content project. One of the things that I needed to make things a bit easier was the ability to do things like matrix multiplication. Certain things, like determining yaw, pitch, etc. (although I could use quaternions) are much simpler with the use of a matrix. So in order to make things simpler, I created a simple matrix class:

 /*
Copyright (c) 2009 <a href="http://www.gutgames.com">James Craig</a>

Permission is hereby granted, free of charge, to any person obtaining a copy
of this software and associated documentation files (the "Software"), to deal
in the Software without restriction, including without limitation the rights
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
copies of the Software, and to permit persons to whom the Software is
furnished to do so, subject to the following conditions:

The above copyright notice and this permission notice shall be included in
all copies or substantial portions of the Software.

THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
THE SOFTWARE.*/

#region Usings
using System;
using System.Text;
using System.Xml.Serialization;
#endregion

namespace Utilities.Math
{
    [Serializable()]
    public class Matrix
    {
        #region Constructor
        /// <summary>
        /// Constructor
        /// </summary>
        /// <param name="Width">Width of the matrix</param>
        /// <param name="Height">Height of the matrix</param>
        public Matrix(int Width,int Height)
        {
            _Width = Width;
            _Height = Height;
            _Values = new double[Width, Height];
        }
        #endregion

        #region Public Properties
        /// <summary>
        /// Width of the matrix
        /// </summary>
        [XmlElement]
        public int Width
        {
            get { return _Width; }
            set { _Width = value; _Values = new double[Width, Height]; }
        }

        /// <summary>
        /// Height of the matrix
        /// </summary>
        [XmlElement]
        public int Height
        {
            get { return _Height; }
            set { _Height = value; _Values = new double[Width, Height]; }
        }
        /// <summary>
        /// Sets the values of the matrix
        /// </summary>
        /// <param name="X">X position</param>
        /// <param name="Y">Y position</param>
        /// <returns>the value at a point in the matrix</returns>
        public double this[int X, int Y]
        {
            get
            {
                if (X < _Width && X >= 0 && Y < _Height && Y >= 0)
                {
                    return _Values[X, Y];
                }
                throw new Exception("Index out of bounds");
            }

            set
            {
                if (X < _Width && X >= 0 && Y < _Height && Y >= 0)
                {
                    _Values[X, Y] = value;
                }
                throw new Exception("Index out of bounds");
            }
        }

        /// <summary>
        /// Values for the matrix
        /// </summary>
        [XmlElement]
        public double[,] Values
        {
            get { return _Values; }
            set { _Values = value; }
        }
        #endregion

        #region Private Variables
        private int _Width = 1;
        private int _Height = 1;
        private double[,] _Values = null;
        #endregion

        #region Operators
        public static bool operator ==(Matrix M1, Matrix M2)
        {
            if (M1.Width != M2.Width || M1.Height != M2.Height)
                return false;
            for (int x = 0; x <= M1.Width; ++x)
            {
                for (int y = 0; y <= M1.Height; ++y)
                {
                    if (M1[x, y] != M2[x, y])
                        return false;
                }
            }
            return true;
        }

        public static bool operator !=(Matrix M1, Matrix M2)
        {
            return !(M1 == M2);
        }

        public static Matrix operator +(Matrix M1, Matrix M2)
        {
            if (M1.Width != M2.Width || M1.Height != M2.Height)
                throw new ArgumentException("Both matrices must be the same dimensions.");
            Matrix TempMatrix = new Matrix(M1.Width, M1.Height);
            for (int x = 0; x < M1.Width; ++x)
            {
                for (int y = 0; y < M1.Height; ++y)
                {
                    TempMatrix[x, y] = M1[x, y] + M2[x, y];
                }
            }
            return TempMatrix;
        }

        public static Matrix operator -(Matrix M1, Matrix M2)
        {
            if (M1.Width != M2.Width || M1.Height != M2.Height)
                throw new ArgumentException("Both matrices must be the same dimensions.");
            Matrix TempMatrix = new Matrix(M1.Width, M1.Height);
            for (int x = 0; x < M1.Width; ++x)
            {
                for (int y = 0; y < M1.Height; ++y)
                {
                    TempMatrix[x, y] = M1[x, y] - M2[x, y];
                }
            }
            return TempMatrix;
        }

        public static Matrix operator -(Matrix M1)
        {
            Matrix TempMatrix = new Matrix(M1.Width, M1.Height);
            for (int x = 0; x < M1.Width; ++x)
            {
                for (int y = 0; y < M1.Height; ++y)
                {
                    TempMatrix[x, y] = -M1[x, y];
                }
            }
            return TempMatrix;
        }

        public static Matrix operator *(Matrix M1, Matrix M2)
        {
            if (M1.Width != M2.Width || M1.Height != M2.Height)
                throw new ArgumentException("Dimensions for the matrices are incorrect.");
            Matrix TempMatrix = new Matrix(M2.Width, M1.Height);

            for (int x = 0; x < M2.Width; ++x)
            {
                for (int y = 0; y < M1.Height; ++y)
                {
                    TempMatrix[x,y]=0.0;
                    for (int i = 0; i < M1.Width; ++i)
                    {
                        for (int j = 0; j < M2.Height; ++j)
                        {
                            TempMatrix[x, y] += (M1[i, y] * M2[x, j]);
                        }
                    }
                }
            }
            return TempMatrix;
        }

        public static Matrix operator *(Matrix M1,double D)
        {
            Matrix TempMatrix = new Matrix(M1.Width, M1.Height);
            for (int x = 0; x < M1.Width; ++x)
            {
                for (int y = 0; y < M1.Height; ++y)
                {
                    TempMatrix[x, y] = M1[x, y] * D;
                }
            }
            return TempMatrix;
        }

        public static Matrix operator *(double D, Matrix M1)
        {
            Matrix TempMatrix = new Matrix(M1.Width, M1.Height);
            for (int x = 0; x < M1.Width; ++x)
            {
                for (int y = 0; y < M1.Height; ++y)
                {
                    TempMatrix[x, y] = M1[x, y] * D;
                }
            }
            return TempMatrix;
        }

        public static Matrix operator /(Matrix M1, double D)
        {
            return M1 * (1 / D);
        }

        public static Matrix operator /(double D, Matrix M1)
        {
            return M1 * (1 / D);
        }
        #endregion

        #region Public Overridden Functions
        public override bool Equals(object obj)
        {
            if (obj is Matrix)
            {
                return this == (Matrix)obj;
            }
            return false;
        }

        public override int GetHashCode()
        {
            double Hash=0;
            for (int x = 0; x < Width; ++x)
            {
                for (int y = 0; y < Height; ++y)
                {
                    Hash += this[x, y];
                }
            }
            return (int)Hash;
        }

        public override string ToString()
        {
            StringBuilder Builder = new StringBuilder();
            string Seperator = "";
            Builder.Append("{");
            for (int x = 0; x < Width; ++x)
            {
                Builder.Append("{");
                for (int y = 0; y < Height; ++y)
                {
                    Builder.Append(Seperator + this[x, y]);
                    Seperator = ",";
                }
                Builder.Append("}" + System.Environment.NewLine);
            }
            Builder.Append("}");
            return Builder.ToString();
        }
        #endregion
    }
}

The class has functions for multiplication, addition, subtraction, etc. Note that matrix division isn't in there though (well, division by another matrix anyway). So it's rather basic, but hopefully it helps someone out. So give it a try, leave feedback, and happy coding.

kick it on DotNetKicks.com   Shout it
Digg It!DZone It!StumbleUponTechnoratiRedditDel.icio.usNewsVineFurlBlinkListEmail

Posted by: James Craig
Posted on: 3/3/2009 at 11:18 AM
Tags: , ,
Categories: C# | Procedural Content
Post Information: Permalink | Comments (0) | Post RSSRSS comment feed

Procedural Textures and Dilation

It's amazing how I tend to get sucked into projects or think up new projects when I already have too many (including such projects as a web portal, multiplayer game, a proof for an algorithm to find a p-like cycle in polynomial time, etc.). However I find the procedural texture project to be the one that interests me the most.  Anyway, I've been looking back through FxGen again and found an interesting function, Dilate. A rework of the code, in C#, can be found below:

namespace Graphics
{
    class Dilate
    {
        public static float[,] Process(float[,] Data, int Width, int Height,int Iterations)
        {
            float[,] FinalValues = new float[Width, Height];
            for(int i=0;i<Iterations;++i)
            {
                for(int y=0;y<Height;++y)
                {
                    for (int x = 0; x < Width; ++x)
                    {
                        float Threshold = Data[x, y];
                        FinalValues[x, y] = Threshold;
                        for (int u = -1; u < 2; ++u)
                        {
                            for (int v = -1; v < 2; ++v)
                            {
                                int XIndex = (x + Width + u) % Width;
                                XIndex = GlobalFunctions.ClampValue(XIndex, Width, 0);
                                int YIndex = (y + Height + v) % Height;
                                YIndex = GlobalFunctions.ClampValue(YIndex, Height, 0);
                                if (Data[XIndex, YIndex] > Threshold)
                                {
                                    Threshold = Data[XIndex, YIndex];
                                    FinalValues[x, y] = Data[XIndex, YIndex];
                                }
                            }
                        }
                    }
                }
                Data=FinalValues;
                FinalValues = new float[Width, Height];
            }
            return Data;
        }
    }
}

The basic concept is we got through and check each pixel against its neighbors and whichever neighbor is the highest, we set the pixel to that value. In turn it gives a result similar to  the one below:

 



It's probably not the most useful function, but it has its uses. Anyway, check out the code, leave feedback, and happy coding.
kick it on DotNetKicks.com   Shout it
Digg It!DZone It!StumbleUponTechnoratiRedditDel.icio.usNewsVineFurlBlinkListEmail

Posted by: James Craig
Posted on: 5/15/2008 at 8:29 AM
Tags: ,
Categories: Game Programming | Procedural Content
Post Information: Permalink | Comments (0) | Post RSSRSS comment feed

Swirling Vortexes and Procedural Textures

Before I start, this is pretty much taken from FXGen. I really like that library for procedural texture generation. The code can be a bit difficult to parse through some times, but I still like it.  Anyway, I was bored and looking through their code when I came across their Vortex function.  I couldn't quite figure out what I would do with it until I started looking at items in their gallery. And since I was bored, I figured I would implement it in my own library:

 



All that the function is, really, is a rotation within a certain distance from a specified point. The closer you are to the center, the more you rotate. So basically you just find the distance from the current point to the center, determine the inverse percentage between that distance and the maximum distance, multiply that by the desired rotation, and then rotate the point. You could use cosine or something to give a smoother transition but a linear transition works just as well in my book. Anyway, I'm sure you're interested in the code:

 

Vortex.zip (1.11 kb)

 

So download the code, leave feedback, and as always happy coding. 

kick it on DotNetKicks.com   Shout it
Digg It!DZone It!StumbleUponTechnoratiRedditDel.icio.usNewsVineFurlBlinkListEmail

Posted by: James Craig
Posted on: 4/28/2008 at 12:42 PM
Tags: ,
Categories: Game Programming | Procedural Content
Post Information: Permalink | Comments (0) | Post RSSRSS comment feed