1cb93a386Sopenharmony_ci---
2cb93a386Sopenharmony_cititle: 'Skia Coordinate Spaces'
3cb93a386Sopenharmony_cilinkTitle: 'Coordinates'
4cb93a386Sopenharmony_ci---
5cb93a386Sopenharmony_ci
6cb93a386Sopenharmony_ci## Overview
7cb93a386Sopenharmony_ci
8cb93a386Sopenharmony_ciSkia generally refers to two different coordinate spaces: **device** and
9cb93a386Sopenharmony_ci**local**. Device coordinates are defined by the surface (or other device) that
10cb93a386Sopenharmony_ciyou're rendering to. They range from `(0, 0)` in the upper-left corner of the
11cb93a386Sopenharmony_cisurface, to `(w, h)` in the bottom-right corner - they are effectively measured
12cb93a386Sopenharmony_ciin pixels.
13cb93a386Sopenharmony_ci
14cb93a386Sopenharmony_ci---
15cb93a386Sopenharmony_ci
16cb93a386Sopenharmony_ci## Local Coordinates
17cb93a386Sopenharmony_ci
18cb93a386Sopenharmony_ciThe local coordinate space is how all geometry and shaders are supplied to the
19cb93a386Sopenharmony_ci`SkCanvas`. By default, the local and device coordinate systems are the same.
20cb93a386Sopenharmony_ciThis means that geometry is typically specified in pixel units. Here, we
21cb93a386Sopenharmony_ciposition a rectangle at `(100, 50)`, and specify that it is `50` units wide and
22cb93a386Sopenharmony_citall:
23cb93a386Sopenharmony_ci
24cb93a386Sopenharmony_ci<fiddle-embed name='96f782b723c5240aab440242f4c7cbfb'></fiddle-embed>
25cb93a386Sopenharmony_ci
26cb93a386Sopenharmony_ciLocal coordinates are also used to define and evaluate any `SkShader` on the
27cb93a386Sopenharmony_cipaint. Here, we define a linear gradient shader that goes from green (when
28cb93a386Sopenharmony_ci`x == 0`) to blue (when `x == 50`):
29cb93a386Sopenharmony_ci
30cb93a386Sopenharmony_ci<fiddle-embed name='97cf81a465fdeff01d2298e07a0802a3'></fiddle-embed>
31cb93a386Sopenharmony_ci
32cb93a386Sopenharmony_ci---
33cb93a386Sopenharmony_ci
34cb93a386Sopenharmony_ci## Shaders Do Not Move With Geometry
35cb93a386Sopenharmony_ci
36cb93a386Sopenharmony_ciNow, let's try to draw the gradient-filled square at `(100, 50)`:
37cb93a386Sopenharmony_ci
38cb93a386Sopenharmony_ci<fiddle-embed name='3adc73d23d57084f954f52c6b14c8772'></fiddle-embed>
39cb93a386Sopenharmony_ci
40cb93a386Sopenharmony_ciWhat happened? Remember, the local coordinate space has not changed. The origin
41cb93a386Sopenharmony_ciis still in the upper-left corner of the surface. We have specified that the
42cb93a386Sopenharmony_cigeometry should be positioned at `(100, 50)`, but the `SkShader` is still
43cb93a386Sopenharmony_ciproducing a gradient as `x` goes from `0` to `50`. We have slid the rectangle
44cb93a386Sopenharmony_ciacross the gradient defined by the `SkShader`. Shaders do not move with the
45cb93a386Sopenharmony_cigeometry.
46cb93a386Sopenharmony_ci
47cb93a386Sopenharmony_ci---
48cb93a386Sopenharmony_ci
49cb93a386Sopenharmony_ci## Transforming Local Coordinate Space
50cb93a386Sopenharmony_ci
51cb93a386Sopenharmony_ciTo get the desired effect, we could create a new gradient shader, with the
52cb93a386Sopenharmony_cipositions moved to `100` and `150`. That makes our shaders difficult to reuse.
53cb93a386Sopenharmony_ciInstead, we can use methods on `SkCanvas` to **change the local coordinate
54cb93a386Sopenharmony_cispace**. This causes all local coordinates (geometry and shaders) to be
55cb93a386Sopenharmony_cievaluated in the new space defined by the canvas' transformation matrix:
56cb93a386Sopenharmony_ci
57cb93a386Sopenharmony_ci<fiddle-embed name='ce89b326b2bbe41587eec738706bf155'></fiddle-embed>
58cb93a386Sopenharmony_ci
59cb93a386Sopenharmony_ci---
60cb93a386Sopenharmony_ci
61cb93a386Sopenharmony_ci## <span>Transforming Shader Coordinate Space</span>
62cb93a386Sopenharmony_ci
63cb93a386Sopenharmony_ciFinally, it is possible to transform the coordinate space of the `SkShader`,
64cb93a386Sopenharmony_cirelative to the canvas local coordinate space. To do this, you supply a
65cb93a386Sopenharmony_ci`localMatrix` parameter when creating the `SkShader`. In this situation, the
66cb93a386Sopenharmony_cigeometry is transformed by the `SkCanvas` matrix. The `SkShader` is transformed
67cb93a386Sopenharmony_ciby the `SkCanvas` matrix **and** the `localMatrix` for that shader. The other
68cb93a386Sopenharmony_ciway to think about this: The `localMatrix` defines a transform that maps the
69cb93a386Sopenharmony_cishader's coordinates to the coordinate space of the geometry.
70cb93a386Sopenharmony_ci
71cb93a386Sopenharmony_ciTo help illustrate the difference, here's our gradient-filled box. It's first
72cb93a386Sopenharmony_cibeen translated `50` units over and down. Then, we apply a `45` degree rotation
73cb93a386Sopenharmony_ci(pivoting on the center of the box) to the canvas. This rotates the geometry of
74cb93a386Sopenharmony_cithe box, and the gradient inside it:
75cb93a386Sopenharmony_ci
76cb93a386Sopenharmony_ci<fiddle-embed name='d4b52d94342f1b55900d489c7ba8fd21'></fiddle-embed>
77cb93a386Sopenharmony_ci
78cb93a386Sopenharmony_ciCompare that to the second example. We still translate `50` units over and down.
79cb93a386Sopenharmony_ciHere, though, we apply the `45` degree rotation _only to the shader_, by
80cb93a386Sopenharmony_cispecifying it as a `localMatrix` to the `SkGradientShader::MakeLinear` function.
81cb93a386Sopenharmony_ciNow, the box remains un-rotated, but the gradient rotates inside the box:
82cb93a386Sopenharmony_ci
83cb93a386Sopenharmony_ci<fiddle-embed name='886fa46943b67e0d6aa78486dcfbcc2c'></fiddle-embed>
84