Tuesday, October 23, 2012

Adjacency (Sunburst) Diagram in C#

I am currently in the process of developing a special custom outliner program to help me design other big projects I'll get involved with in the future. (Check it out here!) I finished the basic outliner view and all under-the-hood functionality, but now to enhance it (add more tools and features) before I polish it off and share it with the world. The first idea that popped into my head was a data visualizer tool - specifically the node-link diagrams that used the Reingold-Tilford algorithm. I toured the sites and images online so that I wouldn't wast time 're-inventing the wheel' and along the way discovered many more diagrams that I have never seen or even heard of before - take A Tour Through the Visualization Zoo if you want to get clue of what you could do with specific types of data. ( "OO" XD ). Never the less, I actually wasted more time searching than I could have 're-inventing that wheel', but I did find a possible solution for one type of diagram here. (I'll maybe implement that later after parsing from WPF to WinForms)

Long Story Short
I was searching for an algorithm for hierarchy node-link diagram, learned about other was to display the same data, choose the 'Sunburst' diagram as my new primary choice, and never found a hint or clue of algorithmic code for it. This is what it looks like (without words):



To The CODE!

So, first I create an object that would store the drawing data:
public class TreeNodeEx : TreeNode
{
    public float Radius { get; set; }
    public float Scale { get; set;  }
    public float StartAngle { get; set; }
    public float SweepAngle { get; set; }

    public TreeNodeEx(String text)
        : base(text)
    {
        Radius = 0;
        Scale = StartAngle = SweepAngle = 0;
    }
}
Next, the actual sunburst generator!
// This is the entry point of the sunburst algorithm
private void GenerateStructures(TreeNodeEx rTNH)
{
    rTNH.Radius = 1;
    rTNH.SweepAngle = 360;
    tree_depth = Round1(rTNH);
    Round2(rTNH);
}
private int Round1(TreeNodeEx rootx)
{
    // traverse to the bottom while setting depth and breadth
    TreeNodeEx current;

    if(rootx == null) return 0; 

    current = (TreeNodeEx)rootx.Nodes[0];
    bool next_flag = false;
    int depth = 2, max = 0;
    while (current.Parent != null) // have we reached the root yet
    {
        if(current.Nodes.Count == 0 || next_flag)
        {
            if(!next_flag) current.Scale = 1; // count it's self
            ((TreeNodeEx)current.Parent).Scale += current.Scale;
            next_flag = false; // reset
            current.Radius = depth;

            int idx = current.Parent.Nodes.IndexOf(current);
            idx++; // get next sibling in line
            if (current.Parent.Nodes.Count == idx)
            {
                // move to next parant
                next_flag = true;
                current = (TreeNodeEx)current.Parent;
                current.Scale++; // count parent
                depth--;
            }
            else
            {
                current = (TreeNodeEx)current.Parent.Nodes[idx];
            }
        }
        else
        {
            // traverse to the bottom of the tree
            current = (TreeNodeEx)current.Nodes[0];
            depth++;
            max = Math.Max(max, depth);
        }
    }
    return max; // return max depth - used for precise rendering
}
private void Round2(TreeNodeEx rootx)
{
    // traverse to the bottom while setting depth and breadth
    TreeNodeEx current;

    if (rootx == null) return;
    current = (TreeNodeEx)rootx.Nodes[0];
    bool next_flag = false;
    while (current.Parent != null) // have we reached the root yet
    {
        if (current.Nodes.Count == 0 || next_flag)
        {
            if (current.PrevNode != null)
            {
                current.StartAngle = 
                    ((TreeNodeEx)current.PrevNode).StartAngle +
                    ((TreeNodeEx)current.PrevNode).SweepAngle;
                current.SweepAngle =
                    (current.Scale /
                    (((TreeNodeEx)current.Parent).Scale - 1F)) *
                    ((TreeNodeEx)current.Parent).SweepAngle;
            }
            else
            {
                current.StartAngle =
                    ((TreeNodeEx)current.Parent).StartAngle;
                current.SweepAngle =
                    (current.Scale /
                    (((TreeNodeEx)current.Parent).Scale - 1F)) *
                    ((TreeNodeEx)current.Parent).SweepAngle;
            }

            next_flag = false; // reset

            int idx = current.Parent.Nodes.IndexOf(current);
            idx++; // get next sibling in line
            if (current.Parent.Nodes.Count == idx)
            {
                // move to next parant
                next_flag = true;
                current = (TreeNodeEx)current.Parent;
            }
            else
            {
                current = (TreeNodeEx)current.Parent.Nodes[idx];
            }
        }
        else
        {
            if (current.PrevNode != null)
            {
                current.StartAngle =
                    ((TreeNodeEx)current.PrevNode).StartAngle +
                    ((TreeNodeEx)current.PrevNode).SweepAngle;
                current.SweepAngle =
                    (current.Scale /
                    (((TreeNodeEx)current.Parent).Scale - 1F)) *
                    ((TreeNodeEx)current.Parent).SweepAngle;
            }
            else
            {
                current.StartAngle =
                    ((TreeNodeEx)current.Parent).StartAngle;
                current.SweepAngle =
                    (current.Scale /
                    (((TreeNodeEx)current.Parent).Scale-1F)) *
                    ((TreeNodeEx)current.Parent).SweepAngle;
            }

            // traverse to the bottom of the tree
            current = (TreeNodeEx)current.Nodes[0];
        }
    }
}

I didn't include the drawing code portion because this is just an algorithmic post and not an application post.  After all, shapes can be presented, colored, or drawn in many ways with many graphics libraries... and also I feel mine may be a little bit messy or too complex for such a simple task here. However, if you'd like to see how I did it, please leave a comment and I'll try to get back to you!
EDIT: Rewrote the above code without recursion as sometimes trees can grow very deep and there is only a limited amount of stack space available on a machine. Also made a few bug fixes along the way such as the 'overlapping rendering' - a result of a logic error in the variable generation. The above code can still be further improved, but compared to the previous this is an improvement!

Here Are MY Results:
I did it all in WinForms using custom control designs.


HAVE FUN!

Sunday, June 3, 2012

Promoting/Demoting, Moving Up and Down, nodes in the TreeView Control [C#]

I had a difficult time finding the answers to these situations that I needed to implement, and when there is more than one of the same slip in the basket, that same slip will have a higher chance of being found. So, if there are already working answers for these out there, then this post will increase the chances of success in finding these answers to another questioner like me before.

Knowing me I like to get strait to the point and not read about how it works or why and where it would be used first. I like to see the raw [working] code first, then evaluate and implement it. I feel it saves me some time in a sense... So:
To move a node up and down within it's parent node, the following code would be used: (as found here)

public static class Extensions
{
    public static void MoveUp(this TreeNode node)
    {
        TreeNode parent = node.Parent;
        TreeView view = node.TreeView;
        if (parent != null)
        {
            int index = parent.Nodes.IndexOf(node);
            if (index > 0)
            {
                parent.Nodes.RemoveAt(index);
                parent.Nodes.Insert(index - 1, node);
            }
        }
        else if (node.TreeView.Nodes.Contains(node)) //root node
        {
            int index = view.Nodes.IndexOf(node);
            if (index > 0)
            {
                view.Nodes.RemoveAt(index);
                view.Nodes.Insert(index - 1, node);
            }
        }
    }

    public static void MoveDown(this TreeNode node)
    {
        TreeNode parent = node.Parent;
        TreeView view = node.TreeView;
        if (parent != null)
        {
            int index = parent.Nodes.IndexOf(node);
            if (index < parent.Nodes.Count -1)
            {
                parent.Nodes.RemoveAt(index);
                parent.Nodes.Insert(index + 1, node);
            }
        }
        else if (view != null && view.Nodes.Contains(node)) //root node
        {
            int index = view.Nodes.IndexOf(node);
            if (index < view.Nodes.Count - 1)
            {
                view.Nodes.RemoveAt(index);
                view.Nodes.Insert(index + 1, node);
            }
        }
    }
}


...though I don't know if they actually work as I have not yet tested them. But I did write and test some methods of my own that do the same job and I know for a fact that they work (up to the root node only). However, I'm not sure if they are efficient at doing their jobs:... (So if the above doesn't work, you could resort to the one bellow or attempt to write your own (Or keep searching till you find what your looking for))

        private void btnDown_Click(object sender, EventArgs e)
        {
            TreeNode node = treeView.SelectedNode;
            if (treeView.SelectedNode.Parent != null)
            {
                TreeNodeCollection collection = treeView.SelectedNode.Parent.Nodes;
                treeView.SelectedNode = treeView.SelectedNode.Parent;
                int index = collection.IndexOf(node);
                collection.RemoveAt(index);
                collection.Insert(index - 1, node);
                List<TreeNode> nodes = new List<TreeNode>();
                foreach (TreeNode tree in collection) nodes.Add(tree);
                treeView.SelectedNode.Nodes.Clear();
                treeView.SelectedNode.Nodes.AddRange(nodes.ToArray());
                treeView.SelectedNode = node;
            }
        }
        private void btnUp_Click(object sender, EventArgs e)
        {
            TreeNode node = treeView.SelectedNode;
            if (treeView.SelectedNode.Parent != null)
            {
                TreeNodeCollection collection = treeView.SelectedNode.Parent.Nodes;
                treeView.SelectedNode = treeView.SelectedNode.Parent;
                int index = collection.IndexOf(node);
                collection.RemoveAt(index);
                collection.Insert(index + 1, node);
                List<TreeNode> nodes = new List<TreeNode>();
                foreach (TreeNode tree in collection) nodes.Add(tree);
                treeView.SelectedNode.Nodes.Clear();
                treeView.SelectedNode.Nodes.AddRange(nodes.ToArray());
                treeView.SelectedNode = node;
            }
        }


Now, when it comes to promoting or demoting nodes, that is a hard problem to find an answer to via source code online. I have spent a good 3-5hrs just trying to find an efficient answer if even an answer. What I came up with were description-only routines, other's comments of there success, or job-related topics where employees can be 'promoted'. Alright, unless you have some luck finding a better solution to this matter, here is my working code: (up to the root node only)

        private void btnPremote_Click(object sender, EventArgs e)
        {
            TreeNode node = treeView.SelectedNode;
            if (treeView.SelectedNode.Parent != null)
            {
                if (treeView.SelectedNode.Parent.Parent != null)
                {
                    TreeNodeCollection collection = treeView.SelectedNode.Parent.Nodes;
                    TreeNodeCollection collection2 = treeView.SelectedNode.Parent.Parent.Nodes;

                    treeView.SelectedNode = treeView.SelectedNode.Parent;
                    int index = collection.IndexOf(node);
                    collection.RemoveAt(index);
                    collection2.Insert(collection2.Count, node);

                    List<TreeNode> nodes = new List<TreeNode>();
                    foreach (TreeNode tree in collection2) nodes.Add(tree);
                    treeView.SelectedNode = treeView.SelectedNode.Parent;
                    treeView.SelectedNode.Nodes.Clear();
                    treeView.SelectedNode.Nodes.AddRange(nodes.ToArray());
                    treeView.SelectedNode = node;
                }
            }
        }
        private void btnDemote_Click(object sender, EventArgs e)
        {
            TreeNode node = treeView.SelectedNode;
            if (treeView.SelectedNode.Parent != null)
            {
                if (treeView.SelectedNode.Parent != null)
                {
                    if (treeView.SelectedNode.Parent.Nodes.Count > 1 
                        && treeView.SelectedNode.PrevNode != null)
                    {
                        treeView.SelectedNode = treeView.SelectedNode.PrevNode;
                        TreeNodeCollection collection = treeView.SelectedNode.Nodes;
                        collection.Remove(node);
                        collection.Insert(collection.Count, node);

                        List<TreeNode> nodes = new List<TreeNode>();
                        foreach (TreeNode tree in collection) nodes.Add(tree);
                        treeView.SelectedNode.Nodes.Clear();
                        treeView.SelectedNode.Nodes.AddRange(nodes.ToArray());
                        treeView.SelectedNode = node;
                    }
                }
            }
        }



So, there you have it!
Looking at the code presented on the post from StackOverflow, I see implementations that could be made to my code to remove the 'up to root node only' statement; I will not implement it this time as it is not needed in my current project... but maybe another time.

Thursday, May 24, 2012

Adding a Table to a RichTextBox Control in C#

As I have searched, there are not many tutorials, examples, or projects specifically to C# for how to going about adding a user defined table to a RichTextBox control. One of last stands for a programmer would be to program a custom control for them self that would perform what they could not already find. What everybody's goal in development is going the best affordable rout and as 'this' example is so simple, it would be kind of pointless to shell out +$250 on a library that does the same thing.

Note: for developers programming in VB.Net, try this link; it basically does just what the code in C# does - in fact, I used that link to construct this code by example. WPF, Java, ASP.Net, and Silverlight devs, there are plenty of tutorials and examples already... kind of annoying when your trying to search for only pure Windows Forms - C#!

To the code! I have tested this method bellow and it works... there was a side effect though that I couldn't fix so I went the long rout, but still looks the same. Greater success to those who can fix that.

public void InsertTable(RichTextBox Rtb, int Rows, 
        int Cols, int BrdrW, int TableWidth)
{
    String A; int i = 1, j = 1, a = 1, b = 1;
    A = @"{\rtf1\fbidis\ansi\ansicpg1252\deff0\deflang1033" +
        @"{\fonttbl{\f0\froman\fprq2\fcharset0 Times New Roman;}" +      
        @{\f1\fnil\fcharset0 Microsoft Sans Serif;}}" +
        @"\viewkind4\uc1\trowd";
    for (; j <= Rows; j++) // for every row
    {
        for (; i <= Cols; i++) // for every column
        {
            A += @"\clbrdrt\brdrw" + BrdrW + "\brdrs" +
                 @"\clbrdrl\brdrw" + BrdrW + "\brdrs" +
                 @"\clbrdrb\brdrw" + BrdrW + "\brdrs" +
                 @"\clbrdrr\brdrw" + BrdrW + "\brdrs" +
                 @"\cellx" + ((TableWidth / Cols) * 10 * i);
        }
        A += @"\pard\intbl\ltrpar\lang1023\f0\fs24";
        for (; a <= Rows; a++)
        {
            A += @"\intbl\clmrg";
            for (; b <= Cols; b++) A += @"\cell";
            A += @"\row";
        }
    }
    A += "}";

    Rtb.SelectedRtf = A; // send table to RichTextBox 
    Rtb.Rtf = Rtb.Rtf.Replace("\\\'08rdrs", ""); 
    // (\'08rdrs seems to be the side effect here)

    // center table in RichTextBox (and everything else XP )
    Rtb.SelectAll();
    Rtb.SelectionAlignment = HorizontalAlignment.Center;
}

If you would also like to combine this method with this project, you'll be one step closer to creating your own Microsoft Word Program.
I also came across something interesting relating to RichTextBox's, maybe it may be of use to any of you viewing. Check it out!

Friday, May 11, 2012

Programming Imaginary-Complex Numbers [C#]

Now I know there is a library with a class created supposedly for this, and though I haven't fully explored it to know what it is capable of, I wanted to create my own custom Imaginary Number i class with the basic desired features I was after.

If you would rather(or in the mean time) check out that class I was talking about, follow these instructions:
  1. New Project >> Add Reference >> System.Numerics
  2. Add using System.Numerics; to the top of your class file.
  3. The class is called Complex: Complex i = new Complex();
  4. ...new Complex(2, 3); would look something like this in mathematical notation: 2 + 3i
[Important Note]
I recently read this article: to understand how I would go about finding the root of an imaginary number. Now, unless you wish to spend much time reading and figuring out what they are trying to describe and explain(like I did), the simplified answer goes as follows:
√i = cos(90[1/2]) + sin(90[1/2])i
OR
n
√i = cos(90n) + sin(90n)i
If this doesn't explain or satisfy what you are looking for, then I recommend reading on in that article.

The code is pretty explanatory and I have added comments to things that may not so easily be seen...
Alright, enough talk, here is the [C#] code:
namespace Math
{
    public sealed class i
    {
        // set value to default
        private double val = 1; // i^0
        public string Value
        {
            get
            {
                String final;
                if (double.IsPositiveInfinity(val)) 

                     final = "i";
                else if (double.IsNegativeInfinity(val))
                     final = "-i";
                else final = val.ToString();
                return final;
            }
            // only set value through operators
            // private set
            {
                String test = value;
                if (!double.TryParse(test, out val))
                    val = String.Equals(test, "-i") ?
                          double.NegativeInfinity :
                          double.PositiveInfinity;
            }
        }

        // main targeted desire for this class
        public static object Pow(double x)
        {
            object ans = null;
            // root powers
            if (System.Math.Ceiling(x) > x)
               ans = System.Math.Cos(90 * x) + " + " +
                     System.Math.Sin(90 * x) + "i";
            else
               // returns real numbers if power is a multiple
               // of 2
               if (x % 2 == 0) ans = System.Math.Pow(-1, x/2);
               // returns a string representation if 

               // power is odd
               else ans = (System.Math.Pow(-1, (x-1)/2) == 1
                          ? "i" : "-i");
            return ans;
        }

        // Allows for there to be 'i * i * i'
        // instead of just i.Pow(#);
        // This is also the only way to set the 

        // 'Value' property.
        public static i operator *(i complex, i complex2)
        {
            // this section may not be entirely accurate
            i c = new i();
            short tag = 0;

            // i^1
            if (double.IsPositiveInfinity(complex.val)) 

                     tag = 1;
            else if (double.IsNegativeInfinity(complex.val))
                     tag = 3; // i^3
            else if (complex.val == -1) tag = 2; // i^2

            if (double.IsPositiveInfinity(complex2.val))
                     tag += 1; // i^1
            else if (double.IsNegativeInfinity(complex2.val))
                     tag += 3;// i^3
            else if (complex2.val == -1) tag += 2; // i^2

            c.Value = (string)Pow((double)tag);
            return c;
        }
    }
}

Interesting fact: as I developed this I realized I could have just rewritten the equation: 
[(i2n)-1]/-2 as (-1)n

Edit: I also recently gained experience with extensions in C# allowing no need to create an additional separate class - just an extensions class.