Become a MacRumors Supporter for $50/year with no ads, ability to filter front page stories, and private forums.

vlad12

macrumors newbie
Original poster
Nov 16, 2009
2
0
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];
}
 
Can you post a screenshot of what these "kinks" are? Possibly related to drawing on non-pixel boundaries from the transforms.
 
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.
 

Attachments

  • s1.png
    s1.png
    8.5 KB · Views: 201
  • s2.png
    s2.png
    9.5 KB · Views: 205
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.
 
Register on MacRumors! This sidebar will go away, and you'll see fewer ads.