@startuml
title Конвейер координат: Local -> World -> Canvas -> Buffer

skinparam rectangle {
  RoundCorner 10
}

rectangle "Local coords\n(object space)" as L
rectangle "World coords\n(document space)" as W
rectangle "Canvas coords\n(scaled document)" as C
rectangle "Buffer coords\n(visible rect origin)" as B

L --> W : localToWorld()\nrotate + scale + translate
W --> C : world * scale_x/scale_y
C --> B : subtract visible_rect.(x,y)

B --> C : + visible_rect.(x,y)
C --> W : divide by scale_x/scale_y
W --> L : worldToLocal()\ntranslate^-1 + rotate^-1 + scale^-1

note right of B
All raster tests are done
in buffer coords (integer pixels).
Shape analytics often done
in local coords after inverse map.
end note

@enduml
