NSBezierPath HiDPI
NSBezierPath HiDPI
- Subject: NSBezierPath HiDPI
- From: Steven Spencer <email@hidden>
- Date: Sun, 11 Sep 2011 01:59:07 +0100
Hello,
What is the correct way to draw a pixel aligned bezier path for HiDPI display modes ?
I've got the following code to draw a rounded rectangle in both standard 1440x900 and HiDPI 720x450 resolutions,
though it seems overly complex.
Is there a simpler solution, perhaps an api method ?
I have to rerun the code for it to take account of a display resolution change, how do I fix this ?
Thanks.
Steven
Lion, Xcode 4.1, Garbage collection on.
--------------------------------------------------
#import <Cocoa/Cocoa.h>
@interface TestView : NSView
{
NSBezierPath *thePath;
}
- (NSAffineTransform *)transformationToDrawBezierPath:(NSBezierPath *)path
alignedInView:(NSView *)view
centredAtX:(CGFloat)x
y:(CGFloat)y
alignPathWidth:(BOOL)alignPathWidth;
@end
--------------------------------------------------
#import "TestView.h"
@implementation TestView
- (id)initWithFrame:(NSRect)frame
{
self = [super initWithFrame:frame];
if (self) {
NSRect bounds = NSMakeRect(100.0, 100.0, 60.0, 60.0);
thePath = [NSBezierPath bezierPathWithRoundedRect:bounds xRadius:6.0 yRadius:6.0];
[thePath setLineWidth:0.0];
}
return self;
}
- (BOOL)isFlipped
{
return YES;
}
- (void)drawRect:(NSRect)dirtyRect
{
NSAffineTransform* transform = [self transformationToDrawBezierPath:thePath
alignedInView:self
centredAtX:123.0
y:84.0
alignPathWidth:YES];
[transform concat];
[[NSColor blueColor] set];
[thePath stroke];
[transform invert];
[transform concat];
}
- (NSAffineTransform *)transformationToDrawBezierPath:(NSBezierPath *)path
alignedInView:(NSView *)view
centredAtX:(CGFloat)x
y:(CGFloat)y
alignPathWidth:(BOOL)alignPathWidth;
{
CGFloat onePixelWidth = [self convertSizeFromBacking:NSMakeSize(1.0, 1.0)].width;
CGFloat halfPixelWidth = onePixelWidth * 0.5;
NSInteger lineWidthPixelCount = MAX(1, (NSInteger) round([path lineWidth] / onePixelWidth));
BOOL isLineWidthEven = lineWidthPixelCount %2 == 0;
NSRect pathBounds = [path bounds];
NSRect alignedBounds = [self centerScanRect:pathBounds];
NSRect insideBounds;
NSPoint pathCentrePoint = NSMakePoint(NSMidX(pathBounds), NSMidY(pathBounds));
//Note : used centerScanRect to align the target point as, convertPointToBacking,
//only modified the y coordinate (followed by convertPointFromBacking).
NSRect target = [self centerScanRect:NSMakeRect(x, y, 1.0, 1.0)];
if (isLineWidthEven) {
//Place an even line width path between pixels
insideBounds = alignedBounds;
} else {
//Inset an odd line width path on the centre of pixels
insideBounds = NSInsetRect(alignedBounds, halfPixelWidth, halfPixelWidth);
}
if (alignPathWidth) {
[path setLineWidth:lineWidthPixelCount * onePixelWidth];
}
CGFloat xScale = insideBounds.size.width / pathBounds.size.width;
CGFloat yScale = insideBounds.size.height / pathBounds.size.height;
CGFloat xScaleInverse = 1.0 / xScale;
CGFloat yScaleInverse = 1.0 / yScale;
NSAffineTransform* transform = [NSAffineTransform transform];
//Scale about the path centre
[transform translateXBy:pathCentrePoint.x
yBy:pathCentrePoint.y];
[transform scaleXBy:xScale
yBy:yScale];
//Position the path
[transform translateXBy:-pathCentrePoint.x + ((target.origin.x - pathCentrePoint.x) * xScaleInverse)
yBy:-pathCentrePoint.y + ((target.origin.y - pathCentrePoint.y) * yScaleInverse)];
return transform;
}
@end
_______________________________________________
Cocoa-dev mailing list (email@hidden)
Please do not post admin requests or moderator comments to the list.
Contact the moderators at cocoa-dev-admins(at)lists.apple.com
Help/Unsubscribe/Update your Subscription:
This email sent to email@hidden