views:

215

answers:

2

I currently have an NSView that draws a grid pattern (essentially a guide of horizontal and vertical lines) with the idea being that a user can change the spacing of the grid and the color of the grid.

The purpose of the grid is to act as a guideline for the user when lining up objects. Everything works just fine with one exception. When I resize the NSWindow by dragging the resize handle, if my grid spacing is particularly small (say 10 pixels). the drag resize becomes lethargic in nature.

My drawRect code for the grid is as follows:

-(void)drawRect:(NSRect)dirtyRect {

    NSRect thisViewSize = [self bounds];

    // Set the line color

    [[NSColor colorWithDeviceRed:0 
                           green:(255/255.0) 
                            blue:(255/255.0) 
                           alpha:1] set];

    // Draw the vertical lines first

    NSBezierPath * verticalLinePath = [NSBezierPath bezierPath];

    int gridWidth = thisViewSize.size.width;
    int gridHeight = thisViewSize.size.height;

    int i;

    while (i < gridWidth)
    {
        i = i + [self currentSpacing];

        NSPoint startPoint = {i,0};
        NSPoint endPoint = {i, gridHeight};

        [verticalLinePath setLineWidth:1];
        [verticalLinePath moveToPoint:startPoint];
        [verticalLinePath lineToPoint:endPoint];
        [verticalLinePath stroke];
    }

    // Draw the horizontal lines

    NSBezierPath * horizontalLinePath = [NSBezierPath bezierPath];

    i = 0;

    while (i < gridHeight)
    {
        i = i + [self currentSpacing];

        NSPoint startPoint = {0,i};
        NSPoint endPoint = {gridWidth, i};

        [horizontalLinePath setLineWidth:1];
        [horizontalLinePath moveToPoint:startPoint];
        [horizontalLinePath lineToPoint:endPoint];

        [horizontalLinePath stroke];
    }
}

I suspect this is entirely to do with the way that I am drawing the grid and am open to suggestions on how I might better go about it.

I can see where the inefficiency is coming in, drag-resizing the NSWindow is constantly calling the drawRect in this view as it resizes, and the closer the grid, the more calculations per pixel drag of the parent window.

I was thinking of hiding the view on the resize of the window, but it doesn't feel as dynamic. I want the user experience to be very smooth without any perceived delay or flickering.

Does anyone have any ideas on a better or more efficient method to drawing the grid?

All help, as always, very much appreciated.

+1  A: 
e.James
Since it's stroking the path and not actually generating the path that is inefficient, why not just leave the code the way it is but move the stroke to outside the loop?
Jason Coco
@Jason Coco: That's a good idea. I'd be curious which of the two methods is faster after that change.
e.James
I'll try both and let you know... Thanks! Stay tuned for an update
Hooligancat
@e.James - looks like the path stroke was the culprit. Your alternate solution (using `strokeLineFromPoint:toPoint:`) was marginally, but only marginally, slower than moving the path stroke to outside the loop. For the scale that I am using this works perfectly. Thanks to you and @Jason Coco for your help.
Hooligancat
You're more than welcome. Great question, by the way. I ran some benchmarks just to see how it would come out. See results in my answer. Cheers!
e.James
If you want to increase the drawing speed even further, simply using `NSRectFill()` to draw the lines will be even faster than `+strokeLineFromPoint:toPoint:`.
Rob Keniger
@e.James - thanks for the test results. I think the key here is, as you point out, the hidden repetition. These are the gotchas that one could spend hours trying to figure out. I'm pretty religious about unit testing each individual area before I fully commit it to my application. Imagine having a whole host of drawing going on, doing a resize and then trying to figure out exactly which piece was slowing me down. That would be a nightmare. Thanks again!
Hooligancat
@Rob Keniger - I will have to give your code a run through as well at some point to see if I can get further gains. At this point the performance is easily acceptable in my app, but I'm always interested in making things more efficient at some point - especially as the app grows and more complex operations add to the performance issues.
Hooligancat
A: 

You should run Instruments Cpu Sampler to determine where most of the time is being spent and then optimized based on that info. If it's the stroke, put it outside the loop. If it's drawing the path, try offloading the rendering to the gpu. See if CALayer can help.

lucius