1

I am new to C# and XNA. Have just managed to write a class that generates a triangular grid. But there is one problem. I can get maximum 27 nodes length triangle. At 28 it throws Out of memory exception and at 31 -overFlow exception.

I don't understand how it overflows or out of memory... Tried to calculate all those memory values but they look very tiny.

It is only array of nodes affected by variable. Node class is not very big:

float x; 4 B float y; 4 B float z; 4 B int[] con; int[6] 4*6=24 B byte pass; 1 B Color col; 32 b= 4 B

            Total:  41B

sequence sum of nodes needed to create triangle is n(n+1)/2

out of memory at 28

28*29/2=406 nodes

total memory:

41*406 = 16646 B = 16.26 kB

Overflows at 31: 496 nodes is 19.9 kB

I did read articles about "out of memory exceptions", that structures size is bigger than it seems and that out of memory happens at sizes of 500MB... there is no way my small triangle would reach such huge size.

This is my whole class:

class TriMatrix
    {
        int len;
        int Lenght;
        Node[] node;
        VertexPositionColor[] vertex;

        public class Node
        {
            public float x;
            public float y;
            public float z;
            public int[] con;
            public byte pass;
            public Color col;
            public Node(byte passable)
            {
                pass = passable;
                if (pass > 0)
                { col = Color.Green; }
                else
                { col = Color.DarkRed; }
                x = 0;
                z = 0;
                con = new int[6];
            }
        }

        public TriMatrix(int lenght)
        {
            len = lenght;
            Lenght = 0;
            byte pass;
            Random rnd = new Random();
            for (int i = 0; i <= len; i++)
            {
                Lenght += Lenght + 1;
            }
            node = new Node[Lenght];
            int num = 0;
            for (int i = 0; i < len; i++)
            {
                for (int j = 0; j <= i; j++)
                {

                    if (rnd.Next(0, 5) > 0) { pass = 1; } else { pass = 0; }
                    node[num] = new Node(pass);
                    node[num].x = (float)i - (float)j / 2.0f;
                    node[num].y = 0;
                    node[num].z = (float)j * 0.6f;
                    if (i < len - 1) { node[num].con[0] = num + i; } else { node[num].con[0] = -1; node[num].col = Color.Violet; }
                    if (i < len - 1) { node[num].con[1] = num + i + 1; } else { node[num].con[1] = -1; }
                    if (j < i) { node[num].con[2] = num + 1; } else { node[num].con[2] = -1; node[num].col = Color.Violet; }
                    if (j < i) { node[num].con[3] = num - i; } else { node[num].con[3] = -1; }
                    if (i > 0) { node[num].con[4] = num - i - 1; } else { node[num].con[4] = -1; }
                    if (i > 0) { node[num].con[5] = num - 1; } else { node[num].con[5] = -1; }
                    if (j == 0) { node[num].col = Color.Violet; }
                    num++;
                }
            }
        }

        public void Draw(Effect effect, GraphicsDevice graphics)
        {
            VertexPositionColor[] verts = new VertexPositionColor[3];
            int num = 0;
            for (int i = 0; i < len-1; i++)
            {
                for (int j = 0; j <= i; j++)
                {
                    foreach (EffectPass pass in effect.CurrentTechnique.Passes)
                    {
                        pass.Apply();

                        verts[0] = new VertexPositionColor(new Vector3(node[num].x, node[num].y, node[num].z), node[num].col);
                        verts[1] = new VertexPositionColor(new Vector3(node[num + i + 1].x, node[num + i + 1].y, node[num + i + 1].z), node[num + i + 1].col);
                        verts[2] = new VertexPositionColor(new Vector3(node[num + i + 2].x, node[num + i + 2].y, node[num + i + 2].z), node[num + i + 2].col);
                        graphics.DrawUserPrimitives<VertexPositionColor>(PrimitiveType.TriangleStrip, verts, 0, 1);

                        if ( j < i)
                        {
                            verts[0] = new VertexPositionColor(new Vector3(node[num].x, node[num].y, node[num].z), node[num].col);
                            verts[1] = new VertexPositionColor(new Vector3(node[num + i + 2].x, node[num + i + 2].y, node[num + i + 2].z), node[num + i + 2].col);
                            verts[2] = new VertexPositionColor(new Vector3(node[num + 1].x, node[num + 1].y, node[num + 1].z), node[num + 1].col);
                            graphics.DrawUserPrimitives<VertexPositionColor>(PrimitiveType.TriangleStrip, verts, 0, 1);
                        }
                    }
                    num++;
                }
            }
        }
    }// endclass
Kiaurutis
  • 827
  • 7
  • 10

1 Answers1

7

I assume that your bug lies in this loop (taking the liberty to correct your spelling):

for (int i = 0; i <= len; i++)
{
    Length += Length + 1;
}

Within the loop, you are incrementing the value of Length by itself plus one. This effectively means that you are doubling the value of Length for each iteration, resulting in exponential growth.

During the first few iterations, the values of Length will be: 1, 3, 7, 15, 31, 63, …. We can generalize this sequence such that, at iteration i, the value of Length will be 2i+1−1. At iteration 28, this would be 536,870,911. At iteration 31, this would be 4,294,967,295.

Edit: As you mentioned in the comment below, the correct fix for computing the number of elements in a triangular grid of length len would be:

for (int i = 1; i <= len; i++)
{
    Length += i;
} 

This is equivalent to the summation 1 + 2 + 3 + … + len, which computes what is known as the triangular number. It may be succinctly computed using the formula:

Length = len * (len + 1) / 2;

The reason that this number grows so large is that it is a square relation; for a side of length n, you need an area of approximately half of .

Douglas
  • 53,759
  • 13
  • 140
  • 188
  • 1
    `for(int i = 0; i <= len; i++) { Length += 1; }` would be equivalent to `if(len>0) { Length += len; }` – Trisped Oct 12 '12 at 22:14
  • mmmm... i don't know if it was this problem – Kiaurutis Oct 12 '12 at 22:16
  • I need to add last column +1, not all the length. That must have been the mistake – Kiaurutis Oct 12 '12 at 23:00
  • 1
    I changed Length = Length + 1 to Length = i + 1; and it works perfect ;D Get out of memory exception only at ~6000. It is like 490 MB of memory and is really big size. Problem is solved, but I am curious how do MMORPG developers make their grids? Like L2 or WoW grids, meshes or whatever should be huge. If I combine my grid of smaller ones and calculate only on demand, how to combine them? If I succeed implementing pathfinding for this triangle, will try to optimize, splitting this triangle into smaller ones :] PS thx for help very much, it was fast ;D – Kiaurutis Oct 13 '12 at 07:31
  • I'm afraid I have no expertise in MMORPG development. I assume almost all of them would employ some form of distributed computing, whereby clusters of workstations would work on different parts of the grid. But you would probably be better off starting another question if you would like information on how such distribution may be performed. – Douglas Oct 13 '12 at 12:33