# [cairo] [patch] enable projective transformations

Bill Spitzak spitzak at gmail.com
Tue Aug 17 17:22:28 PDT 2010

```
Maarten Bosmans wrote:

> Yes, this is exactly what I implemented in the suggested patch. But
> the 3x3 matrix in Cairo only stores 8 values and assumes the last one
> always to be zero. Pixman uses a double[][] array, so this is taken
> care of in _cairo_matrix_to_pixman_matrix.

I think you meant the last entry is always 1, not zero. I am trying to
figure out if arbitrary transforms can make this entry become zero, as
that would prevent normalization. But I think that will only happen for
degenerate cases that we do not need to worry about.

> What is this z-axis you're talking about, it sounds very intriguing ;-)
> Remember, there's no 3d here, projective transformation in 2d is just
> messing with the third coordinate from the 2d homogeneous system.

I was imagining a rather simple api called cairo_projection(d) which (in
a 4x4 description) multiplies the matrix by this:

| 1 0 0 0 |
| 0 1 0 0 |
| 0 0 0 0 |
| 0 0 d 1 |

This would be the only operation that produces a matrix where the last
row is not the identity. The result of this is that an object at z==1/d
would be drawn 1/2 the size of an object at z==0, and the scale would be
around 0,0. (Possibly -d should be used so positive z is toward the camera).

The user could get arbitrary projections by first scaling and
translating to indicate where to draw the z=0 plane, then calling this,
then doing further 3D transformations to rotate the z=0 plane in space
and translate the origin.

Since the 'd' is in the third column which is thrown away if this is
reduced to a 3x3 matrix, it means the intermediate result cannot be this
3x3 matrix if this is to work, a 4x4 matrix is needed to keep d so it
can influence further transforms.

So what I am trying to say is that (IMHO) if we want a user-friendly
method of setting the projection matrix then 3D transforms must be
possible and 4x4 matrix used. This also implies that paths should be 3D
translated. It might mean that the z coordinate of paths should be
settable just like the x and y.

The alternative, which is quite possible, is that users are only
interested and can only get a 3D transform of a source surface,
specified by setting the entire 3x3 matrix with an 8 or 9 variable API.
But I kind of feel that if that is what is wanted, why does Cairo do any
transforms at all, it could instead have direct setting of the current
stroke and font matrixes along with the surface matrix, but instead it
provides translate/rotate/scale api.

> Unless I don't understand you correctly, this is already the case.
> Notice how in my example drawing the black transformed stroke is of
> even width. I think the converse of getting a gradually thinner stroke
> is much more difficult to achieve.

Yes I agree your output is correct and showing "line width locking", and
also easier to render as the path can be reduced to 2D before stroking.
However as currently defined Cairo scales line widths by the CTM. If 3D
transforms are allowed I think this means lines that are drawn further
away should be scaled since the transform reduces to something
indistinguishable from a scale. I don't think that is wanted so I think
the fix is to change Cairo, including 2D, to do line width locking. Also
font transform locking for the same reason.
```