Search code examples
macosswiftuiappkitcgcontextcoordinate-systems

Does macOS use different coordinate systems for different UI levels or different frameworks?


I'm teaching myself some macOS GUI programming among other things, slowly.

I thought the origin for the coordinate system was in the top-left like in most systems but came across this older OS X documentation:

Local Coordinate Systems Cocoa uses a Cartesian coordinate system as its basic model for specifying coordinates. The origin in this system is located in the lower-left corner of the current drawing space, with positive values extending along the axes up and to the right of the origin point. The root origin for the entire system is located in the lower-left corner of the screen containing the menu bar.

That didn't seem to match my very limited Mac programming experience so I fumbled a bit of SwiftUI code to test it:

Path { path in
    path.move(to: .zero)
    path.addLine(to:CGPoint(x: 0, y: 20))
    path.addLine(to:CGPoint(x: 25, y: 25))
    path.addLine(to:CGPoint(x: 20, y: 0))
    path.addLine(to: .zero)
    path.closeSubpath()
}

That should draw a square with one corner more pointy in the direction both X and Y increase. It produced this shape:
pointy square in macOS SwiftUI
That clearly shows it's going down and to the right, contradicting the old documentation.

So I've tried Googling to find out where in the macOS ecosystem the old coordinate system is used and where the new one is used, but to no avail.

Obviously for backward compatibility they couldn't've just flipped it at some point.

Is it only SwiftUI that's different in macOS, to be consistent with iOS, which I believe also uses the top left for the origin?

Or is it AppKit vs everything else? Or does low-level CoreGraphics do it differently to higher-level stuff operating on NSViews?

Ideally I would just knock out some code to test it but I'm far from fluent and there may be other areas on macOS besides those listed. I'm assuming this is actually common knowledge for Mac programmers even though it's proving to be hard to Google.


Solution

  • As you suspect, AppKit has a lower-left origin, better matching common mathematical conventions. Core Graphics on Mac also has a lower-left origin. Core Text also has a lower-left origin on all platforms.

    UIKit (primarily iOS) has an upper-left convention. This better matches common 2D computer graphics conventions, but not common 3D computer graphics conventions. There is no "obvious" convention. There are just choices.

    This has been a long-time hassle when porting between the platforms. There are various properties and well-known transforms you can apply to flip the systems.

    Path is part of SwiftUI. A key goal of SwiftUI is to be portable across Apple platforms, and it adopts the iOS upper-left convention universally. The documentation you're reading is still accurate, but does not apply to SwiftUI.