@AdamP - Challenge: Possible correction to BNR Code Example?


I had a good hard think about this as I wasn’t happy with the 0.5 used in creating the workingOval NSRect… After some tinkering, I came up with the following.

Adam, your comments would be appreciated here as I might be missing something. I only did this as I hate inaccuracies put in code as workarounds :smiley: Also, I think that in the BNR example, on the mouse

The corrections I made are as follows, and it works great:


  • (void)mouseDown:(NSEvent *)theEvent
    //Why do we offset by 0.5? Because lines drawn exactly on the .0 will end up spread over two pixels.
    //workingOval = NSMakeRect(pointInView.x + 0.5, pointInView.y + 0.5, 0, 0);
    //[self setNeedsDisplay:YES];
    start = [self convertPoint:[theEvent locationInWindow] fromView:nil];
    workingOval = NSMakeRect(start.x, start.y, 0, 0);

  • (void)mouseDragged:(NSEvent *)theEvent
    finish = [self convertPoint:[theEvent locationInWindow] fromView:nil];
    if (!(start.x == finish.x) & !(start.y == finish.y)){
    workingOval.size.width = finish.x - start.x;
    workingOval.size.height = finish.y - start.y;
    [self setNeedsDisplay:YES];
    // NSPoint pointInView = [self convertPoint:[theEvent locationInWindow] fromView:nil];
    // workingOval.size.width = pointInView.x - (workingOval.origin.x - 0.5);
    // workingOval.size.height = pointInView.y - (workingOval.origin.y - 0.5);
    // [self setNeedsDisplay:YES];

  • (void)mouseUp:(NSEvent *)theEvent
    if (!(start.x == finish.x) & !(start.y == finish.y)){
    [[self document] addOvalWithRect:workingOval];
    workingOval = NSZeroRect; // zero rect indicates we are not presently drawing
    [self setNeedsDisplay:YES];


Please correct me if I’m wrong but:


  • NSMakeRect(0,0,0,0) works great, if you look at dragged, I prevent anything from being drawn until start x or y != finish x or y


  • If statement is purely there to work around the 0.5 workaround for the 0 sized rect, it also prevents anything from being drawn until the x and y at least have 1 larger (or smaller)
  • I put setNeedsDisplay in the if comment to streamline 'non drawn rects, i.e. not dragged, or dragged up x without changing y etc…

-If statement is there for two reasons:
i) I think that if you sit and click, 89732879623874682734678324 times without moving the mouse, the ovals NSMutableArray will get overpopulated with ‘null rectangles’ as to put it. With the if, a rectangle is only sent back to the ovals NSMutableArray IF it’s a valid rectangle i.e. width>=1 or height>=1
ii)I think if you clicked 8374928374982374982373432 times you would be setNeedsDisplay pointlessly too, so I set that in here.
iii) I think if you clicked 873948728472834 times, the undomanager would have a fit and die! (lol), so now it will only get relevant rects into it’s undo stack.

Adam, can you confirm or criticise my thoughts? It’d be interesting to know if this had helped or hindered!


Just a thought:

NSZeroRect == NSMakeRect(0, 0, 0, 0)

Does that mean I get to name it to NSNullRect? :smiley:

i.e. NSNullRect(x, y) == NSMakeRect(x, y, x-x, y-y)

OR is there already something like that?



It sounds like there may be a misunderstanding about the purpose of the 0.5 (“half pixel”) offset. The purpose of the offset is to ensure that when a line with width 1 is drawn that it will only occupy one pixel. In Cocoa if you draw a line from (0.0,0.0) to (5.0,0.0), you will see that the line appears to actually be 2 pixels wide. To get the line to appear sharply you need to draw it on the half pixel. So we might use coordinates like this: (0.5, 0.5) - (4.5, 0.5), which will result in a nice crisp line.

You may find it helpful to turn on zoom on your display to check the pixel accuracy of your drawing code. On Mountain Lion it’s under System Preferences, Accessibility, Zoom. Check “Use scroll gesture with modifier keys to zoom” and uncheck “Smooth images”.