开发者

Mac OS X Cocoa, Flipping Y Coordinate in Global Screen Coordinate Space

How do I flip the y value of an NSPoint to a flipped coordinate space.

I have two sources of points, both in global screen space, but one is flipped:

  1. one from a screen coordinate space with 0,0 = top left.

  2. one from a screen coordinate space with 0,0 = bottom left.

I need to flip the second one (bottom开发者_运维问答 left) to be in the same space as the first one, top left. How can I do that on an NSPoint or CGPoint?


For Mac OSX Cocoa, you can flip the y Coordinate for a view, just override isFlipped to return YES for each view:

- (BOOL)isFlipped {
    return YES;
}


If you have multiple monitors, the overall height of the global coordinate space may be larger than the vertical height on any individual display. I found it necessary to use the following code (given originalPoint) to find that:

let globalHeight = screens.map {$0.frame.origin.y + $0.frame.height}.max()!
let flippedY = globalHeight - originalPoint.y
let convertedPoint = NSPoint(x: originalPoint.x, y: flippedY)


Let's say you have a point in a bottom left coordinate space, called 'originalPoint'. To flip this point to a top left coordinate space, you can use the following code:

let screenFrame = (NSScreen.main()?.frame)!
let flippedY = screenFrame.size.height - originalPoint.y
let convertedPoint = NSPoint(x: originalPoint.x, y: flippedY)

We can also make an extension:

extension NSPoint {

    var flipped: NSPoint {

        let screenFrame = (NSScreen.main()?.frame)!
        let screenY = screenFrame.size.height - self.y
        return NSPoint(x: self.x, y: screenY)  
    }
}

Use:

let flippedPoint = originalPoint.flipped


I think the other answers are not quite correct and will fail in some circumstances.

See this post for what I think is the correct answer.

Here's my implementation for copy-pasting:

#pragma mark - Coordinate conversion

/// The *cocoa*  global "display" coordinate system starts at the bottom left of the zero screen, while the *quartz* coordinate system starts at the top left
/// We sometimes need to convert between them

/// Convenience wrappers

+ (CGPoint)flipPoint:(CGPoint)point {
    return [self cocoaToQuartzScreenSpace:NSMakeRect(point.x, point.y, 0, 0)].origin;
}

+ (CGRect)flipRect:(CGRect)rect {
    return [self cocoaToQuartzScreenSpaceConversionWithOriginFrame:rect];
}

/// Base function

+ (CGRect)cocoaToQuartzScreenSpaceConversionWithOriginFrame:(CGRect)originFrame {
    
    /// Get zero screen height
    NSScreen *zeroScreen = NSScreen.screens[0];
    CGFloat screenHeight = zeroScreen.frame.size.height;
    
    /// Extract values
    CGFloat originY = originFrame.origin.y;
    CGFloat frameHeight = originFrame.size.height;
    
    /// Get new y
    CGFloat destinationY = screenHeight - (originY + frameHeight);
    
    /// Get new frame
    CGRect destinationFrame = originFrame;
    destinationFrame.origin.y = destinationY;
    
    /// return
    return destinationFrame;
}
0

上一篇:

下一篇:

精彩评论

暂无评论...
验证码 换一张
取 消

最新问答

问答排行榜