Help with GRAPH RESIZING using NSBezier Path

Discussion in 'Mac Programming' started by vlad12, Nov 16, 2009.

  1. vlad12 macrumors newbie

    Joined:
    Nov 16, 2009
    #1
    Hello everyone, I am a little stuck on programming a NSView thats draws a graph live. My graph should draw itself for every point passed in the "liveGraph:forTime:" function. If the graph is reaching the top or bottom of the view, the curve (not the view) is resized (by half) so it will fit. I am trying to find a smooth way of doing so. So far, the resizing works, but it gives me small kinks every time it resizes. I am testing it with y=x+10.

    Here is what I have so far:


    Code:
    - (void) awakeFromNib {
    	path = [[NSBezierPath alloc] init];
    	[path moveToPoint:NSMakePoint(0.0, 0.0)];
    	[path setLineWidth:3.0];
    	maxY = [self bounds].size.height;
    	maxX = [self bounds].size.width;
    }
    
    - (void) drawRect:(NSRect)rect {
    	[super drawRect:rect];
    	if (path) {
    		[[NSColor redColor] set];
    		[path stroke];
    	}
    }
    
    - (void) liveGraph:(float)y forTime:(float)x {
    	if (y > maxY) {
    		maxY = y*2;
    		NSAffineTransform* transform = [NSAffineTransform transform];
    		[transform scaleXBy:1 yBy:0.5];
    		[path transformUsingAffineTransform:transform];		
    	}
    	if (x > maxX) {
    		maxX = x*2;
    		NSAffineTransform* transform = [NSAffineTransform transform];
    		[transform scaleXBy:0.5 yBy:1];
    		[path transformUsingAffineTransform:transform];
    	}
            NSPoint point = NSMakePoint((x/maxX)*[self  bounds].size.width, (y/maxY)*[self bounds].size.height);
    	[path lineToPoint:point];
    
    	[self setNeedsDisplay:YES];
    }
    
     
  2. kainjow Moderator emeritus

    kainjow

    Joined:
    Jun 15, 2000
    #2
    Can you post a screenshot of what these "kinks" are? Possibly related to drawing on non-pixel boundaries from the transforms.
     
  3. vlad12 thread starter macrumors newbie

    Joined:
    Nov 16, 2009
    #3
    I attached 2 screenshots, the bend is a little less visible, as I increased the width of the line... I guess that is some sort of a quick-fix, but I am still looking for a legit solution.

    s1 is before the graph resized itself. You can see that in s2, there is a bend in the line which is y = x... basically.
     

    Attached Files:

    • s1.png
      s1.png
      File size:
      8.5 KB
      Views:
      153
    • s2.png
      s2.png
      File size:
      9.5 KB
      Views:
      139
  4. chown33 macrumors 604

    Joined:
    Aug 9, 2009
    #4
    What type are maxX and maxY?

    Make sure all of your calculations never lose any precision. If I had to guess, I would not rely on the NSView coordinates. I'd log all the values right before and then right after a rescaling in either X or Y, or set breakpoints on the first lines inside your if blocks and then carefully step through looking at the values being appended to the path.

    To me, it doesn't look like a kink, i.e. a change in slope. It looks more like a cumulative precision loss that suddenly gets corrected, a discontinuity. The slope to the left of the glitch looks the same as the slope to the right of the glitch. Clearly, the slope of the left plot differs from the one on the right.

    Another guess is that the NSBezierPath might not be keeping full-precision floats internally, so applying an affine transform subtly affects the overall precision of the accumulated path. That's just a guess, though.

    Finally, you could change your algorithm so the path is never rescaled, only a display-transform is rescaled. Then in drawRect:, set the transform before drawing the path. This approach may also be faster, as a rescale only affects the coefficients of a single affine transform, rather than having to be applied to every stored point in the path.
     

Share This Page