3


Intro: Lets' set of points (x, y) on a plane and func F(x, y) returning double. Points're generated randomly in the user-defined rectangle(which means constraint on variables). Let's set the number of gerated points as N. This set than is triangulated(Delaunay triangulation). Imagine that this triangulation sets the approximation of surface of func F(x, y). Values on edges vary linearly(so it's just a ranges between points(x, y, z = F(x, y)). Vertices are vertices of interpolation. So we have triangles itself as the interpolation planes.
I draw triangulation on a standard PictureBox. The edges are drawn using LinearGradientBrush - color reflect the level of value F(x, y)(brown - max value, aqua - min value, green - middle). It all works until I set N >= M, where M varies from time to time from ~30k to 50k. In these cases I get Out of memory exception. And while I don't see lack of operative memory in task manager I think it refers to video memory, isn't it?
I can draw triangulation with N = 100k without using color gradients(just simple solid one-color edges) so I think the problem is in LinearGradientBrush using or in creation of GDI objects Pen and LinearGradientBrush on every iteration.
Some code:

private void pboxTriangulation_Paint(object sender, PaintEventArgs e)
{
    e.Graphics.SmoothingMode = SmoothingMode.AntiAlias;
    if (null != dt)
        PaintWithGradient(e.Graphics);
}

private void PaintWithGradient(Graphics g)
{
    //here I erased code block
    //where I find min, max and middle values of F(x, y) on a set        

    foreach (Triangle t in dt.triangles)
    {
        System.Drawing.PointF[] ps = new System.Drawing.PointF[3];
        Color[] colors = new Color[3];
        for (int i = 0; i < 3; i++)
        {
            //here for every i-th point I find its display coordinates - ps[i]
            //and color of vertex - colors[i]
        }

        for (int i = 0; i < 3; i++)
        {
            using (LinearGradientBrush b = new LinearGradientBrush(ps[i], ps[(i + 1) % 3], colors[i], colors[(i + 1) % 3]))
            {
                using (Pen pen = new Pen(b))
                {
                    g.DrawLine(pen, ps[i], ps[(i + 1) % 3]);
                }
            }
        }
    }
}


Examples: n = 10k, n = 100k (built as x86), n = 200k (built as x86)
Question: What is the problem and how I can solve it?
Please, don't suggest another drawing tools as a solution(e.g. OpenGL and other strong tools) but if you want just write it as a commentary to question - I'll remember it and maybe it will be useful in future. This question is not about how to draw triangulation with gradient edges in a broad sense but what is the root of exception in my case.

UPD: Program was built in x64. In x86 it draws 200k (not tried higher N) and seems ok. 300k fell after some time with ~1.8gb allocated.

pkuderov
  • 3,501
  • 2
  • 28
  • 46
  • have you tried running this without creating a new pen and linear gradiant on each interation? Obviously the result would be a solid color, but if you don't hit the memory exception then you may have found your issue. Sounds like you thought of this but you didn't specify if you had tried it yet. – Lee Harrison Sep 26 '12 at 21:16
  • CLR OutOfMemory exception never refer to video memory. Are you sure you actually getting OOM in drawing code, not in other parts of the code? (also check CLR memory performance counters to see how much space is allocated, also specify if process is 32 or 64 bit) – Alexei Levenkov Sep 26 '12 at 21:22
  • @LeeHarrison: yep, I tried it and drew 100k points without any problems – pkuderov Sep 26 '12 at 21:35
  • @AlexeiLevenkov: exception rises every time in LinearGradientBrush constructor. I have x64 win7 so am I right that "Any cpu" option in project properties means x64? So I tried build it in x86 and it drew 200k points triangulation! – pkuderov Sep 26 '12 at 21:39
  • 1
    @pkuderov: Seems strange to me, but have you tried using a single `LinearGradientBrush` and simply modifying the `GradientStops` property each time you need to (and any other relevant properties)? Worth a shot?1 – Ed S. Sep 26 '12 at 22:03
  • @Ed S. this sounds like a worthy solution – Lee Harrison Sep 26 '12 at 22:11
  • @EdS.: thanks, sounds really worthy. I'll try it – pkuderov Sep 26 '12 at 22:14
  • That said... I have to believe the problem is actually due to something else and now the OOM exception will rear its head in another location. You're properly disposing of those things, releasing any associated native resources you need to. Are you perhaps invalidating the surface many many times in quick succession? It would be interesting to profile the app and see what it consuming significant portions of memory. – Ed S. Sep 26 '12 at 22:16
  • Also, how many `Triangle`s does `dt.Triangles` contain? – Ed S. Sep 26 '12 at 22:19
  • @EdS.: it contains 2*N+2 triangles. It would be seen if it redraws many times, so no, I don't think it happens(even more I don't move or resize window to prevent it). And the problem is that I never used profiler(yeah, shame on me). – pkuderov Sep 26 '12 at 22:42
  • @pkuderov: That's... a lot of triangles. I wouldn't be surprised if that was the problem here. RedGate has a nice .NET memory profiler with a free trial, I'd give it a spin. I'm very surprised it works at all when targeting x86. I would think that 2^202 objects would be > 2GB. – Ed S. Sep 26 '12 at 22:48
  • @EdS.: yeah, we have N points each are 2*sizeof(double), 2*N triangles each have Point[3] and Triangle[3]. It's huge... – pkuderov Sep 26 '12 at 22:56
  • let us [continue this discussion in chat](http://chat.stackoverflow.com/rooms/17205/discussion-between-pkuderov-and-ed-s) – pkuderov Sep 26 '12 at 22:57

0 Answers0